4

這是一個非常廣泛/模糊的問題,但這裏有。提前道歉。需要關於Cocoa MVC/KVO模式的一些提示

的應用程序(桌面應用程序),我建設需要不同種類的輸入來生成QR碼(我只是建立它來學習一些的OBJ-C /可可)。用戶可以在允許輸入純文本(單個文本字段),VCard/MeCard數據(多個文本字段)和其他內容的不同視圖之間切換。無論輸入什麼,結果都是QR碼。

爲了保持載,我想使用視圖作爲視圖控制器,所以他們處理他們自己的投入,可以簡單地「送」通用「數據編碼」包含所有數據對象一箇中央編碼器。即純文本視圖將使用其文本字段的文本創建數據對象,而VCard/MeCard視圖將使用其所有字段來創建結構化VCard/MeCard數據。

我可以在代碼中手動綁定在一起所有這些東西,但我真的想學習如何綁定/國際志願者組織可以幫助我。唉,在閱讀Apple的開發人員文檔以及我可以找到的更簡單的教程/示例之後,我仍然不確定如何將其應用到我的應用程序。

例如:用戶在VCard視圖中編輯文本字段。 VCard視圖控制器被通知每個更新並「重新計算」數據對象。中央編碼器控制器然後被通知更新的數據對象,並對數據進行編碼。

所有這一切的點,是輸入意見可以完全獨立創建的,並且可以包含各種輸入字段。然後他們處理自己的輸入,並「返回」編碼器可以使用的通用數據對象。在內部,視圖觀察它們的輸入以更新數據對象,而在外部,編碼器僅需要觀察數據對象。

麻煩是我不知道如何使這一切發生,並保持它的解耦。在輸入視圖及其字段之間是否應該有一個對象控制器?視圖和編碼器之間是否應該有另一個?我需要在哪裏?如果有人有好的教程鏈接,請分享。

同樣,我可以推出自己的通知和膠水代碼的系統,但我認爲這一點是爲了避免。

回答

2

絕對是一個含糊不清的問題,而是一個初學者到另一個,我覺得你的痛苦:)

我下載並解壓通過他們的每一個例子和grep頻繁。我發現這是讓我超越駝峯的最有價值的東西。我絕對不建議放棄這些例子。我砍了this script來下載並解壓縮它們。

在良好的國際志願者組織模式方面,我發現技術described here是非常有用的。然而,它在Objective-C 2.0中是doesn't work as-is。另外他並沒有詳細說明它是如何使用的。下面是我有工作:

KVODispatcher.h這樣的:

#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 

而且KVODispatcher.m是這樣:

#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 

然後你就可以註冊到觀察的事件,像這樣:

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

而且在執行上述相同的對象,你可以上午像這樣:

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

    // do your thing 
} 

你可以有任意數量的這些「doSomething」類型的方法,只要你喜歡。只要他們使用相同的參數(keyPath:object:change :),它就會生效。與每個對象一個調度一個希望接收關於在任意數量的對象的改變的任何數量的通知。

我喜歡它:

  1. 只能每班一個observeValueForKeyPath,但你可能要觀察幾件事情。自然的下一個想法是:「嘿,也許我可以通過選擇」
  2. 哦,但它是不可能的,除非像NSNotification包裝對象被用來通過performSelector傳遞多個參數。誰想要清理包裝對象。
  3. 覆蓋observeValueForKeyPath當超類還使用KVO使任何通用方法都很難 - 您必須知道將哪些通知傳遞給超類以及要保留哪些通知。
  4. 誰願意重新實施中的每個對象相同的基於通用選擇反正observeValueForKeyPath?最好只做一次並重用它。

一個很好的變化可能是添加一個字段像id additionalContext到KVODispatcher並有additionalContext對象在objc_msgSend調用中傳遞。可以用它來隱藏,需要時觀測到的數據的變化得到更新UI目標是有用的。甚至可能是一個NSArray。

+0

非常漂亮 - 謝謝!當然,我可以把我的牙齒鑽進那裏。 – Flambino 2011-01-03 16:26:15