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,它是我的自定义类。它不是一个NSXMLParser
NSXMLParser
有一个名为
parse
的方法。您需要调用在自定义类中执行解析的方法
fetchXMLFromURL:
我想应该是这样。我的错误是,该方法是
-(void)performSelectorOnMainThread:(SEL)一个带对象的选择器:(id)arg waitUntilDone:(BOOL)wait
。我在回答中给出了错误的方法名称。@squegy-OK,这有点帮助。现在没有错误,但我的函数fetchXMLFromURL实际上并没有做它应该做的事情。这就好像在解析器为xml文件实际启动到服务器的连接之前,控制正在返回到主线程。在引入线程之前,它工作得很好。也许你应该在一个有线程的沙箱中尝试一个更简单的例子。让你的头脑清醒是很困难的。听起来这可能是一个单独的问题,一个单独的问题。这个问题有点拥挤了。@squegy好吧,我想这个问题有点难看了。感谢您的帮助,我认为禁用和重新启用按钮比线程更容易。似乎不必要的复杂