如何使用单个解析器通过多个ViewControllers在解析端通知ViewController

时间:2010-05-16 15:56:33

标签: iphone objective-c nsxmlparser

我已经创建了一个RSS解析器和3个TableViews,它可以很好地解析RSS文件,但是我不知道如何在解析结束时通知TableViewController,这样它就可以更新视图。 TableViewController启动解析器和解析feed。

parser = [[RSSParser alloc] initWithURL:@"http://randomfeed.com"];

我可以访问单个Feed项目,例如

[parser feedItems];

在parser.m中,我实现了NSXMLParser的委托方法:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
- (void)parserDidEndDocument:(NSXMLParser *)parser 

那么如何让parserDidEndDocument通知我的控制器,以便我可以将数据添加到tableview。

来自obj-c初学者的欢呼。

3 个答案:

答案 0 :(得分:1)

如果您需要多个对象通知单个事件,则委托方法通常会开始变得混乱。

NSNotification是一个很好的选择。

    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(reachabilityChanged:) name: kInternetAvailableNotification object: nil];

上面为当前对象添加了一个“监听器”,用于侦听任何触发它的人 kInternetAvailableNotification通知。当事件发生时,调用方法“reachabilityChanged”。

在你的dealloc方法中,记得取消注册通知:

- (void)dealloc {

    [[NSNotificationCenter defaultCenter] 
     removeObserver:self 
     name:kInternetAvailableNotification 
     object:nil];   

    [super dealloc];
}

您的代码中的任何地方现在都可以通知侦听器某个事件:

[[NSNotificationCenter defaultCenter]
 postNotificationName:kInternetAvailableNotification
 object:nil];

NSNotifications可以发送带有对象的字典 听众可以使用。

因此,每个需要知道新数据何时可用的控制器都可以注册 kInternetAvailableNotification通知(它只是一个由NSString定义的名称) 并被告知。

这是一个简短的贯通:)

答案 1 :(得分:1)

好的,委托模式在Cocoa框架中被广泛使用。

解析数据的文件必须具有协议,任何想要回调的人都会形成这个协议 类必须实现协议中的方法:

    //XMLParser.h

    //import statements here ..

    @protocol XMLParserDelegate

    - (void) parserDidFinish:(NSArray*) theParsedData; //have as many methods as you please, didFail, doingProgress etc.

    @end

    @interface XMLParser : NSObject {

    id <XMLParserDelegate> delegate; //we don't know what type of object this will be, only that it will adhere to the XMLParserDelegate protocol.

    }

@property(assign) id delegate;
    //methods

    @end

在XMLParser的实现中:

@implementation XMLParser

@synthesize delegate;

- (void)parserDidEndDocument:(NSXMLParser *)parser {

[self.delegate parserDidFinish:dataYouCollectedArray]; //this is where it happens.

}

因此,在您的控制器界面文件中,您说您将遵守XMLParserDelegate协议。

//MyController.h

#import "XMLParser.h"

@interface MyController : UIViewController <XMLParserDelegate> { //this is where you "promise" to implement the methods of the protocol.

}

在MyController.m文件中,您现在可以实例化XMLParser。

@implementation MyController

- (void) init {
XMLParser *parser = [[XMLParser alloc] init];
[parser setDelegate:self] //now the parser has a reference to this object.
[parser start];

}

- (void) parserDidFinish:(NSArray*) results {

//now you have your results in the controller, can set it as the data source of the tableView and call tableView.reloadData;
}

这是一个很好的模式,它可以松散地与呼叫者和响应者结合,而不会让他们知道协议所规定的任何其他内容。

如果我的视图元素仅限于其自身的功能,例如时钟。 我会有一个ClockViewController,它会实例化arm,dials等。它们都会链接到时钟并使用这种模式提醒时钟控制器他们的行为。这样我可以使用时钟臂或拨打其他代码,只要实例化它们的对象遵守ClockArmDelegate协议。

希望它有道理:)它是我非常肯定的,在Cocoa中最常用的模式。

答案 2 :(得分:0)

我在这里看到三种可能的解决方案:

  • NSNotifications 即可。易于实现,但并不总是很好的可维护性(您永远不知道哪个对象已注册到您的通知)
  • 委托数组(而不是单个委托),并在数组的每个对象上调用委托方法。 Three20大量使用这种模式(而Three20是一个很好的参考),但它仍然看起来像委托模式被拉得太远了,恕我直言。
  • 数据对象上的
  • 键值观察。例如,如果模型上包含已解析的RSS数据的属性“RSSItems”,则应注册每个控制器以侦听对RSSItems对象的更改:

    [rssParser addObserver:yourViewController
                forKeyPath:@"RSSItems"
                   options:NSKeyValueObservingOptionNew
                   context:NULL];
    

然后,在您的parser:didEndElement:方法中,您将设置RSSItem的内容,从而触发KVO通知。

我认为第三种选择是最好的:它是一种标准的Cocoa机制,它不需要系统范围的通知,也不会过多地延长委托模式。