// In the default implementation, all requests run in a single background thread // Advanced users only: Override this method in a subclass for a different threading behaviour // Eg: return [NSThread mainThread] to run all requests in the main thread // Alternatively, you can create a thread on demand, or manage a pool of threads // Threads returned by this method will need to run the runloop in default mode (eg CFRunLoopRun()) // Requests will stop the runloop when they complete // If you have multiple requests sharing the thread or you want to re-use the thread, you'll need to restart the runloop + (NSThread*)threadForRequest:(ASIHTTPRequest*)request { if (networkThread ==nil) { @synchronized(self) { if (networkThread ==nil) { networkThread = [[NSThread alloc] initWithTarget:self selector:@selector(runRequests) object:nil]; [networkThread start]; } } } return networkThread; } + (void)runRequests { // Should keep the runloop from exiting CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; CFRunLoopSourceRef source =CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); BOOL runAlways =YES; // Introduced to cheat Static Analyzer while (runAlways) { NSAutoreleasePool*pool = [[NSAutoreleasePool alloc] init]; CFRunLoopRun(); [pool drain]; } // Should never be called, but anyway CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); CFRelease(source); }
+ (void)startCFStreamThreadIfNeeded { static dispatch_once_t predicate; dispatch_once(&predicate, ^{ cfstreamThread = [[NSThread alloc] initWithTarget:self selector:@selector(cfstreamThread) object:nil]; [cfstreamThread start]; }); } + (void)cfstreamThread { @autoreleasepool{ [[NSThread currentThread] setName:GCDAsyncSocketThreadName]; LogInfo(@"CFStreamThread: Started"); // We can't run the run loop unless it has an associated input source or a timer. // So we'll just create a timer that will never fire - unless the server runs for decades. [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow] target:self selector:@selector(doNothingAtAll:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] run]; LogInfo(@"CFStreamThread: Stopped"); }}
1 2 3 4 5 6 7 8 9 10 11 12 13
+ (void)scheduleCFStreams:(GCDAsyncSocket*)asyncSocket { LogTrace(); NSAssert([NSThread currentThread] == cfstreamThread, @"Invoked on wrong thread"); CFRunLoopRef runLoop =CFRunLoopGetCurrent(); if (asyncSocket->readStream) CFReadStreamScheduleWithRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode); if (asyncSocket->writeStream) CFWriteStreamScheduleWithRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode); }
CFRunLoopRef runLoop =CFRunLoopGetCurrent(); // This is a idle mode of RunLoop, when UIScrollView scrolls, it jumps into "UITrackingRunLoopMode" // and won't perform any cache task to keep a smooth scroll. CFStringRef runLoopMode = kCFRunLoopDefaultMode; // Collect all index paths to be precached. NSMutableArray*mutableIndexPathsToBePrecached =self.fd_allIndexPathsToBePrecached.mutableCopy; // Setup a observer to get a perfect moment for precaching tasks. // We use a "kCFRunLoopBeforeWaiting" state to keep RunLoop has done everything and about to sleep // (mach_msg_trap), when all tasks finish, it will remove itself. CFRunLoopObserverRef observer =CFRunLoopObserverCreateWithHandler (kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity_) { // Remove observer when all precache tasks are done. if (mutableIndexPathsToBePrecached.count ==0) { CFRunLoopRemoveObserver(runLoop, observer, runLoopMode); CFRelease(observer); return; } // Pop first index path record as this RunLoop iteration's task. NSIndexPath*indexPath = mutableIndexPathsToBePrecached.firstObject; [mutableIndexPathsToBePrecached removeObject:indexPath]; // This method creates a "source 0" task in "idle" mode of RunLoop, and will be // performed in a future RunLoop iteration only when user is not scrolling. [self performSelector:@selector(fd_precacheIndexPathIfNeeded:) onThread:[NSThread mainThread] withObject:indexPath waitUntilDone:NO modes:@[NSDefaultRunLoopMode]]; }); CFRunLoopAddObserver(runLoop, observer, runLoopMode);