Безопасно ли автоматически высвобождать объекты внутри NSOperation?
Я выполняю операции типа NSInvocationOperation в NSOperationQueue, и мне было интересно, безопасно ли выполнять автоматическое высвобождение объектов - то есть гарантируется ли, что поток, запущенный для каждой операции, имеет собственный пул автоматического выпуска.
Я не нашел никаких пулов авто-выпусков документации для операций - Чтение документации Apple фактически предполагает, что мне действительно нужно определить свой собственный пул авто-выпусков.
Однако: 1) Я не вижу никаких утечек в инструментах, по крайней мере, не больше, чем когда я выделяю свой пул автоматического выпуска в операции.
2) глядя в отладчике, я вижу эту трассировку стека:
#0 0x00fc3e82 in -[NSObject(NSObject) release] ()
#1 0x00faaa6c in CFRelease ()
#2 0x00fbf804 in __CFBasicHashDrain ()
#3 0x00faabcb in _CFRelease ()
#4 0x00fcfb8d in _CFAutoreleasePoolPop ()
#5 0x000edd0d in -[__NSOperationInternal start] ()
#6 0x000ed826 in ____startOperations_block_invoke_2 ()
#7 0x94358024 in _dispatch_call_block_and_release ()
#8 0x9434a2f2 in _dispatch_worker_thread2 ()
#9 0x94349d81 in _pthread_wqthread ()
#10 0x94349bc6 in start_wqthread ()
Таким образом, похоже, что существует CFAutoreleasePool. Безопасно ли предполагать, что этот объект вызовет release для всех моих автоматически выпущенных объектов, когда операция будет завершена?
1 ответ
Я написал небольшую программу, чтобы проверить, NSInvocationOperation
создаст пул автоматического выпуска для операции:
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
- (void)performSomeTask:(id)data
{
NSString *s = [[[NSString alloc] initWithFormat:@"hey %@", data]
autorelease];
if ([[NSThread currentThread] isMainThread])
NSLog(@"performSomeTask on the main thread!");
else
NSLog(@"performSomeTask NOT on the main thread!");
NSLog(@"-- %@", s);
}
@end
int main(int argc, char *argv[]) {
MyClass *c = [MyClass new];
if (argc == 2 && strcmp(argv[1], "nop") == 0)
[c performSomeTask:@"ho"];
else {
NSInvocationOperation *op = [[NSInvocationOperation alloc]
initWithTarget:c
selector:@selector(performSomeTask:)
object:@"howdy"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op];
[op waitUntilFinished];
[op release];
[queue release];
}
[c release];
return 0;
}
Он работает следующим образом: если в командной строке передано "nop", оно выполнится -performSomeTask:
напрямую, в главном потоке, без пула автоматического выпуска. В результате получается:
$ ./c nop
*** __NSAutoreleaseNoPool(): Object 0x10010cca0 of class NSCFString autoreleased with no pool in place - just leaking
performSomeTask on the main thread!
-- hey ho
Авто-выпущенная строка в -performSomeTask:
вызывает утечку.
Запуск программы без пропуска "nop" выполнит -performSomeTask:
через NSInvocationOperation
в другой теме. В результате получается:
$ ./c
*** __NSAutoreleaseNoPool(): Object 0x100105ec0 of class NSInvocation autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x100111300 of class NSCFSet autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x100111b60 of class NSCFSet autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x100105660 of class NSCFSet autoreleased with no pool in place - just leaking
performSomeTask NOT on the main thread!
-- hey howdy
Как мы видим, есть случаи NSInvocation
а также NSSet
которые протекают, но автоматически выпущенная строка в -performSomeTask:
не просачивается, следовательно, для этой операции вызова был создан пул автоматического выпуска.
Я думаю, можно с уверенностью предположить, что NSInvocationOperation
(и, вероятно, все NSOperation
подклассы в каркасах Apple) создают свои собственные пулы автоматического выпуска, как в Руководстве по программированию параллелизма предлагается для пользовательских NSOperation
подклассы.