123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- //
- // NSThread+YYAdd.h
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 15/7/3.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import "NSThread+YYAdd.h"
- #import <CoreFoundation/CoreFoundation.h>
- @interface NSThread_YYAdd : NSObject @end
- @implementation NSThread_YYAdd @end
- #if __has_feature(objc_arc)
- #error This file must be compiled without ARC. Specify the -fno-objc-arc flag to this file.
- #endif
- static NSString *const YYNSThreadAutoleasePoolKey = @"YYNSThreadAutoleasePoolKey";
- static NSString *const YYNSThreadAutoleasePoolStackKey = @"YYNSThreadAutoleasePoolStackKey";
- static const void *PoolStackRetainCallBack(CFAllocatorRef allocator, const void *value) {
- return value;
- }
- static void PoolStackReleaseCallBack(CFAllocatorRef allocator, const void *value) {
- CFRelease((CFTypeRef)value);
- }
- static inline void YYAutoreleasePoolPush() {
- NSMutableDictionary *dic = [NSThread currentThread].threadDictionary;
- NSMutableArray *poolStack = dic[YYNSThreadAutoleasePoolStackKey];
-
- if (!poolStack) {
- /*
- do not retain pool on push,
- but release on pop to avoid memory analyze warning
- */
- CFArrayCallBacks callbacks = {0};
- callbacks.retain = PoolStackRetainCallBack;
- callbacks.release = PoolStackReleaseCallBack;
- poolStack = (id)CFArrayCreateMutable(CFAllocatorGetDefault(), 0, &callbacks);
- dic[YYNSThreadAutoleasePoolStackKey] = poolStack;
- CFRelease(poolStack);
- }
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //< create
- [poolStack addObject:pool]; // push
- }
- static inline void YYAutoreleasePoolPop() {
- NSMutableDictionary *dic = [NSThread currentThread].threadDictionary;
- NSMutableArray *poolStack = dic[YYNSThreadAutoleasePoolStackKey];
- [poolStack removeLastObject]; // pop
- }
- static void YYRunLoopAutoreleasePoolObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
- switch (activity) {
- case kCFRunLoopEntry: {
- YYAutoreleasePoolPush();
- } break;
- case kCFRunLoopBeforeWaiting: {
- YYAutoreleasePoolPop();
- YYAutoreleasePoolPush();
- } break;
- case kCFRunLoopExit: {
- YYAutoreleasePoolPop();
- } break;
- default: break;
- }
- }
- static void YYRunloopAutoreleasePoolSetup() {
- CFRunLoopRef runloop = CFRunLoopGetCurrent();
- CFRunLoopObserverRef pushObserver;
- pushObserver = CFRunLoopObserverCreate(CFAllocatorGetDefault(), kCFRunLoopEntry,
- true, // repeat
- -0x7FFFFFFF, // before other observers
- YYRunLoopAutoreleasePoolObserverCallBack, NULL);
- CFRunLoopAddObserver(runloop, pushObserver, kCFRunLoopCommonModes);
- CFRelease(pushObserver);
-
- CFRunLoopObserverRef popObserver;
- popObserver = CFRunLoopObserverCreate(CFAllocatorGetDefault(), kCFRunLoopBeforeWaiting | kCFRunLoopExit,
- true, // repeat
- 0x7FFFFFFF, // after other observers
- YYRunLoopAutoreleasePoolObserverCallBack, NULL);
- CFRunLoopAddObserver(runloop, popObserver, kCFRunLoopCommonModes);
- CFRelease(popObserver);
- }
- @implementation NSThread (YYAdd)
- + (void)addAutoreleasePoolToCurrentRunloop {
- if ([NSThread isMainThread]) return; // The main thread already has autorelease pool.
- NSThread *thread = [self currentThread];
- if (!thread) return;
- if (thread.threadDictionary[YYNSThreadAutoleasePoolKey]) return; // already added
- YYRunloopAutoreleasePoolSetup();
- thread.threadDictionary[YYNSThreadAutoleasePoolKey] = YYNSThreadAutoleasePoolKey; // mark the state
- }
- @end
|