Schedule NSStreams on secondary thread - ipad

In an iPad app I'm developing, I need to put the network handling on a separate thread since it occasionally blocks the UI of the app. At the moment, I have created a Connection object in which all the networking logic goes (NSStreams and its delegate methods).
The main obstacle is how to create the secondary thread and schedule the NSStreams on the run loop of this thread. Do I explicitly create an NSThread that is then owned by the Connection object?
I have been experimenting with NSOperation, but this didn't seem like the best solution as I feel the need for a thread dedicated to handling networking events.
Pointers and advice are welcome. Any sample code might be helpful as well.
Bart

I like the detachNewThreadSelector... approach too, but FYI you can use NSOperation and NSOperationQueue. It'll throw non-concurrent operations onto separate threads.
To get the streams going, you're looking at this kind of thing:
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:mode];
Definitely look at the Apple sample "PictureSharing" at http://developer.apple.com/library/mac/#samplecode/PictureSharing.
In particular, copy the FileSendOperation and FileReceiveOperation classes, and the QRunLoopOperation. I also use the LinkedImageFetcher sample's QWatchedOperationQueue class, which works well with the PictureSharing classes. I took their *SendOperation and *ReceiveOperation classes and turned them into classes sending/receiving what I needed (some NSData).
Then it's as easy as:
FileSendOperation *op;
op = [[[FileSendOperation alloc] initWithFilePath:somePath outputStream:outStream ] autorelease];
[self.queue addOperation:op finishedAction:#selector(networkingDone:)];

I did just some googling, and I came up with this:
http://kdl.nobugware.com/post/2008/12/22/nsthread-iphone-template/
I think this is what you need ;)
EDIT:
http://www.xprogress.com/post-36-threading-tutorial-using-nsthread-in-iphone-sdk-objective-c/
Maybe that is usefull to...
If you read the code, you see performSelectorOnMainThread (or something) so you can send back info from thread to thread.

Related

Is there any difference between dataWithContentsOfURL (threaded) and dataTaskWithURL?

We're using dataWithContentsOfURL because it is, uh, simple...
NSData *datRaw = [NSData dataWithContentsOfURL:ur];
Now, of course, that will hang the main UI thread.
So we put it on another thread. We do that exactly thus,
-(void)performSearch:(NSString *)stuff then:(void(^)(void))after
{
dispatch_queue_t otherThread =dispatch_queue_create(nil,0);
dispatch_queue_t mainThread =dispatch_get_main_queue();
dispatch_async(otherThread,
^{
self.resultsRA = [self ... calls dataWithContentsOfURL ...];
dispatch_async(mainThread, ^{ if (after) after(); });
});
}
(Incidentally, here's an excellent introduction to that if needed https://stackoverflow.com/a/7291056/294884).
Well now, Apple says you should not use dataWithContentsOfURL, they say you should instead just use NSSession. So, dataTaskWithURL:completionHandler:
My question, is there any difference at all between making our own thread (i.e. with dataWithContentsOfURL) versus using dataTask ?
Are we wrong to use dataWithContentsOfURL: on a thread, for some reason? I appreciate it is more convenient, etc. I mean is there are real difference, any dangers, etc.
One reason to prefer true async io over threaded synchronous io is that threads are not free memory-wise. It's not a huge deal in general but you can save a little memory in your app and (more importantly) a little wired memory in the OS's kernel by not keeping a thread sitting around doing nothing while it waits.
Some of reasons I can see:
With synchronous request you can't know download progress and can't resume download. If you download big file and it fails on 99%, you will need to redownload whole file.
As Apple states "Do not use this synchronous method to request network-based URLs. For network-based URLs, this method can block the current thread for tens of seconds on a slow network...". If you are using GCD, you won't directly control the thread you are given and it may block some other important operations on that thread, dataTask scheduler may have better overview of system resources. If you create thread manually, you may overload system(if there is already resource strain at least) with this blocked thread.
Also there is "added ability to support custom authentication and cancellation" in dataTaskWithURL:.
You may need to customize request headers/body. Maybe it falls in "convenience" category, but anyway it's another thing.

How to dispatch_after in the current queue?

Now that dispatch_get_current_queue is deprecated in iOS 6, how do I use dispatch_after to execute something in the current queue?
The various links in the comments don't say "it's better not to do it." They say you can't do it. You must either pass the queue you want or dispatch to a known queue. Dispatch queues don't have the concept of "current." Blocks often feed from one queue to another (called "targeting"). By the time you're actually running, the "current" queue is not really meaningful, and relying on it can (and historically did) lead to dead-lock. dispatch_get_current_queue() was never meant for dispatching; it was a debugging method. That's why it was removed (since people treated it as if it meant something meaningful).
If you need that kind of higher-level book-keeping, use an NSOperationQueue which tracks its original queue (and has a simpler queuing model that makes "original queue" much more meaningful).
There are several approaches used in UIKit that are appropriate:
Pass the call-back dispatch_queue as a parameter (this is probably the most common approach in new APIs). See [NSURLConnection setDelegateQueue:] or addObserverForName:object:queue:usingBlock: for examples. Notice that NSURLConnection expects an NSOperationQueue, not a dispatch_queue. Higher-level APIs and all that.
Call back on whatever queue you're on and leave it up to the receiver to deal with it. This is how callbacks have traditionally worked.
Demand that there be a runloop on the calling thread, and schedule your callbacks on the calling runloop. This is how NSURLConnection historically worked before queues.
Always make your callbacks on one of the well-known queues (particularly the main queue) unless told otherwise. I don't know of anywhere that this is done in UIKit, but I've seen it commonly in app code, and is a very easy approach most of the time.
Create a queue manually and dispatch both your calling code and your dispatch_after code onto that. That way you can guarantee that both pieces of code are run from the same queue.
Having to do this is likely because the need of a hack. You can hack around this with another hack:
id block = ^foo() {
[self doSomething];
usleep(delay_in_us);
[self doSomehingOther];
}
Instead of usleep() you might consider to loop in a run loop.
I would not recommend this "approach" though. The better way is to have some method which takes a queue as parameter and a block as parameter, where the block is then executed on the specified queue.
And, by the way, there are ways during a block executes to check whether it runs on a particular queue - respectively on any of its parent queue, provided you have a reference to that queue beforehand: use functions dispatch_queue_set_specific, and dispatch_get_specific.

NSMutableDictionary - EXC BAD ACCESS - simultaneous read/write

I was hoping for some help with my app.
I have a set up where multiple threads access a shared NSMutableDictionary owned by a singleton class. The threads access the dictionary in response to downloading JSON and processing it. The singleton class is basically preventing duplication of some downloaded objects which have an unique id number.
ie.
//NSURLConnection calls:
[[Singleton sharedInstance] processJSON:data];
#interface Singleton
+ (Singleton) sharedInstance;
#property (nonatomic, strong) NSMutableDictionary *store;
#end
#implementation
-(void) processJSON:(NSData*)data {
...
someCustomClass *potentialEntry = [someCustomClass parse:data];
...
if(![self entryExists:potentialEntry.stringId])
[self addNewEntry:potentialEntry];
...
}
-(void) entryExists:(NSString*)objectId {
if(self.store[objectId])
return true;
else return false;
}
-(void) addEntry:(someCustomClass *object) {
self.store[object.stringId] = object;
}
There can be as many as 5-10 threads at a time calling processJSON at once.
Not immediately but after a few minutes of running (quicker on the iPhone than on the simulator) I get the dreaded EXC BAD ACCESS.
I don't confess to know how NSMutableDictionary works but I would guess that there's some kind of hash table in the background which needs to be updated when assigning objects and read when accessing objects. Therefore, if threads were to instantaneously read/write to a dictionary, this error could occur - may be because an object has moved in memory?
Im hoping that someone with more knowledge on the subject could enlighten me!
As for solutions I was thinking of the singleton class having an NSOperationQueue with a maximum concurrent operation number of 1 and then using operationWithBlock: whenever I want to access the NSDictionary. The only problem is that it makes calling processJSON an asynchronous function and I can't return the created object straight away; I'd have to use a block and that would be a bit messier. Is there any way of using #synchronize? Would that work well?
I'd draw your attention to the Synchronization section of the iOS rendition of the Threading Programming Guide that Hot Licks pointed you to. One of those locking mechanisms, or the use of a dedicated serial queue, can help you achieve thread safety.
Your intuition regarding the serial operation queue is promising, though frequently people will use a serial dispatch queue for this (e.g., so you can call dispatch_sync from any queue to your dictionary's serial queue), achieving both a controlled mechanism for interacting with it as well as synchronous operations. Or, even better, you can use a custom concurrent queue (not a global queue), and perform reads via dispatch_sync and perform writes via dispatch_barrier_async, achieving an efficient reader/writer scheme (as discussed in WWDC 2011 - Mastering GCD or WWDC 2012 - Asynchronous Design Patterns).
The Eliminating Lock-Based Code section of the Concurrency Programming Guide outlines some of the rationale for using a serial queue for synchronization versus the traditional locking techniques.
The Grand Central Dispatch (GCD) Reference and the dispatch queue discussion in the Concurrency Programming Guide should provide quite a bit of information.
the simplest solution is to just put all off the code that accesses the dict in an #synchronized block.
serial operation queues are great, but sounds like overkill to me for this, as you aren't guarding a whole ecosystem of data, just one structure..

#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.

Warn on calls to UIKit from background threads

iOS's UIKit is not thread-safe, let us call this fact well known. I know the rule, I'm careful, but I still get bitten - and every now and then the resulting crash is far enough removed from the offending background call into UIKit to make tracking down the problem a less than joyeus experience.
This problem seems like it could be easy to solve - have UIKit classes/methods warn when they are invoked from a background thread, at least as a debug feature. As far as I'm aware, iOS does not provide any such feature. Of course one could achieve the same effect manually by having some form of assertions precede such calls, but this solution is not the most elegant and in addition suffers from the same weakness as the original problem, namely that programmers are prone to forgetfulness.
Does anyone have a more elegant solution? How do you deal with this problem in your projects?
(Note: this question is related, but not quite as explicit. One is left wondering)
UPDATE: Andrew's answer is the solution I was looking for at the time, however note that at least as of Xcode 9 this is now provided by xcode/ios. For instance, adding this code:
DispatchQueue.global().async {
print(self.view.frame)
}
To a UIView's viewDidLoad method produces a runtime warning inline in Xcode UIView.frame must be used from the main thread only and a message printed to the console: Main Thread Checker: UI API called on a background thread: -[UIView frame]
This code (just add to project and compile this file without ARC) causes assertions on UIKit access outside of the main thread: https://gist.github.com/steipete/5664345
I've just used it to pickup numerous UIKit/main thread issues in some code I've just picked up.
I try not to introduce multi threading unless I have tried a single threaded approach first but it depends on the problem you are trying to solve.
Even when multithreading is the only option I usually avoid long running background operations or operations that that perform several unrelated tasks.
Just my opinion.
Edit
An example of doing work on the main thread whilst displaying a loading spinner:
MBProgressHUD *hud = [MBProgressHUD customProgressHUDInView:view dim:dim];
[hud show:NO];
//Queue it so the ui has time to show the loading screen before the op starts
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:block];
NSBlockOperation *finOp = [NSBlockOperation blockOperationWithBlock:^{
[MBProgressHUD hideAllHUDsForView:view animated:NO];
}];
[finOp addDependency:blockOp];
[[NSOperationQueue mainQueue] addOperations:#[blockOp, finOp] waitUntilFinished:NO];
Personally anytime I open the box to a multithreaded approach I start wrapping ALL interface based calls in performSelectorOnMainThread: so that there is never an issue. If we've already made it to the main there this call shouldn't cause any significant slow down, but if its called from a background thread I can rest easy knowing its safe.

Resources