4

Ceci est une question très large/vague, mais voilà. Excuses d'avance. L'application (application de bureau) que je suis en train de construire prend différents types d'entrées pour générer un code QR (je ne fais que le construire pour apprendre Obj-C/Cocoa). L'utilisateur peut basculer entre différentes vues qui permettent d'entrer du texte brut (champ de texte unique), des données VCard/MeCard (plusieurs champs de texte) et d'autres choses. Peu importe l'entrée, le résultat est un code QR. Pour garder les choses contenues, je voudrais utiliser les vues en tant que contrôleurs de vue, afin qu'elles gèrent leurs propres entrées, et peuvent simplement "envoyer" un objet générique "données à encoder" contenant toutes les données à un encodeur central. C'est à dire. la vue en texte brut ferait un objet de données avec le texte de son champ de texte, tandis que la vue VCard/MeCard utiliserait tous ses champs pour créer des données VCard/MeCard structurées.Besoin de quelques conseils concernant les modèles Cocoa MVC/KVO

Je peux lier tous ces éléments manuellement dans le code, mais j'aimerais vraiment savoir comment les bindings/KVO pourraient m'aider. Hélas, après avoir lu les docs de développeur d'Apple, et les tutoriels/exemples plus simples que j'ai pu trouver, je ne sais toujours pas comment l'appliquer à mon application.

Par exemple: L'utilisateur édite les champs de texte dans la vue VCard. Le contrôleur de vue VCard est averti de chaque mise à jour et "recalcule" l'objet de données. Le contrôleur de codeur central est ensuite informé de l'objet de données mis à jour et code les données. Le but de tout ceci, est que les vues d'entrée peuvent être créées complètement indépendamment, et peuvent contenir toutes sortes de champs d'entrée. Ils gèrent ensuite leurs propres entrées et "retournent" un objet de données générique, que le codeur peut utiliser. En interne, les vues observent leurs entrées pour mettre à jour l'objet de données et, en externe, l'encodeur n'a besoin que d'observer l'objet de données. Le problème est que je n'ai aucune idée de comment tout cela se produirait et le garder découplé. Devrait-il y avoir un contrôleur d'objet entre la vue d'entrée et ses champs? Devrait-il en avoir un autre entre la vue et l'encodeur? De quoi ai-je besoin où? Si quelqu'un a un lien vers un bon tutoriel, merci de le partager.

Encore une fois, je peux rouler mon propre système de notifications et de code de colle, mais je pense que le but est d'éviter cela.

Répondre

2

Certainement une question vague, mais un débutant à l'autre, je me sens votre douleur :)

J'ai téléchargé et déballés chaque seul exemple et grep à travers eux fréquemment. J'ai trouvé que c'était la chose la plus précieuse pour me faire passer la balle. Je recommande vraiment de ne pas abandonner les exemples. J'ai piraté this script pour les télécharger et les déballer tous.

En termes de bons modèles KVO, j'ai trouvé la technique described here très utile. Il doesn't work as-is en Objective-C 2.0 cependant. En outre, il ne donne pas beaucoup de détails sur la façon dont il est réellement utilisé.Voici ce que j'ai travail:

Le KVODispatcher.h comme ceci:

#import <Foundation/Foundation.h> 

@interface KVODispatcher : NSObject { 

    id owner; 
} 

@property (nonatomic, retain) id owner; 

- (id) initWithOwner:(id)owner; 

- (void)startObserving:(id)object keyPath:(NSString*)keyPath 
       options:(NSKeyValueObservingOptions)options 
       selector:(SEL)sel; 

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context; 
@end 

Et le KVODispatcher.m est comme si:

#import "KVODispatcher.h" 
#import <objc/runtime.h> 

@implementation KVODispatcher 

@synthesize owner; 

- (id)initWithOwner:(id)theOwner 
{ 
    self = [super init]; 
    if (self != nil) { 
     self.owner = theOwner; 
    } 
    return self; 
} 

- (void)startObserving:(id)object 
       keyPath:(NSString*)keyPath 
       options:(NSKeyValueObservingOptions)options 
       selector:(SEL)sel 
{ 
    // here is the actual KVO registration 
    [object addObserver:self forKeyPath:keyPath options:options context:sel]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    // The event is delegated back to the owner 
    // It is assumed the method identified by the selector takes 
    // three parameters 'keyPath:object:change:' 
    objc_msgSend(owner, (SEL)context, keyPath, object, change); 

    // As noted, a variation of this technique could be 
    // to expand the data passed in to 'initWithOwner' and 
    // have that data passed to the selected method here. 
} 
@end 

Ensuite, vous pouvez vous inscrire pour observer des événements comme ceci:

KVODispatcher* dispatcher = [[KVODispatcher alloc] initWithOwner:self]; 
[dispatcher startObserving:theObject 
        keyPath:@"thePath" 
        options:NSKeyValueChangeNewKey 
        selector:@selector(doSomething:object:change:)]; 

Et dans le même objet que exécuté ci-dessus, vous pouvez avoir am ethod comme ça:

- (void) doSomething:(NSString *)keyPath 
      object:(id)object 
      change:(NSDictionary *)change { 

    // do your thing 
} 

Vous pouvez avoir autant de ces méthodes de type «faire quelque chose» que vous le souhaitez. Aussi longtemps qu'ils utilisent les mêmes paramètres (keyPath: object: change :) cela fonctionnera. Avec un répartiteur par objet qui souhaite recevoir un nombre quelconque de notifications concernant les modifications d'un nombre quelconque d'objets.

Ce que j'aime ce:

  1. Vous ne pouvez avoir qu'un seul observeValueForKeyPath par classe, mais vous pouvez observer plusieurs choses. Oh, mais il n'est pas possible de passer plusieurs arguments via performSelector sauf si des objets wrapper comme NSNotification sont utilisés. Qui veut nettoyer les objets wrapper. Si une super-classe utilise également KVO, il est difficile de contourner les approches génériques - vous devez savoir quelles notifications transmettre à la super classe et lesquelles conserver. Qui veut réimplémenter le même observeValueForKeyPath basé sur sélecteur générique dans chaque objet de toute façon? Mieux vaut juste le faire une fois et le réutiliser.

Une variante belle peut-être ajouter un autre domaine comme id additionalContext à KVODispatcher et ont cet objet additionalContext passé dans l'appel objc_msgSend. Il peut être utile de l'utiliser pour stocker un objet d'interface utilisateur qui doit être mis à jour lorsque les données observées changent. Même peut-être un NSArray.

+0

Très bien - merci! Il y a certainement quelque chose que je peux faire mes dents là-dedans. – Flambino

Questions connexes