Question

Apple propose un petit didacticiel pour créer une interface maître-détail simple. Interface Builder en générera même automatiquement un à partir d'une entité Core Data. Cependant, j'essaie de faire quelque chose de plus compliqué que le simple exemple et je lutte depuis un moment pour que cela fonctionne.

J'ai une application basée sur les documents Core Data. Le modèle comprend une entité abstraite Page et plusieurs sous-entités concrètes de Page. Toutes les pages ont des attributs en commun (comme "nom") et ceux-ci sont définis dans Page. De toute évidence, les sous-entités possèdent les attributs qui leur sont propres.

Je souhaite que l'interface permette à l'utilisateur de voir tous les types de pages de la liste principale (un NSTableView). Lorsqu'ils sélectionnent une page, les champs de détail affichés dépendent du type de page.

Voici ce que j'ai en ce moment:

J'ai un fichier principal, où la liste principale est affichée, ainsi que tous les champs communs à une page. Il y a une référence pour chaque type de page avec ses champs spécifiques. Il y a le NSArrayController principal dans le fichier nib principal, qui remplit le NSTableView. Il existe également un NSArrayController dans chaque nib spécifique à la page afin que je puisse lier les champs de détail aux attributs de la sélection actuelle. Tous mes NSArrayControllers sont configurés de manière identique et je les ai tous liés au même managedObjectContext et au même selectionIndexes.

J'utilise la méthode de permutation de vues d'Aaron Hillegass qu'il décrit dans son livre Cocoa. Je me suis donc inscrit à NSTableViewSelectionDidChangeNotifications et, quand j'en reçois un, il appelle une méthode switchView:

switchView examine l'objet actuellement sélectionné, vérifie de quel type de page il s'agit et bascule dans le fichier nib approprié selon la méthode de Hillegass.

Tout fonctionne bien si je n'ajoute que les pages d'un type, mais dès que j'ajoute une page d'un second type, j'obtiens cette erreur:

  

Erreur lors de la définition de la valeur du chemin de clé selectionIndexes de l'objet (à partir de l'entité d'objet lié: page, nombre d'objets sélectionnés: 1): [valueForUndefinedKeyKey:]: l'entité NoColPage n'est pas une clé conforme à la codification pour le côté clé.

La dernière partie de l'erreur a du sens: elle est coincée en essayant d'afficher le mauvais nib, alors elle essaie de se lier à des champs qui n'existent pas pour cet objet.

J'ai ajouté un champ selectionIndexes à MyDocument afin que tous mes NSArrayControllers puissent être liés au même endroit. Je souffre depuis des jours et je n'arrive pas à comprendre. Des idées?

Si cela vous aide, voici un exemple de projet que vous pouvez télécharger . J'ai extrait uniquement les éléments pertinents à ce problème de mon projet dans une nouvelle application factice, que je me suis servie pour tester et jouer.

PS: L’outil d’Interface Builder permettant de générer une interface maître-détail à partir d’une entité Core Data ne fonctionne pas comme prévu pour les entités abstraites. Il crée uniquement des champs pour les attributs dans la superentité.

Modifier: Je pense que Joshua est intéressé par quelque chose, mais malheureusement, cela ne fonctionne pas - je continue à rencontrer le même problème. Au début, j’avais des difficultés, car je ne comprenais pas que -unbind: attend une chaîne constante, pas un chemin de clé.

J'ai essayé plusieurs variantes: où je garde une trace du contrôleur de la matrice actuellement affiché; où je garde la trace du type de page actuellement affiché et que je dissocie / noue les liens lorsque je tente d’afficher un type de page différent ...

Voici la section de code pertinente.

-(void) displayViewController: (ManagingVC *) vc withClass:(NSString*) className {

//Try to end editing
NSWindow *w = [box window];
BOOL ended = [w makeFirstResponder:w];
if (!ended) {
    NSBeep();
    return;
}

//The Managing View Controller's NSArrayController
NSArrayController* vcAc = [vc arrCont];

//if the page we're trying to switch to is NOT the same type as the current page we're displaying
//if it is, do nothing.
if (![currPageDisplayed isEqual:className]) {

    //unbind the old view controller
    ManagingVC *oldvc = [viewControllers objectForKey:className];
    NSArrayController* oldsac = [oldvc arrCont];
    [oldsac unbind:@"selectionIndexes"];

    //bind the new view controller
    [vcAc bind:@"selectionIndexes" toObject:self withKeyPath:@"selectionIndexes" options:nil];
    currPageDisplayed = className;

    NSView *v = [vc view];

    //display the new view in an NSBox in the main nib
    [box setContentView:v];
}

}

Était-ce utile?

La solution 2

Après avoir passé beaucoup trop de temps à essayer de synchroniser le contrôleur RAID de chaque carte NIB, j'ai abandonné cette approche. La seule chose qui a fonctionné pour moi est de contrôler par programme les éléments de l'interface graphique affichés dans la nib principale et leurs liaisons. Cela signifie éliminer les autres plumes. Ce n'est pas vraiment une solution durable si vous travaillez avec plus que quelques champs de texte, mais cela fonctionne pour moi maintenant.

Je suis toujours le conseil de Joshua de dissocier la liaison avant de changer de vue, mais pour le moment, je ne lie que les champs de texte à arrayController.selection.witelyKey

Autres conseils

Le problème est que vous laissez les contrôleurs de tableau de vos nibs liés à la sélection du document, ce qui les amène à tenter (lorsque la sélection change) de représenter l'élément sélectionné.

Essayez ceci:

  1. Supprimez les liaisons dans les nibs.
  2. Avant d'ajouter une nouvelle vue, connectez ses liaisons au code.
  3. Avant de supprimer l'ancienne vue, déconnectez ses liaisons dans le code.

Cela devrait garder tout heureux.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top