What happens when NSTimer kicks in - ios

I have a iOS construction where I get callbacks from an underlying class.
This callback make changes to a NSMutablearray.
At the same time I have a NSTimer that makes a callback to a method that makes changes to the same NSMutable array.
I see a potential problem here if the callbacks "collide" working with the NSMutablearray.
I am not sure how to deal with this. Could NSLock do the trick or should I instantiate my NSMutablearray as atomic?

You should make sure that any change to the mutable array occurs on the same thread. This will make sure there can be no 'collisions'. If your timer fires on the main thread, and your callback also occurs on the main thread, everything is good.
If the timer and the callback are on different threads, you can serialize the access to the array using a serial GCD-queue. When you do this, ANY AND ALL access to this array should be done on this queue (keep a reference to this queue in a property for instance).
NSLock might help you, but if you are working on the main thread, this is usually not a good idea, as you might be blocking the main queu, which affects user-interaction / scrolling behviour.
Also, atomic only means that getting or setting the pointer to the array is thread safe, i.e.: a valid value will be returned or set (dors not mean it will be the correct value though). Any operations you do on it have nothing to do with the property being atomic or nonatomox.

Related

How to make a function atomic in Swift?

I'm currently writing an iOS app in Swift, and I encountered the following problem: I have an object A. The problem is that while there is only one thread for the app (I didn't create separate threads), object A gets modified when
1) a certain NSTimer() triggers
2) a certain observeValueForKeyPath() triggers
3) a certain callback from Parse triggers.
From what I know, all the above three cases work kind of like a software interrupt. So as the code run, if NSTimer()/observeValueForKeyPath()/callback from Parse happens, current code gets interrupted and jumps to corresponding code. This is not a race condition (since just one thread), and I don't think something like this https://gist.github.com/Kaelten/7914a8128eca45f081b3 can solve this problem.
There is a specific function B called in all three cases to modify object A, so I'm thinking if I can make this function B atomic, then this problem is solved. Is there a way to do this?
You are making some incorrect assumptions. None of the things you mention interrupt the processor. 1 and 2 both operate synchronously. The timer won't fire or observeValueForKeyPath won't be called until your code finishes and your app services the event loop.
Atomic properties or other synchronization techniques are only meaningful for concurrent (multi-threaded) code. If memory serves, Atomic is only for properties, not other methods/functions.
I believe Parse uses completion blocks that are run on a background thread, in which case your #3 **is* using separate threads, even though you didn't realize that you were doing so. This is the only case in which you need to be worried about synchronization. In that case the simplest thing is to simply bracket your completion block code inside a call to dispatch_async(dispatch_get_main_queue()), which makes all the code in the dispatch_async closure run on the main, avoiding concurrency issues entirely.

Asynchronous methods called inside `-dealloc` could generate unwanted zombie objects

As I was walking through some line of codes I stumbled upon this problem a couple of days ago,
- (void)dealloc {
...
[self.postOfficeService deregister:self];
...
}
Where the de-registration from the Post Office Service is an asynchronous operation, even if it's not self evident from the interface as there's no block or function passed to the postOfficeService.
The internal implementation of postOfficeService's -deregister method is something like that
// -deregister:(id)formerSubscriber implementation
//some trivial checks here
// deregister former subscriber
dispatch_asynch(_serialQueue, ^{
[self.subcribers removeObject:formerSubscriber];
});
...
The container, self.subscribers, does perfectly its job and contains only weak references. I.e. it is a NSHashTable.
As long as the deregistration method got called within the dealloc method, I keep on getting a crash while postOfficeService is trying to remove the former subscribers from its list inside that asynch block, which is used for thread safety purposes I guess.
Adding a breakpoint on [self.subscribers removeObject:formerSubscriber], it's possible to notice that the formerSubscriber object is always a NSZombieObject. That's the reason for crashes.
I know that it's possible to get thread safety for deregister method without incurring in this problem - I figure it should be enough use the dispatch_synch in lieu of the dispatch_asynch version
I think this is one of the reason why asynchronous methods shouldn't be called within dealloc methods.
But the question is how's possible to constantly get NSZombie objects even if we are in an ARC environment and the container objects is a NSHashTable (so it should be working I guess)?
The rule is: When dealloc is called, the object will be gone once dealloc returns to its caller (whoever called release when the reference count was 0), and nothing is going to prevent this.
Before ARC, you might have tried to retain an object inside dealloc - doesn't help; once dealloc is called the object will go (and dealloc will be called only once for it, in case you do a retain / release inside dealloc). ARC does the same, just automatically.
Using ARC doesn't means all your memory problem magically disappeared.
What happened is
[obj release] called by ARC
[obj dealloc]
[obj.postOfficeService deregister:obj]
[obj retain] - sorry you can't cancel the deallocation process
dispatch_async
free(obj) - from this point, obj is a zombie
GCD scheduling tasks
dispatch_async execute task
use obj - crash
The correct solution is use dispatch_sync to make sure you not trying to use object after it is deallocated. (be careful about dead lock)
Don't call asynchronous cleanup methods from dealloc. It's just not a good idea. Your -deregister should be synchronous.
NSHashTable stores pointers - it's the equivalent of __unsafe_unretained or assign - UNLESS it was created using +weakObjectsHashTable or the equivalent set of options (NSHashTableZeroingWeakMemory and NSPointerFunctionsObjectPersonality). If it was not created that way, it is quite likely you will have values pointing to zombie objects.
The question of "why am I getting zombies" is best answered by profiling your application with the Zombies template in Instruments and stimulating the required behavior.
I agree with the others that you should probably avoid asynchronous cleanup in your -dealloc method. However, it may be possible to fix this by making the parameter to -deregister: __unsafe_unretained. That method would then have to treat the pointer purely as a opaque value. It must not dereference it or message it. Unfortunately, you don't control the implementation of NSHashTable and can't guarantee that. Even if NSHashTable could be relied upon, the interface of -removeObject: takes an implicitly strong object pointer, so ARC might retain the pointer when it's copied from the unsafe unretained pointer.
You might use the C function API for hash tables (e.g. NSHashRemove()) as suggested in the overview for the NSHashTable class.

How do I stop an NSSet from being mutated while it's being enumerated elsewhere?

I have an NSMutableSet of objects which I mutate at several points on the main thread. There are times though when this set will be enumerated on a background thread. Short of using a bunch of booleans to manage state, is there a good way to make any mutations wait, should the set currently be enumerating?
Thanks in advance.
NSMutableSet is not thread safe. You cannot hack it to be thread safe.
If you want a copy that won't mutate for inspection in the background then take a copy on the main queue and pass that back. It'll be a lot faster than any other approach.
Otherwise you'll have to wrap all accesses to it in a mutex. #synchronizeing on the set itself would be the most straightforward way.

#synchronized block versus GCD dispatch_async()

Essentially, I have a set of data in an NSDictionary, but for convenience I'm setting up some NSArrays with the data sorted and filtered in a few different ways. The data will be coming in via different threads (blocks), and I want to make sure there is only one block at a time modifying my data store.
I went through the trouble of setting up a dispatch queue this afternoon, and then randomly stumbled onto a post about #synchronized that made it seem like pretty much exactly what I want to be doing.
So what I have right now is...
// a property on my object
#property (assign) dispatch_queue_t matchSortingQueue;
// in my object init
_sortingQueue = dispatch_queue_create("com.asdf.matchSortingQueue", NULL);
// then later...
- (void)sortArrayIntoLocalStore:(NSArray*)matches
{
dispatch_async(_sortingQueue, ^{
// do stuff...
});
}
And my question is, could I just replace all of this with the following?
- (void)sortArrayIntoLocalStore:(NSArray*)matches
{
#synchronized (self) {
// do stuff...
};
}
...And what's the difference between the two anyway? What should I be considering?
Although the functional difference might not matter much to you, it's what you'd expect: if you #synchronize then the thread you're on is blocked until it can get exclusive execution. If you dispatch to a serial dispatch queue asynchronously then the calling thread can get on with other things and whatever it is you're actually doing will always occur on the same, known queue.
So they're equivalent for ensuring that a third resource is used from only one queue at a time.
Dispatching could be a better idea if, say, you had a resource that is accessed by the user interface from the main queue and you wanted to mutate it. Then your user interface code doesn't need explicitly to #synchronize, hiding the complexity of your threading scheme within the object quite naturally. Dispatching will also be a better idea if you've got a central actor that can trigger several of these changes on other different actors; that'll allow them to operate concurrently.
Synchronising is more compact and a lot easier to step debug. If what you're doing tends to be two or three lines and you'd need to dispatch it synchronously anyway then it feels like going to the effort of creating a queue isn't worth it — especially when you consider the implicit costs of creating a block and moving it over onto the heap.
In the second case you would block the calling thread until "do stuff" was done. Using queues and dispatch_async you will not block the calling thread. This would be particularly important if you call sortArrayIntoLocalStore from the UI thread.

On iOS, how to check inside a new thread for a UISwitch's value in the ViewController's view?

On iOS, if there is a single view app, and a new thread is created using:
[NSThread detachNewThreadSelector:#selector(consumeData:)
toTarget:self.consumer withObject:self.queue];
where the consumer is a Consumer object that will process data inside the method consumeData, and the queue is a Queue object, which is where the data comes from for the consumer to process.
But what if the thread needs to check whether a Switch on the main view is set to on or off? That is to toggle whether the Consumer object should do the work or pause at the moment. Should the withObject:self be used instead, so that the whole ViewController reference is passed to the thread, and then the thread will use viewController.view.______ to access the switch's value, and use viewController.queue to access the queue, or is there a better or alternative method?
Absolutely not. Nothing UI-related can ever be touched from another thread. It's simply not safe. If the other thread needs to know the switch's current value, then it needs to call back to the main thread before asking for it.
If you create a subclass, you could store your state in variables in the object, then access these variables from any thread; provided of course these operations do not call methods defined by UIKit.

Resources