title: NSOperation with repeat option
body: <p>I've developed a Category that gives the NSOperation the ability to be executed in the background at timed intervals. I would really appreciate getting some feedback on this, especially any potential problems with this approach that I'm not thinking of.</p>
  
  <p>Thank you!</p>
  
  <p>Here's the code:</p>
  
  <p>NSOperation+Repeat.h</p>
  
  <pre><code>#import &lt;Foundation/Foundation.h&gt;
  
  @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
  </code></pre>
  
  <p>NSOperation+Repeat.m</p>
  
  <pre><code>#import "NSOperation+repeat.h"
  #import &lt;objc/runtime.h&gt;
  
  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
  </code></pre>
  
  <p>Here's an example of a NSOperation subclass that can repeat:</p>
  
  <p>MSScheduleImportOperation.h</p>
  
  <pre><code>#import &lt;Foundation/Foundation.h&gt;
  #import "NSOperation+Repeat.h"
  
  @interface MSScheduleImportOperation : NSOperation &lt;NSCopying&gt;
  
  @property (readonly, strong, nonatomic) NSString* employeeId;
  
  - (id)initWithEmployeeId:(NSString *)employeeId;
  
  @end
  </code></pre>
  
  <p>MSScheduleImportOperation.m</p>
  
  <pre><code>#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
  </code></pre>