5

¿Qué debo hacer para actualizar un tableView vinculado a un NSArrayController cuando se llama a un método que actualiza la matriz subyacente? Un ejemplo podría aclarar esto.NSArrayController y KVO

Cuando se inicia mi aplicación, crea un SubwayTrain. Cuando SubwayTrain se inicializa, crea un solo SubwayCar. SubwayCar tiene una matriz mutable 'pasajeros'. Cuando se inicializa un vagón de metro, se crea el conjunto de pasajeros y se colocan un par de objetos People (digamos una persona con el nombre "ticket collector" y otro, llamado "vagabundo"). Estos tipos siempre están en el SubwayCar, así que los creo en la inicialización y los agrego al conjunto de pasajeros.

Durante la vida de la aplicación, las personas abordan el automóvil. 'addPassenger' se llama en el SubwayCar, con la persona que se pasa como un argumento.

Tengo un NSArrayController vinculado a subwayTrain.subwayCar.passengers, y en el momento de mi lanzamiento mi colector de boletos y el vagabundo aparecen bien. Pero cuando uso [subwayCar addPassenger:], tableView no se actualiza. He confirmado que el pasajero definitivamente se agrega a la matriz, pero nada se actualiza en la GUI.

¿Qué es probable que esté haciendo mal? Mi instinto es que está relacionado con KVO: el controlador de array no sabe actualizarse cuando se llama a addPassenger (aunque addPassenger llama [pasajeros addObject:]. ¿Qué podría estar equivocando aquí? - Puedo publicar código si ayuda.

Gracias a cualquiera que esté dispuesto a ayudar.

ACTUALIZACIÓN

Así, resulta que puedo conseguir que esto funcione, cambiando por el método de addPassenger

[seatedPlayers addObject:person]; 

a

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers]; 

[newSeatedPlayers addObject:sp]; 

[seatedPlayers release]; 

[self setSeatedPlayers:newSeatedPlayers]; 

Supongo que esto se debe a que estoy usando [self setSeatedPlayers]. ¿Esta es la manera correcta de hacerlo? Parece terriblemente engorroso copiar la matriz, liberar la anterior y actualizar la copia (en lugar de solo agregarla a la matriz existente).

+0

¿Cómo se relaciona la vista de tabla con el controlador? ¿Tiene cada columna de la tabla vinculada a una propiedad de 'subwayTrain.subwayCar.passengers' (por ejemplo, columna Nombre vinculado a' subwayTrain.subwayCar.passengers.name')? – outis

+0

sí exactamente. Y los nombres de los pasajeros aparecen cuando se lanza. –

Respuesta

1

Así, resulta que puedo conseguir que esto funcione, cambiando por el método de addPassenger

[seatedPlayers addObject:person]; 

a

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers]; 
[newSeatedPlayers addObject:sp]; 
[seatedPlayers release]; 
[self setSeatedPlayers:newSeatedPlayers]; 

supongo que esto se debe a que estoy usando [self setSeatedPlayers]. ¿Esta es la manera correcta de hacerlo?

En primer lugar, es setSeatedPlayers:, con los dos puntos. Eso es de vital importancia en Objective-C.

Usar sus propios ajustadores es la forma correcta de hacerlo, pero está utilizando la forma correcta incorrecta. Funciona, pero todavía está escribiendo más código del que necesita.

Lo que debe hacer es implementar accesos de conjunto, como addSeatedPlayersObject:. Entonces, envíate ese mensaje. Esto hace que añadir las personas un corto de una sola línea:

[self addSeatedPlayersObject:person]; 

Y mientras usted sigue the KVC-compliant accessor formats, recibirá notificaciones MVA de forma gratuita, tal como lo hace con setSeatedPlayers:.

Las ventajas de este sobre setSeatedPlayers: son:

  • Su código de mutar el conjunto será más corto.
  • Porque es más corto, será más limpio.
  • El uso de accesadores de conjunto de muñones específicos ofrece la posibilidad de notificaciones de KVO de mutación de conjuntos específicos, en lugar de notificaciones generales de todo el conjunto de cambios.

También prefiero esta solución en vez de mutableSetValueForKey:, tanto por brevedad como porque es muy fácil escribir mal la clave en esa cadena literal. (Uli Kusterer has a macro to cause a warning when that happens, que es útil cuando usted realmente necesita hablar con KVC o el propio MVA.)

7

No sé si se considera un error, pero addObject: (y removeObject: atIndex :) no genera notificaciones KVO, por lo que la vista del controlador/tabla de la matriz no se está actualizando. Para ser compatible con MVA, utilice mutableArrayValueForKey:

Ejemplo:

[[self mutableArrayValueForKey:@"seatedPlayers"] addObject:person]; 

Usted también desea implementar InsertObject: inSeatedPlayersAtIndex: desde el default métodos MVA está muy lento (que crean un conjunto completamente nuevo, añadir el objeto de esa matriz, y establecer la matriz original a la nueva matriz - muy ineficiente)

- (void)insertObject:(id)object inSeatedPlayerAtIndex:(int)index 
{ 
    [seatedPlayers insertObject:object atIndex:index]; 
} 

Tenga en cuenta que este método también se llamará cuando el controlador de array añade objetos, por lo que también es un buen gancho para piensa como registrar una operación de deshacer , etc.

1

No he probado esto, así que no puedo decir que funciona, pero no habría que obtener notificaciones MVA llamando

InsertObject: atArrangedObjectIndex:

en el ArrayController?

+0

Sí, el uso del NSArrayController para mutar la matriz lo hace para que el NSArrayController sepa sobre la mutación y (y las cosas relacionadas con ella) deben actualizarse en consecuencia. – ipmcc

0
  1. Uso willChangeValueForKey: y didChangeValueForKey: envuelto alrededor de un cambio de un miembro cuando el cambio no parece causar una notificación de MVA. Esto es útil cuando está cambiando directamente una variable de instancia.

  2. Utilice willChangeValueForKey:withSetMutation:usingObjects: y didChangeValueForKey:withSetMutation:usingObjects: alrededor de un cambio de contenido de una colección cuando el cambio no parece causar una notificación de KVO.

  3. Utilice [seatedPlayers setByAddingObject:sp] para hacer las cosas más cortas y para evitar la asignación innecesaria de conjuntos mutables.

En general, lo haría bien esto:

[self willChangeValueForKey:@"seatedPlayers" 
      withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:sp]; 
[seatedPlayers addObject:sp]; 
[self didChangeValueForKey:@"seatedPlayers" 
      withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:sp]; 

o esto:

[self setSeatedPlayers:[seatedPlayers setByAddingObject:sp]]; 

con esta última alternativa que causa una invocación automática de las funciones enumeradas en el punto 1. En primer lugar alternativo debería tener un mejor rendimiento.

1

La clave de la magia de Key Value Observing está en Key Value Compliance. Inicialmente estaba utilizando un nombre de método addObject: que solo está asociado con el "patrón de acceso desordenado" y su propiedad era una propiedad indexada (NSMutableArray). Cuando cambió su propiedad a una propiedad no ordenada (NSMutableSet) funcionó. Considere que NSArray o NSMutableArray son propiedades indexadas y NSSet o NSMutableSet como propiedades desordenadas. Realmente debes leer esta sección cuidadosamente para saber qué se necesita para que la magia suceda ... Key-Value-Compliance. Existen algunos métodos 'obligatorios' para las diferentes categorías, incluso si no planea usarlos.

Cuestiones relacionadas