【发布时间】:2012-10-10 08:02:57
【问题描述】:
我有一个向串行 NSOperationQueue 添加操作的方法。由于我想定期调用该方法,所以我使用调度源计时器。
但是,也可以调用此方法来响应用户操作。当发生这种情况时(例如,由于计时器调用方法之前的片刻)我延长计时器的触发日期。
问题是我写的代码有一个保留循环,我不明白在哪里。
这是演示问题的简化示例(不要忘记将部署 SDK 设置为 10.7):
#import <Foundation/Foundation.h>
@interface MyObject : NSObject
@end
@implementation MyObject
{
NSOperationQueue *_queue;
dispatch_source_t _timer;
}
- (id)init
{
self = [super init];
if (self)
{
_queue = [[NSOperationQueue alloc] init];
[_queue setMaxConcurrentOperationCount:1];
}
return self;
}
- (void)dealloc
{
NSLog(@"dealloc");
[_queue cancelAllOperations];
dispatch_source_cancel(_timer);
dispatch_release(_timer);
}
- (void)scheduleTimer
{
if (_timer)
{
dispatch_source_cancel(_timer);
dispatch_release(_timer);
}
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0,
0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
if (_timer)
{
__weak MyObject *selfBlock = self;
dispatch_source_set_event_handler(_timer, ^{
dispatch_source_cancel(_timer);
[selfBlock doMethod];
});
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0);
dispatch_resume(_timer);
}
}
- (void)doMethod
{
NSLog(@"doMethod");
__weak MyObject *selfBlock = self;
[_queue cancelAllOperations];
[_queue addOperationWithBlock:^{
[selfBlock scheduleTimer];
}];
}
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
MyObject *obj = [MyObject new];
[obj doMethod];
sleep(10);
obj = nil;
NSLog(@"something still points to obj");
sleep(10);
}
return 0;
}
【问题讨论】:
-
这个问题是用ARC标记的,但是你怎么能在那里调用dispatch_release呢?
-
@Eiko Dispatch 对象不需要 dispatch_release 如果最小部署 SDK 是 10.8 所以你仍然需要在 10.7 下手动释放它们
-
您在哪里发现了保留周期?我在 Instruments 中运行了您的代码,部署目标为 10.7。它没有检测到周期。静态分析器没有显示任何保留周期。
-
@NSBum MyObject 实例永远不会被释放(除非应用程序当然被终止)。我希望它会在
obj = nil之后很快被释放。不幸的是,有些东西保留了对对象的引用
标签: objective-c automatic-ref-counting nsoperationqueue retain-cycle