Iphone 如何在NSXMLParser运行时禁用按钮,然后在完成时启用它?
我有一个Iphone 如何在NSXMLParser运行时禁用按钮,然后在完成时启用它?,iphone,cocoa,cocoa-touch,Iphone,Cocoa,Cocoa Touch,我有一个viewController,它导入XMLParser.h作为类XMLParser 我正在使用下面的getXML方法将viewController中的NSURL对象传递给xmlParser类 goButton是我点击调用下面的getXML方法的按钮。我禁用了触发getXML方法的按钮,但我不确定在xmlParser完成对返回的XML的解析后,将代码放在何处再次启用它 - (IBAction) getXML { goButton.enabled = NO; // allo
viewController
,它导入XMLParser.h
作为类XMLParser
我正在使用下面的getXML
方法将viewController
中的NSURL
对象传递给xmlParser
类
goButton
是我点击调用下面的getXML
方法的按钮。我禁用了触发getXML
方法的按钮,但我不确定在xmlParser完成对返回的XML的解析后,将代码放在何处再次启用它
- (IBAction) getXML {
goButton.enabled = NO;
// allocate and initialize the xmlParser
xmlParser = [[XMLParser alloc] init];
// then generate the URL we are going to pass to it and call the fetchXML method passing the URL.
NSURL *xmlurl = [[NSURL alloc] initWithString:@"http://www.mysite.com/myfile.xml"];
[xmlParser fetchXMLFromURL:xmlurl];
// release objects
[xmlurl release];
[xmlParser release];
}
根据@squegy的建议,我修改了我的代码
- (IBAction) getXML {
goButton.enabled = NO;
xmlParser = [[XMLParser alloc] init];
[self performSelectorInBackground:@selector(parseInBackground:) withObject:xmlParser];
}
- (void)parseInBackground:(XMLParser*)parser {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *xmlurl = [[NSURL alloc] initWithString:@"http://www.mysite.com/myfile.xml"];
[parser fetchXMLFromURL:xmlurl];
[self performSelectorOnMainThread:@selector(didFinishXMLParsing:) withObject:parser];
[xmlurl release];
[pool drain];
}
- (void)didFinishXMLParsing:(NSXMLParser*)parser {
goButton.enabled = YES;
}
看起来一直在工作,直到到达终点
[self performSelectorOnMainThread:@selector(didFinishXMLParsing:) withObject:parser];
编译器抱怨如下:
2010-02-17 00:22:20.574 XMLApp[2443:521b] *** -[viewController performSelectorOnMainThread:withObject:]: unrecognized selector sent to instance 0x1285a0
2010-02-17 00:22:20.578 XMLApp[2443:521b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[viewController performSelectorOnMainThread:withObject:]: unrecognized selector sent to instance 0x1285a0'
2010-02-17 00:22:20.583 XMLApp[2443:521b] Stack: (
861696817,
860329709,
861700631,
861203093,
861166272,
18715,
846004025,
845672609,
848189713
)
当解析器完成解析时,它将调用其委托的:
-(void)parserdinddocument:(NSXMLParser*)parser
在该方法中,您可以重新启用该按钮。您可能应该通过调用performSelectorInMainThread
来执行此操作,因为它涉及到更改视图
- (IBAction)getXML {
goButton.enabled = NO;
xmlParser = [[XMLParser alloc] init];
NSURL *xmlurl = [[NSURL alloc] initWithString:@"http://www.mysite.com/myfile.xml"];
[xmlParser fetchXMLFromURL:xmlurl];
[self performSelectorInBackground:@selector(parseInBackground) withObject:xmlParser];
[xmlurl release];
[xmlParser release];
}
- (void)parseInBackground:(NSXMLParser*)parser {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[parser parse];
[self performSelectorOnMainThread:@selector(didFinishXMLParsing:)
withObject:parser
waitUntilDone:NO];
[pool drain];
}
- (void)didFinishXMLParsing:(NSXMLParser*)parser {
goButton.enabled = YES;
}
诀窍是在后台线程上进行处理,这允许UI执行一些操作。解析完成后,您必须在主线程上进行任何UI更改。@pgb您能详细说明如何实现这一点吗?我没有改变视图,
viewController
是我调用解析器的视图。解析器不是在另一个视图中,它只是在一个外部类中,它是一个NSObject
谢谢@squegy,但我想你误解了我的问题,但我不能确定,因为我不太理解你的代码。我的解析代码位于一个外部类中,该类的唯一目的是作为一个泛型类,我可以导入该类以便在我的应用程序中进行解析。我已经在视图控制器中导入了解析器类的头文件,并从视图控制器中调用了解析器。@squegy我的目标只是禁用该按钮,以便在完成前一个请求之前不能多次调用该方法。因此,我只希望阻止用户在解析完成之前按下按钮。这就做到了performSelectorInBackground:withObject:
允许您在后台线程中运行方法。这对于允许主线程上的UI更新(禁用按钮)非常重要。您的应用程序已响应,但您的按钮已禁用。当解析完成时,它会说“嘿,主线程,我完成了解析”,主线程会启用该按钮。这很重要,因为只有主线程可以更新UI。因此,您的解析器类将在后台线程中执行自己的解析方法,然后在完成后在主线程上调用其委托的方法。好的,我明白您的意思了。我收到一个运行时错误,请参见以下内容:2010-02-16 23:54:31.935 XMLApp[2371:640f]***-[XMLParser parse parse]:发送到实例0x152340的无法识别的选择器传递到parseInBackground的对象是一个类型XMLParser,它是我的自定义类。它不是一个NSXMLParserNSXMLParser
有一个名为parse
的方法。您需要调用在自定义类中执行解析的方法fetchXMLFromURL:
我想应该是这样。我的错误是,该方法是-(void)performSelectorOnMainThread:(SEL)一个带对象的选择器:(id)arg waitUntilDone:(BOOL)wait
。我在回答中给出了错误的方法名称。@squegy-OK,这有点帮助。现在没有错误,但我的函数fetchXMLFromURL实际上并没有做它应该做的事情。这就好像在解析器为xml文件实际启动到服务器的连接之前,控制正在返回到主线程。在引入线程之前,它工作得很好。也许你应该在一个有线程的沙箱中尝试一个更简单的例子。让你的头脑清醒是很困难的。听起来这可能是一个单独的问题,一个单独的问题。这个问题有点拥挤了。@squegy好吧,我想这个问题有点难看了。感谢您的帮助,我认为禁用和重新启用按钮比线程更容易。似乎不必要的复杂