13

Quiero tener múltiples observadores en eventos múltiples de un solo objeto (relación 1-a-N).Cuándo utilizar NSNotificationCenter

Un mecanismo para lograr esta tarea lo proporciona el NSNotificationCenter. El mecanismo parece bastante excesivo cuando se usa para mi problema.

¿Cómo lo haría manualmente sin el uso de NSNotificationCenter:

- (void)addDelegate:(id<DelegateProtocol>)delegate; 
- (void)removeDelegate:(id<DelegateProtocol>)delegate; 

para agregar y quitar los observadores de mi objeto.

- (void)someEventFired:(NSObject<NSCopying> *)eventData 
{ 
    for (id delegate in delegates) { 
     NSObject *data = [eventData copy]; 
     [delegate someEventFired:data]; 
    } 
} 

Este mecanismo es directo y simple de implementar sin que los objetos tengan que compartir cadenas adicionales.

  • ¿Hay un patrón oficial para los delegados de 1 a N (como los eventos de C#) en un marco de iOS además del NSNotificationCenter?
  • ¿Cuándo se debe usar el NSNotificationCenter y cuándo no?
  • ¿Cuándo debería usarse una implementación como la que estoy sugiriendo aquí y cuándo no?
+0

Raramente, o nunca, hice uso de NSNotificationCenter pero fui con el mismo método que usted describe. Lo he usado en numerosas aplicaciones iOS (diría más de 50 aplicaciones) durante muchos años, hasta ahora no he visto ningún problema. Un posible inconveniente podría ser que usted necesita estar seguro de eliminar observadores a veces, o pueden no ser liberados cuando se espera porque son retenidos por el guardián de los delegados. – Jonny

+0

Creo que aunque NSNotificationCenter no es el enfoque que conocemos de C#, aún debemos centrarnos en utilizar los patrones de diseño para la plataforma específica para la que trabajamos. Dicho esto, fui con NSNotificationCenter en varias aplicaciones ahora (no tanto como tú), y no creo que el código empeorara a través de él. – Etan

Respuesta

14

Por convención, los delegados probablemente solo deberían usarse para relaciones 1: 1. Si realmente necesita relaciones 1: N para este tipo de funcionalidad, tiene dos opciones:

  1. Como mencionó, NSNotificationCenter.
  2. Key-Value Observing (también conocido como KVO).

KVO es adecuado si solo le preocupa cuándo cambia una propiedad particular de un objeto. De lo contrario, realmente debería considerar usar NSNotificationCenter. Incluso se le puede notificar solo cuando un objeto específico publique esa notificación pasando ese objeto al método addObserver:selector:name:object:.

Apple utiliza NSNotification en escenarios similares (como las notificaciones definidas para UITextField, incluyendo UITextFieldTextDidBeginEditingNotification, UITextFieldTextDidChangeNotification y UITextFieldTextDidEndEditingNotification).

+0

¿Me puede decir si lo estoy usando, verdad? http://stackoverflow.com/questions/42111829/share-object-state-between-view-controllers-in-ios-development/42113389#42113389 –

-3

digo NSNotificationCenter siempre debe ser utilizado, sobre el modelo de delegado, excepto en situaciones en las que se consulta un delegado de la información (por ejemplo -webView:shouldLoadRequest:). Es más estable, más fácil de implementar y da como resultado un código más limpio y luego trata de usar un delegado. La otra alternativa son los bloques, que pueden ser buenos, pero pueden ser un problema cuando se trata de la gestión de la memoria.

Al final, depende de usted, pero creo que NSNotificationCenter es el mejor camino a seguir en casi cualquier situación, aunque solo sea por la funcionalidad de múltiples observadores.

1

NSNotificationCenter no es excesivo para lo que está sugiriendo, es exactamente la solución correcta. Evita que el objeto observado tenga que saber o preocuparse por sus observadores, haciendo que su código se acople más libremente y sea más limpio.

Compartir cadenas para nombres de notificaciones es trivial y pueden definirse en un archivo de constantes compartidas o en el encabezado del objeto observado, si sus observadores necesitan importar este encabezado para realizar su trabajo.

0

Una relación de delegado de 1 a N no tiene sentido. Eche un vistazo a

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row 

por ejemplo. ¿Y si este objeto realmente tuviera n delegados? ¿Cómo debería decidir cuál de las n vistas que recibe de todos sus delegados debería usarse? Los delegados son exactamente este principio de 1 a 1.

El NSNotificationCenter es el enfoque correcto. Sólo tiene que utilizar

addObserver:selector:name:object: 

respectivamente

postNotification: 

Esto definitivamente no es demasiado código. Y es muy fácil para usted ya que el centro maneja todas las llamadas.

2

usando las notificaciones está transmitiendo: 1 remitente simplemente envía una información y quien la haya sintonizado, la recibe. Petty al igual que una estación de radio, no hay un canal de vuelta (permite por el momento olvidarse de los teléfonos)

delegación es algo diferente. Este objeto, que pide a un delegado que haga algo, generalmente necesita un resultado de esa solicitud, por lo tanto, la delegación es una comunicación de 1 a 1, que siempre es iniciada por el objeto, no por el delegado (mientras que el objeto puede tener métodos que puede llamarse para informar al objeto que inicie la comunicación, es decir, [tableView reloadData]).

Entonces, si el remitente necesita recuperar datos, es una delegación. Si al remitente no le importa nada después de la transmisión, vaya con las notificaciones.

Si se encuentra con la situación, necesita delegación, pero varios objetos deberían implementar el protocolo. debe tener 1 delegado, que contenga referencias a los otros objetos y llame a los métodos en nombre de los remitentes, o podría ir con bloques.

+0

Hoy tendría un único objeto que todos los VC comparten y que les informa. – vikingosegundo

1

Su solución propuesta no es ni más simple que utilizar NSNotificationCenter ni es seguro para subprocesos.

Para hacer que su hilo de solución sea seguro, deberá proporcionar un mecanismo para evitar que la matriz de delegados cambie mientras se ejecuta el envío de eventos para el bucle.

Su solución también requiere que mantenga la matriz de delegados en su clase. Con NotificationCenter puede simplemente usar el centro predeterminado y no necesita implementar los métodos para agregar/eliminar en su clase. En su lugar, las instancias pueden registrarse para recibir notificaciones según mejor les parezca (selector/bloque, cola, fuente). Su clase de origen no tiene que preocuparse por esos detalles. Solo necesita registrarse como una fuente de notificaciones de un tipo especificado. Usar bloques para manejar notificaciones es realmente conveniente.

Una alternativa al centro de notificaciones es utilizar Key-Value-Observing si cumple con las necesidades de su caso de uso.

En última instancia, el mecanismo que decida utilizar depende de cómo se aplica a su caso de uso específico.

0

No desea usar NSNotificationCenter para nada que no sea eventos de todo el sistema (por ejemplo, la apariencia del teclado o algún evento similar). El motivo es que no es completamente seguro para tipos, puede hacer que todo dependa de todo y ya no obtiene verificaciones de tiempo de compilación ni resultados de búsqueda de uso.

KVO en mi opinión no debería usarse para observar cambios fuera del objeto que está escuchando ya que tiene lados negativos similares (no comprueba el tiempo de compilación, se bloquea si no elimina oyentes correctamente o los registra dos veces) .

El patrón addDelegate/removeDelegate que usted representa es completamente el camino correcto, en mi opinión, ya que tiene la ventaja de mantener la seguridad de tipos y las comprobaciones del compilador y hace que las dependencias sean explícitas. El único problema es que Apple no proporciona una solución lista para usar para este patrón, ya que necesita un tipo de colección que retiene débilmente sus elementos para evitar retener los ciclos.

Sin embargo, vea el código de mi BMCommons framework que resuelve este problema cuidadosamente usando BMNullableArray y macros. Ver la cabecera BMCore.h para una definición de esas macros:

BM_LISTENER_METHOD_DECLARATION(protocol) 
BM_LISTENER_METHOD_IMPLEMENTATION(protocol) 

La aplicación asegura que la misma escucha no se añadirá dos veces y también que los oyentes se mantienen débilmente, sin causar ningún accidente, incluso si se olvidan de dar de baja a sí mismos en desasignación (aunque prefiero detectar esta condición con una afirmación ya que es un error de programación).

Cuestiones relacionadas