【问题标题】:How to call performSelectorInBackground with a function having arguments?如何使用具有参数的函数调用 performSelectorInBackground?
【发布时间】:2013-05-14 08:46:28
【问题描述】:

抱歉新手问题(也许)。我正在为 ios 开发一个应用程序,并且我正在尝试从主线程中执行一个外部 xml 读取,以免在调用发挥其魔力时冻结 ui。

这是我知道的唯一方法使进程不在目标 c 的主线程中执行

[self performSelectorInBackground:@selector(callXml)
                           withObject:self];

所以我确实将我的调用封装到一个函数中

 - (void)callXml{
     [RXMLElement elementFromURL:[NSURL URLWithString:indXML]];
 }

现在我必须将字符串 indXML 作为函数的参数,以便根据需要调用不同的 xml。 类似的东西

 - (void)callXml:(NSString *) name{
     [RXMLElement elementFromURL:[NSURL URLWithString:indXML]];
 }

在这种情况下,对 performSelector 的调用如何变化?如果我以通常的方式执行此操作,则会出现语法错误:

[self performSelectorInBackground:@selector(callXml:@"test")
                           withObject:self];

【问题讨论】:

    标签: ios objective-c performselector


    【解决方案1】:
    [self performSelectorInBackground:@selector(callXml:)
                           withObject:@"test"];
    

    ie: 你作为 withObject: 传入的内容成为你的方法的参数。

    就像一个兴趣点,这里是您如何使用 GCD 做到这一点:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self callXml:@"test"];
    
        // If you then need to execute something making sure it's on the main thread (updating the UI for example)
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateGUI];
        });
    });
    

    【讨论】:

    • 第二种方式,代码会在主线程之外执行,不会打乱ui流程?
    • 是的。见here ...“并发队列(也称为全局调度队列的一种)同时执行一个或多个任务,但任务仍然按照加入队列的顺序启动。当前执行任务在由调度队列管理的不同线程上运行。 在任何给定点执行的任务的确切数量是可变的,并且取决于系统条件。"
    • 我还在猜测该怎么做。对于您建议的使用方式,我仍然有问题使用 performSelector 会引发异常,但确实我已经解决了放弃 performSelector 并使用 dispatch_async 的问题。交易! ;)
    • 尝试使用 performSelector 方式解决您的问题:在 'NSInvalidArgumentException' +[funzioni callXml:]) 中注意“+” .这意味着它正在寻找类方法(+(void)callXml:)而不是实例方法(-(void)callXml:),这意味着您正在从类方法而不是实例方法中调用 performSelector...
    【解决方案2】:

    为此

    - (void)callXml:(NSString *) name{
         [RXMLElement elementFromURL:[NSURL URLWithString:indXML]];
     } 
    

    你可以这样调用

      [self performSelectorInBackground:@selector(callXml:)
                                   withObject:@"test"];
    

    如果您的方法有参数,则 : 与 method_name 一起使用,并将参数作为 withObject 参数传递

    【讨论】:

    • 它抛出一个错误:由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'*** - [NSThread initWithTarget:selector:object:]:目标未实现选择器(*** + [funzioni callXml:])' ----- 其中“funzioni”是我的班级。我试图在我的 .m 和我的 .h 中定义函数。没有财富。
    • @ElisabettaFalivene Mike Pollard 已经向您展示了如何从后台线程更新 UI。
    • 使用 GCD?是的,这就是为什么我选择他的答案。这个问题已经为我解决了,但我很想解决我在使用 performSelector 时遇到的问题。 ^^' 不过没那么重要,所以我放弃了。
    • @ElisabettaFalivene:Bhargavi 根据您提供的所有信息给出了正确答案。您的错误与您的问题不一致。您的错误(它试图调用类方法,即您正在调用它的对象,self 是一个类)表明您正在从类方法进行调用。如果是这种情况,那么您之前在调用callXml 时所做的(如果从同一个地方调用)也在调用类方法。但是,在您的问题中,您将 callXmlcallXml: 显示为实例方法。
    【解决方案3】:

    您使用的选择器需要与方法名称完全匹配 - 方法名称包含冒号 (:) 字符。所以你的选择器应该是:

    @selector(callXml:)
    

    如果要传递参数。

    如果您需要传递更复杂的数据,您有 3 个选项:

    1. 传递包含参数的NSArrayNSDictionary
    2. 传递一个包含所有必需数据作为属性的自定义对象
    3. 使用 GCD (GCD_libdispatch reference)

    【讨论】:

    • 传递一个 NSString 很好...查看其他答案
    • 3.选项将传递一个自定义对象,其中包含所有需要的参数。
    【解决方案4】:

    你好,试试这个,

     RXMLElement *rootXML= [self performSelectorInBackground:@selector(callXml:)
                                   withObject:@"test"];
    
    - (RXMLElement *)callXml:(NSString *) name{
    
             NSLog(@"%@",name);//Here passed value will be printed i.e test
    
         return [RXMLElement elementFromURL:[NSURL URLWithString:indXML]];
     } 
    

    【讨论】:

    • 酷!如果函数返回我需要得到的东西怎么办? (即返回 [RXMLElement 等.....])
    • 如果你想从被调用的方法中获取应该返回的东西,即使用你的 return type.ex - (return type)callXml:(NSString *) name { } k @ElisabettaFalivene 而不是 void跨度>
    • 如果你想将它存储在某个变量中然后输入 var_name=[self method];那么被调用的方法将返回一些值。 @ElisabettaFalivene
    • 这是我的猜测,但是当我这样做时 - (RXMLElement *)callXml:(NSString *) xmlName{ return [RXMLElement elementFromURL:[NSURL URLWithString:xmlName]]; } 和 RXMLElement *rootXML=nil; rootXML = [self performSelectorInBackground:@selector(callXml) withObject:indXMLdateAggiornamento];它开始说“从不兼容的类型'void'分配给'RXMLElement *'”
    • 你能告诉我这一行 [RXMLElement elementFromURL:[NSURL URLWithString:indXML]]; 将返回什么类型吗?它将是类型 (RXMLElement *)???
    【解决方案5】:

    因为performSelectorInBackground:withObject: 只接受一个对象参数。解决此限制的一种方法是将参数字典(或数组)传递给“包装器”方法,该方法会解构参数并调用您的实际方法。

    【讨论】:

      猜你喜欢
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 2016-08-04
      • 2015-12-14
      • 1970-01-01
      • 2013-11-14
      • 1970-01-01
      相关资源
      最近更新 更多