シリアル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;
}