当我添加Realm然后它锁定CFRunLoopRun和我的NSURLConnection队列

时间:2017-03-15 04:04:58

标签: ios realm nsurlconnection

-app具有用于运行NSURLConnection的串行队列

-app订阅了connectionDidFinishLoading事件

-app使得简单的' ping'到站点并在队列中运行CFRunLoopRun以启用事件

-app在收到connectionDidFinishLoading事件后关闭连接,     在CFRunLoopRun退出时,我们记录它并在退出队列任务后,另一个任务将收到执行槽

- 但如果我们添加Realm,那么CFRunLoopRun将无限期运行,现在我们的队列被锁定

我还打开了票https://github.com/realm/realm-cocoa/issues/4737

#import "Realm/Realm.h"

@interface ViewController () <NSURLConnectionDataDelegate>
@end

@implementation ViewController {
  dispatch_queue_t my_queue;
  NSURLConnection *_connection;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  my_queue = dispatch_queue_create("my queue", NULL);

  dispatch_async(my_queue, ^{

    [RLMRealm defaultRealm];     // (1) // comment to make it running
    NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.com"]];
    _connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
    CFRunLoopRun();              // (2) infinite loop inside ios so (3) and (4) as result never been called
    NSLog(@"done");              // (3)

  });

}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
  dispatch_async(my_queue, ^{
    NSLog(@"test");              // (4) // never been called when realm is used in the same queue
  });
  _connection = nil;             // (5) // without (1) this line stops runloop so (2) and (3) will be called
}

1 个答案:

答案 0 :(得分:0)

CFRunLoopRun以默认模式运行runloop,直到删除所有源和计时器,或调用CFRunLoopStop。您的代码似乎是在没有其他人会在该runloop上添加runloop源或注册计时器的情况下运行的,并且当您的网络请求结束时,所有runloop源都将被删除。我不认为对您调用的任何第三方代码的行为做出假设是安全的,无论是Realm还是Apple。

此外,我建议不要在调度队列上运行runloop。 Dispatch对由有限数量的系统拥有的线程服务的队列进行排队,并且在等待网络请求时将其阻塞不确定的时间量。 NSURLConnection很乐意让你schedule the connection on a different runloop,例如主线程的runloop,甚至是schedule delegate callbacks to happen on a dispatch queue

如果你绝对必须继续在这样的调度队列上运行runloop,你应该使用一些显式信号来确定何时停止运行runloop然后调用CFRunLoopStop。我建议不要这样做。