2
votes

I have learnt one global rule in iOS -> never to block main thread. However, several time I run into open source code snippets where this rule is violated.

Two such examples are follows :

The following function is taken from https://github.com/piwik/piwik-sdk-ios/blob/master/PiwikTracker/PiwikTracker.m

- (void)startDispatchTimer {

  // Run on main thread run loop
  __weak typeof(self)weakSelf = self;
  dispatch_async(dispatch_get_main_queue(), ^{

    [weakSelf stopDispatchTimer];

    // If dispatch interval is  0) {

      // Run on timer
      weakSelf.dispatchTimer = [NSTimer scheduledTimerWithTimeInterval:weakSelf.dispatchInterval
                                                                target:weakSelf
                                                              selector:@selector(dispatch:)
                                                              userInfo:nil
                                                               repeats:NO];

      NSLog(@"Dispatch timer started with interval %f", weakSelf.dispatchInterval);

    }

  });

}

In the above code I have been trying to understand why is main thread required for timer object. Something like this is not UI related and still done on main thread.

Another example of this is in a famous networking library MKNetworkKit . Where the following code is in start method of NSOperation. https://github.com/MugunthKumar/MKNetworkKit/blob/master/MKNetworkKit/MKNetworkOperation.m


dispatch_async(dispatch_get_main_queue(), ^{
      self.connection = [[NSURLConnection alloc] initWithRequest:self.request
                                                        delegate:self
                                                startImmediately:NO];

      [self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
                                 forMode:NSRunLoopCommonModes];

      [self.connection start];
    });

So my questions is why do people use main thread for doing no UI related operations and what benefit does it give. It may not freeze your app if you are not holding on to it but why take a chance.

1

1 Answers

2
votes

Both examples are using NSRunLoop methods directly or indirectly. In those cases, you should call the methods from the thread which executes the target NSRunLoop. Thus you need dispatch_get_main_queue().

Take a look at the apple document about NSRunLoop https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/nsrunloop_class/reference/reference.html

Warning: The NSRunLoop class is generally not considered to be thread-safe and its methods should only be called within the context of the current thread. You should never try to call the methods of an NSRunLoop object running in a different thread, as doing so might cause unexpected results.

By the way, NSRunLoop seems using CFRunLoop in Core Foundation, and Core Foundation was released under an open source license from Apple.

http://opensource.apple.com/source/CF/CF-855.17/CFRunLoop.c

It seems CFRunLoop is thread-safe (we can see a lot of __CFRunLoopLock and __CFRunLoopUnlock combination). But you would better obey the document anyway :)