2012-05-10 6 views
0

私は、NSOperationにバックグラウンドで実行される時間間隔を与えるカテゴリを開発しました。私はこれについていくつかのフィードバック、特に私が考えていないこのアプローチの潜在的な問題を得ることを本当に感謝します。NSOperation with repeat option

ありがとうございました!ここで

コードです:

NSOperation + Repeat.h

#import <Foundation/Foundation.h> 

@interface NSOperation (repeat) 

@property (readonly, nonatomic) NSTimeInterval repeatInterval; 
@property (readonly, nonatomic) NSOperationQueue *repeatOperationQueue; 

- (void)performUsingOperationQueue:(NSOperationQueue *)operationQueue; 
- (void)performAtRepeatingInterval:(NSTimeInterval)interval usingOperationQueue:(NSOperationQueue *)operationQueue; 

@end 

NSOperation + Repeat.m

#import "NSOperation+repeat.h" 
#import <objc/runtime.h> 

static char const * const RepeatPropertiesKey = "RepeatProperties"; 

@implementation NSOperation (repeat) 

@dynamic repeatInterval; 
@dynamic repeatOperationQueue; 

static NSString * RepeatIntervalKey = @"interval"; 
static NSString * RepeatOperationQueueKey = @"operationQueue"; 
static NSString * RepeatTimerKey = @"timer"; 

- (NSMutableDictionary *)repeatProperties { 
    NSMutableDictionary * properties = objc_getAssociatedObject(self, RepeatPropertiesKey); 
    if (properties == nil) { 
     properties = [NSMutableDictionary new]; 
     objc_setAssociatedObject(self, RepeatPropertiesKey, properties, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    } 
    return properties; 
} 

- (NSTimeInterval)interval { 
    NSNumber * interval = [[self repeatProperties] objectForKey:RepeatIntervalKey]; 
    return [interval doubleValue]; 
} 

- (NSOperationQueue *)repeatOperationQueue { 
    NSOperationQueue * operationQueue = [[self repeatProperties] objectForKey:RepeatOperationQueueKey]; 
    return operationQueue; 
} 

- (void)performUsingOperationQueue:(NSOperationQueue *)operationQueue { 
    [operationQueue addOperation:[self copy]]; 
} 

- (void)performAtInterval:(NSTimer *)timer { 
    [self performUsingOperationQueue:self.repeatOperationQueue]; 
} 

- (void)performAtRepeatingInterval:(NSTimeInterval)interval usingOperationQueue:(NSOperationQueue *)operationQueue { 
    // Save interval and operationQueue in repeatProperties 
    [self.repeatProperties setValue:[NSNumber numberWithDouble:interval] forKey:RepeatIntervalKey]; 
    [self.repeatProperties setValue:operationQueue forKey:RepeatOperationQueueKey]; 

    // Create timer to call performAtInterval on self 
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:(interval*60) 
                 target:self 
                selector:@selector(performAtInterval:) 
                userInfo:nil 
                repeats:YES]; 

    // Save the timer in repeatProperties 
    [self.repeatProperties setValue:timer forKey:RepeatTimerKey]; 

    [self performUsingOperationQueue:operationQueue]; 
} 

@end 

ここで繰り返すことができNSOperationのサブクラスの例です:

MSScheduleImportOperation.h

#import <Foundation/Foundation.h> 
#import "NSOperation+Repeat.h" 

@interface MSScheduleImportOperation : NSOperation <NSCopying> 

@property (readonly, strong, nonatomic) NSString* employeeId; 

- (id)initWithEmployeeId:(NSString *)employeeId; 

@end 

MSScheduleImportOperation.m

#import "MSScheduleImportOperation.h" 

@implementation MSScheduleImportOperation 

@synthesize employeeId = __employeeId; 

- (id)initWithEmployeeId:(NSString *)employeeId  { 
    self = [super init]; 
    __employeeId = [employeeId copy]; 
    return self; 
} 

- (id)copyWithZone:(NSZone *)zone { 
    MSScheduleImportOperation* copy = [[MSScheduleImportOperation alloc] initWithEmployeeId:self.employeeId]; 
    return copy; 
} 

- (void)main 
{ 
... 
} 


@end 
+0

私はかなりの問題を見ることができます。まず、ほとんどのサブクラスがサポートしていないと推測しているNSOperationのコピーを作成しています。 第2に、キャンセルを処理していないようです。操作がキャンセルされた場合、このコードはより多くのインスタンスを生成し続けます。 第3に、操作が完了するまでに時間がかかる場合、このコードにより多くのインスタンスが生成され、複数の操作が同時に実行されます。 –

+0

はい、NSOperationのサブクラスはNSCopyingプロトコルで定義し、(id)copyWithZone:(NSZone *)ゾーンを実装する必要があります。 – ScottD

+0

キャンセルには、私はそれを追加する必要があります。私はそれを繰り返すことを止めるためにタイマにnilを割り当てることができるはずです。 – ScottD

答えて

1

Apple documentationは言う:

操作対象がシングルショットオブジェクト、つまり、それは一度そのタスクを実行し、実行するために使用することはできませんもう一度。

最初の問題は、内部機能が動作しなくなる可能性があることです。しかし、私はあなたがコピーを作成することで問題を回避しようとしているのを見ます。

これは、NSOperationNSCopyingに準拠するようにアドバタイズされていないという問題を引き起こします。

[operationQueue addOperation:[self copy]]; 

この行は例外をスローする必要があります。

+0

はい、NSOperationサブクラスのコピーでは、NSOperationクラスのワンショットアスペクトに対処しようとしていました。しかし、それは動作しているようです。私のサブクラスはNSCopyingプロトコルで定義され、(id)copyWithZone:(NSZone *)ゾーンを実装しています。 NSOperationのどのプロパティが深くコピーされていないのだろうと心配していると思います。正しい? – ScottD

0

NSOperationのカテゴリではなく、オブジェクトが自分自身をコピーしてNSOperationQueueに追加するカテゴリの代わりに、これをより高いレベルで管理する方が簡単です。例:

+[RepeatingOperation operationBlock:(InitOperationBlock)operationBlock 
           queue:(NSOperationQueue*)queue 
          interval:(NSTimeInterval)interval]; 

ここで、InitOperationBlockは、操作が作成され構成されたブロックになります。

主な利点は、APIが混乱するのが難しいことです。たとえば、元の投稿のカテゴリでは、repeatOperationQueueの設定を忘れると、performUsingOperationQueue:は自動的に失敗します。