Cocoa:在模型中使用观察者

Posted

技术标签:

【中文标题】Cocoa:在模型中使用观察者【英文标题】:Cocoa: using observer in a model 【发布时间】:2012-12-24 09:59:22 【问题描述】:

我正在尝试了解如何实现真正的 Cocoa MVC,如图 4-7 所示。

这是一个链接

http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaDesignPatterns/CocoaDesignPatterns.html#//apple_ref/doc/uid/TP40002974-CH6-SW1

图 4-7 显示模型使用模式观察器来通知控制器(被动 MVC)。 我以这种方式在我的模型中实现观察者

@interface IADataManager : NSObject

//MARK: Parsed Feed With IANewsDataObj
@property (nonatomic,retain) NSMutableArray *feedArray;

//MARK: Model use Singelton Pattern
+ (IADataManager *) sharedInstance;

//MARK: Observation methods
- (void) addListener:(id<IADataManagerListener>) listener;
- (void) removeListener:(id<IADataManagerListener>) listener;

//MARK: Business Logic
- (void) loadFeedFromNetwork;
- (void) loadFeedFromDataBase;
- (void) loadImageForTarget:(id<IADataManagerListener>) target
                AtIndexPath:(NSIndexPath *) indPath;
- (void) saveFeedToDataBase;

@end

@protocol IADataManagerListener <NSObject>

- (void) IADataManager            :(IADataManager *) dataMng
         didRefreshWithError      :(NSError *) error;

- (void) IADataManager            :(IADataManager *) dataMng
         didLoadImageForIndexPath :(NSIndexPath *) indexPath;

- (void) IADataManager            :(IADataManager *) dataMng
         didLoadWithError         :(NSError *) error;


@end


  - (void) addListener:(id<IADataManagerListener>) listener

    if([self.listeners indexOfObject:listener] == NSNotFound && listener)
        [self.listeners addObject:listener];

- (void) removeListener:(id<IADataManagerListener>) listener

    if([self.listeners indexOfObject:listener] !=NSNotFound && listener)
        [self.listeners removeObject:listener];


//Notification example
- (void) handleLoadedNews:(NSArray *) loadedNews

    [self.feedArray   addObjectsFromArray:loadedNews];
    [self.listeners enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) 
        objc_msgSend(obj, @selector(IADataManager:didRefreshWithError:),self,nil);
    ];



我想知道,是否有更好的方法在模型中实现观察者?例如使用 KVO 或 NSNotificationCenter。但问题是,在 KVO 和 NSNotificationCenter 的帮助下,我不能使用超过 1 个参数的选择器。例如,

 - (void) DataManager:(DataManager *) dm withObj1:(Obj1*) obj1  Obj1:(Obj2*) obj2  Obj3:(Obj3*) obj3

非常感谢!

【问题讨论】:

【参考方案1】:

But problem is that with the help of KVO and NSNotificationCenter i can not use selectors with more than 1 argument.

你可以!!!

将所有选择器存储在一个数组或字典中,然后传递该单个对象。

【讨论】:

【参考方案2】:

KVO 通常是更好的选择。示例:

在 IDataManager 中:

- (void) handleLoadedNews:(NSArray *) loadedNews

    [self willChangeValueForKey:@"feedsArray"]; //Also, see - (void)willChange:(NSKeyValueChange)changeKind valuesAtIndexes:(NSIndexSet *)indexes forKey:(NSString *)key
    [self.feedsArray addObjectsFromArray:arr];
    [self didChangeValueForKey:@"feedsArray"]; //Also, see - (void)didChange:(NSKeyValueChange)changeKind valuesAtIndexes:(NSIndexSet *)indexes forKey:(NSString *)key

并且,在 ViewController 中:

- (void) viewDidLoad 
    ....
    [[IADataManager sharedInstance] addObserver:self forKeyPath:@"feedsArray" options:0 context:NULL];


- (void) viewWillUnload 
    ....
    [[IADataManager sharedInstance] removeObserver:self forKeyPath:@"feedsArray"];


- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
    //if keyPath is "feedsArray", refresh my views

【讨论】:

【参考方案3】:

我认为使用委托或块将是理想的。要在视图控制器中获取回调,您可以使用委托方法或块。我认为这将是 MVC 设计模式的理想方法。

【讨论】:

以上是关于Cocoa:在模型中使用观察者的主要内容,如果未能解决你的问题,请参考以下文章

Cocoa Touch:图形界面构建UIKit

是否可以在 Cocoa Touch 中观察对象的只读属性?

[深入浅出Cocoa]详解键值观察(KVO)及其实现机理

Swift / Cocoa:如何观察文件夹的变化?

iOS KVO 键值观察

IOS设计模式-观察者模式