1

I have a background thread that runs and modifies the contents of a NSMutableArray within an object. This takes a long time to run (several hours) and I periodically want to draw the contents of an array within the drawRect of a NSView to check on progress and see the intermediate results.

My object has a protocol with a method called: didChange:

// How I start my background thread
[self performSelectorInBackground:@selector(startProcessing) withObject:nil];

- (void)startProcessing {
    myObject.delegate = self;
    [myObject start];
}

// My protocol implementation
- (void)myObjectDidChange:(myObjectClass *)sender {
    [myView setNeedsDisplay:YES];
}

// My View's drawRect (pseudo code)
- (void)drawRect {
    [myObject drawInContext:context];
}

All works, except that the NSMutableArray backing all this is being changed whilst the drawing takes place. How should I do this? Do I somehow pause the processing in the background thread whilst the update is taking place?

EDIT: This is the sort of display I am drawing (although much more complicated):

enter image description here

Any help appreciated.

Magic Bullet Dave
  • 9,006
  • 10
  • 51
  • 81
  • If it's an array then using a tableview sounds like the right choice. – trojanfoe May 06 '15 at 06:37
  • I am drawing a matrix of nodes with connections. So I need to draw what it represents, not just show a list. – Magic Bullet Dave May 06 '15 at 06:39
  • I'll add a picture to give you an idea of what I am drawing. – Magic Bullet Dave May 06 '15 at 06:41
  • 1
    How big is the array? Can you return an immutable copy when it's requested to avoid mutation issues? – Wain May 06 '15 at 06:46
  • 1
    Have you tried making the array `atomic`? That way you will get either the array before the other thread is changing something in it or after, but it will be definitely a viable object to use... @bbum has a great explanation for it: http://stackoverflow.com/a/589392/2242359 – Aviel Gross May 06 '15 at 06:51
  • Thanks Aviel, I will give that a go. My structure is an array of arrays and only the top level array is atomic, which might be where it falls over. – Magic Bullet Dave May 06 '15 at 06:54
  • There's no such thing (built-in) as an "atomic" array. A property can be atomic, and it might be of type `NSArray*` or `NSMutableArray*`, but that doesn't make the array atomic nor safe to access from multiple threads if any of those threads may be mutating it. – Ken Thomases May 06 '15 at 19:56
  • I second Wain's suggestion of making an immutable copy of the array. The background thread would create it (so there'd be no need for synchronization) and pass it into your delegate method. Or, if you prefer to only create it on demand, you would synchronize but only as long as necessary to make the copy. – Ken Thomases May 06 '15 at 20:01

2 Answers2

0

If you are doing something in background thread and you want to update UI, its usually done on the main thread, so in your object did change you would do it, probably like this:

// My protocol implementation
- (void)myObjectDidChange:(myObjectClass *)sender {
     dispatch_async(dispatch_get_main_queue(), ^{
      [self drawRect];  //Or any drawing function you are trying to do
  }); 
}
Qazi
  • 381
  • 2
  • 8
0

I have done it using NSLock to lock the outer loop of the start and the drawInContext methods. I am still not sure if this is the best approach and will not accept this answer for a few days in case there is a better answer out there.

- (void)start {
   for(int i=0; i < MAX; i++) {
      [self.updateLock lock];
      ....
      [self.updateLock unlock];
   }
}

- (void)drawInContext:(CGContextRef)context {
   [self.updateLock lock];
   ...
   [self.updateLock unlock];
}
Magic Bullet Dave
  • 9,006
  • 10
  • 51
  • 81
  • You don't appear to be using the "condition" part of the condition lock. So, you could just use `NSLock`. There are also other synchronization primitives like `@synchronized` or serial dispatch queues. `@synchronized` is probably simplest, least error-prone, and most efficient for this particular use case. – Ken Thomases May 06 '15 at 19:59
  • Thanks Ken, replaced with NSLock and edited the answer. – Magic Bullet Dave May 11 '15 at 06:50