You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

107 lines
3.9 KiB

//
// 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