0

Strange issue while using NSMutableArray as a queue.

Given a singleton object SO, a ViewController object VC, and a NSMutableArray MA. MA is being used as a queue for an ID that is received by SO, and passed to VC via putting the ID in MA and sending a notification that VC handles. There is a problem with MA losing what it holds.

Steps relating to issue:

  1. Seque is initiated to load a view.
  2. SO requests an ID from a server.
  3. VC’s viewDidLoad completes
  4. SO block function receives an ID and puts it in MA, and sends a notification to VC.
  5. VC receives notification and retrieves ID from MA

The first time the view loads there is no problem. However if I go out of the view and back into it repeating the steps above the size of MA in step 4 is 1, and the size of MA in step 5 is 0. I.e. MA becomes empty!

I’m perplexed as to how MA mysteriously becomes empty between the time the notification is sent (step 4), and when the notification handler is called (step 5). I’ve checked that nothing outside of the VC notification handler is clearing the array.

A possible clue is that there is a method called (message sent in obj C parlance) from viewDidLoad that if commented out the issue described doesn’t happen. Also if I put the following line after the method in viewDidLoad (instead of commenting it out) then the issue stops occurring:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.5]];

I’ve been scratching my head on this one. My latest thought is that there is something about NSMutableArray that I don’t understand. I thought MA was storing strong references to IDs placed in it, but if it weren’t then maybe there’d be some strangeness.

Anyone have ideas?

bhartsb
  • 1,316
  • 14
  • 39
  • How are identifiers removed from mutable array? And by whom? Are you 100% sure you're dealing with the same array or is it possibly getting re-instantiated or copied somewhere along the line? (Compare the address associated with the array, itself, across these various calls.) Also, are you sure this is all happening on main thread? In other words, how are you synchronizing the non-thread-safe `NSMutableArray`? (As an aside, if I'm correct in understanding that you have one object adding items and another removing them, I'm wary of that. I'd rather see single interface that coordinates this.) – Rob Feb 05 '15 at 07:15
  • the pointe to MA is a property of the SO, and it is alloc'd and init'd in the appDelegate's didFinishLaunchingWithOptions. – bhartsb Feb 05 '15 at 07:50
  • A single ID that is received is removed with removeObjectAtIndex:0 by the VC notification handler. The pointer to MA is a property of the SO, and it is alloc'd and init'd in the appDelegate's didFinishLaunchingWithOptions. I'm not synchronizing the non-thread safe MA, but I'm only putting the ID in MA by the SO block function in step 4, sending the notification in step 4, and retrieving it in step 5 – bhartsb Feb 05 '15 at 07:57
  • correction, a reference to the ID is fetched from the array with objectAtIndex:0 then cleared from the array with removeObjectAtIndex:0 – bhartsb Feb 05 '15 at 08:04
  • Algorithm looks right, but as you have a problem with it, so implementation is wrong. Try to look at NSNotificationCenter which actually does what you want to reinvent – Mykola Denysyuk Feb 05 '15 at 08:49

1 Answers1

0

The problem was that NSNotificationCenter addObserver: was called every time VC's viewDidLoad completed(step 3). This was causing the notification handler to be called as many times as it was added, even if the notification itself was posted only one time.

The following is related: How to stop the Observer in NSNotification to called twice?

Community
  • 1
  • 1
bhartsb
  • 1,316
  • 14
  • 39