2012-05-10 65 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,我猜大多數的子類都不支持。其次,你似乎不處理取消。如果一個操作被取消,那麼這個代碼將繼續產生更多的實例。第三,如果一個操作需要很長時間才能完成,這段代碼會產生更多的實例,並且你將有多個操作同時運行。 –

+0

是的,必須使用NSCopying協議定義NSOperation的子類並實現(id)copyWithZone :(NSZone *)區域。 – ScottD

+0

關於取消,我需要補充一點。我應該能夠將nil分配給定時器以使其停止重複。 – ScottD

回答

1

Apple documentation說:

的操作對象爲單次對象,也就是說,它一旦執行其任務,不能用於執行它再次。

所以第一個問題是可能有內部元件阻止它工作。雖然,我看到你試圖通過複製來解決問題。

這導致我們的另一個問題是NSOperation未被標榜爲符合NSCopying

[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:將自動失敗。