【问题标题】:IOS - performSelector:withObject:afterDelay: NOT WORKINGIOS - performSelector:withObject:afterDelay: 不工作
【发布时间】:2013-06-02 02:54:05
【问题描述】:

参考:

https://stackoverflow.com/a/14741253/1749293

就像上面的链接说的那样,但似乎没有解释原因。

在我的代码中,以下将起作用:

dispatch_async(dispatch_get_main_queue(), ^{
       [self performSelector:  @selector(helloWorld) withObject:nil afterDelay:0.5];
}); 

但是,当我评论这样的事情时,(我真的确定我在主线程中运行它!!)代码不起作用:

//    dispatch_async(dispatch_get_main_queue(), ^{
        [self performSelector:  @selector(helloWorld) withObject:nil afterDelay: 0.5];
//    });

谁能告诉我为什么? AND 'self',会释放/释放,我会保留它,直到应用程序结束。

“不工作”,意味着,(没有崩溃)它不会跳转到“helloWorld”方法:

-(void) helloWorld {
    NSLog(@"hello world");     // I set a break point here for debug , it wouldn't pause forever
}

我认为是 Run Loop 导致了这个问题。就像this link 说的那样,但我需要更多细节或更明确的解释。

【问题讨论】:

  • 如果你确实在主线程上,那就奇怪了。您不使用dispatch_after()的任何特殊原因?
  • 什么是 BROKER.actors.event?
  • 在您的第一个代码中您使用self,而在第二个代码中您使用BROKER.actors.event。所以你确定他们指的是同一件事吗?
  • “不起作用”...是什么意思?它会崩溃吗?以防万一,日志消息是什么?
  • 看到您的最后一次编辑,您似乎不在主线程上,在这种情况下,@WaltSellers 的回答适用。你究竟是如何测试你在主线程上的?你能写一个重现你的问题的小测试用例吗?

标签: iphone ios objective-c


【解决方案1】:

当我遇到这种事情时,我正在从 GCD 调度中调用 performSelector。因此,它在 GCD 工作线程中设置了计时器,该线程在计时器触发之前就消失了。当 GCD 移除工作线程时,计时器丢失了,所以选择器永远不会被调用。

【讨论】:

    【解决方案2】:

    编辑 如 cmets 所述, performSelector: withObject: afterDelay: 也保留您的对象,因此请忽略我的回答。 结束编辑

    我假设您正在使用 ARC。您的块正在保留您的对象。

    dispatch_async(dispatch_get_main_queue(), ^{
           [self performSelector:  @selector(helloWorld) withObject:nil afterDelay:aTimeUnit];
    });
    

    这就是选择器被触发的原因。当您评论该块时,没有人会保留对您对象的引用,因此它会自动释放。

    //    dispatch_async(dispatch_get_main_queue(), ^{
            [self performSelector:  @selector(helloWorld) withObject:nil afterDelay: aTimeUnit];
    //    });
    

    aTimeUnit已经过去的时候,self可能已经被释放了,所以选择器调用丢失了。那是你的问题。

    您应该避免在块内捕获 self,因为如果您将块存储在 ivar 中,您可能会遇到一个保留循环,这会导致对象不会被释放。他们在这里谈论这个: How do I avoid capturing self in blocks when implementing an API?

    【讨论】:

    • 对已释放对象的选择器调用通常以崩溃结束,对吧?
    • 我很确定 performSelector 也会保留所有内容。
    • 我也认为,作为 w.sellers,performSelector 将成为感兴趣对象的所有者,并保留它直到它执行选择器,因此无需担心同时释放 self 跨度>
    【解决方案3】:

    Apple Documents 说:

    This method sets up a timer to perform the aSelector message on the current thread’s run loop.
    
    The timer is configured to run in the default mode (NSDefaultRunLoopMode).
    
    It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode
    

    请注意: 只有在默认模式下才能成功(NSDefaultRunLoopMode)

    现在。假设你有这样的代码:

    dispatch_async(dispatch_queue_create("com.serial.thread", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"1");
        [self performSelector:@selector(testLog2) withObject:nil afterDelay:0];
    });
    

    PO[NSRunLoop currentRunLoop]在这个Thread:

    <CFRunLoop 0x6040001ea000 [0x10c642960]>
    {
     wakeup port   = 0x5207, 
     stopped       = false, 
     ignoreWakeUps = true, 
     current mode  = (none),.....
    }
    

    如您所见,current mode(none)。所以这个函数永远不会被调用!

    但是如果performSelector:withObject:afterDelay:Main Thread中,例如viewDidLoad,就会调用该函数。

    以下日志是[NSRunLoop currentRunLoop] in viewDidLoad

    <CFRunLoop 0x6000001e9700 [0x10c642960]>
    {
     wakeup port   = 0x1d03, 
     stopped       = false, 
     ignoreWakeUps = false, 
     current mode  = kCFRunLoopDefaultMode,......
    }
    

    @isaacselement

    【讨论】:

      猜你喜欢
      • 2011-02-21
      • 1970-01-01
      • 2012-02-12
      • 1970-01-01
      • 2012-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多