performSelector:withObject:在通过块间接调用时不调用afterDelay,否则调用

时间:2014-04-30 15:37:27

标签: ios

我正在做一些电话调用背景处理的实验,并发现我无法获得performSelector:withObject:afterDelay如果从块内间接调用则调用fire,但如果直接调用则会触发

此代码显示我的意思:

@implementation MyAppDelegate

- (void) sausages
{
    NSLog(@"*************Sausages");
    [self performSelector:@selector(sausages) withObject:nil afterDelay:10];
}
- (void) sausages2
{
    NSLog(@"*************Sausages 2");
    [self performSelector:@selector(sausages2) withObject:nil afterDelay:10];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
        [self sausages2];

        MyAppDelegate __weak *weakSelf = self;
        [self.callCenter setCallEventHandler:^(CTCall *call)
         {
        if ([call.callState isEqualToString: CTCallStateIncoming])
             {
                 NSLog(@"Incomming");
                 [weakSelf sausages];
             }
         }];

当我运行此代码并将应用程序切换到后台时,banages2方法每10秒触发一次(应用程序的位置背景模式未显示在代码段中)。

当我打电话给设备然后接听电话然后在通话期间,香肠2方法仍然每10秒触发一次,但香肠方法只触发一次。这是为什么?为什么在电话会议期间不断调用香肠方法,但香肠方法是什么?

1 个答案:

答案 0 :(得分:3)

问题是setCallEventHandler无疑是异步运行的,并且你不能使用performSelector延迟来自除主队列之外的任何东西上运行的异步块(因为它需要{{1} }})。

它更容易使用NSRunLoop,它不会受此问题的影响。例如,如果要在十秒钟后在主队列上调用dispatch_after,则可以执行以下操作:

someMethod

或者,如果您希望它在某个后台队列上运行:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self someMethod];
});

话虽如此,看起来你想要反复调用这个方法,所以我可能只是倾向于使用dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self someMethod]; }); 或调度源定时器,而不是让方法在10秒后自行调用。例如,如果从主队列启动此计时器,则您需要定义属性:

NSTimer

然后如果从主队列开始,那就简单如下:

@property (nonatomic, strong) NSTimer *timer;

如果从完成块启动此计时器,您可能必须在主runloop上明确安排计时器:

self.timer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(someMethod:) userInfo:nil repeats:YES];

self.timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(someMethod:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; 将被定义为将someMethod作为参数:

NSTimer

顺便说一下,在做重复计时器时,记得- (void)someMethod:(NSTimer *)timer { NSLog(@"%s: %@", __PRETTY_FUNCTION__, timer); } 计时器,例如视图消失,以避免强烈的参考周期:

invalidate