NSRunLoop有时会使应用程序无响应

时间:2014-06-09 10:23:34

标签: ios objective-c xcode multithreading nsrunloop

在我的应用中,我需要对restful web api进行https调用,并在返回时处理结果。同时服务调用的数量永远不会被修复,因此相关代码已被相应地写入。从服务获取的数据临时存储在应用程序内的SQLite DB中。以下是它的工作原理。

当用户导航到需要获取数据的任何屏幕或UI组件时,视图控制器在其指定的模型对象上调用方法。然后,此方法检查数据是否已存在于数据库中,或者是否需要获取数据。如果存在数据,则将其返回给视图控制器。否则,它会启动异步服务请求并等待响应,然后将数据返回给VC。因此,VC在调用指定模型之前初始化一个加载指示符,并在从该函数返回控制之后解除相同的加载指示符。

重要的是模型上的函数等待,直到从web api收到响应。这是通过注册NSNotification来完成的,一旦将返回的数据写入DB,该NSNotification将由服务模块发出。一个布尔变量,它在发出服务请求时设置为false,一旦收到响应就设置为true。 NSRunLoop在此布尔变量的错误条件下运行。因此,一旦变量设置为true,其余处理就可以继续。

以下是实施所有这些的相关代码:

[serviceModule initServiceCall:@"25" withDictionary:[NSDictionary dictionaryWithObjects:@[asOfDate] forKeys:@[@"toDate"]]];

    dataReady=NO;

    NSString *notificationName = @"dataReady";
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(useNotificationFromServiceModule:) name:notificationName object:nil];

    NSRunLoop *theRL = [NSRunLoop currentRunLoop];
    while (!dataReady && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);

此后功能的其余部分将继续。

这是处理通知的函数:

-(void)useNotificationFromServiceModule:(NSNotification *)notification {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
    dataReady=YES;
});}

通常的过程是,一旦发送通知,NSRunLoop退出并且方法的其余部分完成,返回到视图控制器,然后解除加载指示符。问题是有时这不会发生。发出通知时(我可以看到控制台日志),NSRunLoop不会结束。加载指示器继续出现在屏幕上并保持这种状态,直到屏幕被轻敲一次。点击屏幕时,NSRunLoop结束,其余过程随机继续。

这不会永远发生。它发生在相当随机的情况下,可能是10次中的4-5次。请提供一些输入/指针来说明为什么会发生这种情况。

1 个答案:

答案 0 :(得分:2)

如果你直接使用run循环,你要么非常聪明,要么非常愚蠢。在第一种情况下,您将自己找到答案。在第二种情况下,如果你按照与其他人一样的方式执行相同的模式会更好,这是在后台线程上运行网络代码并在结果到达时使用dispatch_async。