iOS XML parsing on main or background thread - objective-c

When parsing XML in Objective-C on an iOS app, when can the main thread be used and when should the parsing happen on a background thread? Can the main thread handle SAX parsing on small documents, or should all XML parsing happen in the background?

I normally do all of my data processing on a background thread. This ensures that the UI thread isn't blocked at any point in time by whatever I'm doing.

Anything that does not call into UIKit (UIView & it's subclasses) or even suggests that it might render to the screen is completely safe to do off the main thread.
I've got several apps that process XML on a background thread. I would suggest using a NSOperation that you pass the entire XML document to, allow it to process it completely or provide a series of delegate methods that notify the main thread about it's progress. If you plan on using core data, might i suggest my own NSOperation abstract class for doing background imports.
In fact you can do some rendering on a background thread, but you must pick your API's very carefully.

Related

Able to use UIKit class in a background thread

I experimented and was able to instantiate UIKit class (UIImageView in this case) in a background thread without issue. I have seen app crashes by doing things with UIKit on a background thread. Behind the scene, what causes exception when dealing with UIKit on a non-main thread? For example, if I stay completely away from dealing with the view hierarchy, is it safe?
It is not safe. There are some documented tasks that are safe to call on a background task, e.g. drawing a string into an image, accesing UIFont, pushing/popping/using current graphics context. However, mostly the behavior is undefined or documented as unsafe. You never know what shared resources the classes are using in the background (or they will in future releases). They could use shared memory pools, for example.
From my experience, in most cases you won't see a problem if the UIView is not added to any UIWindow but still it is not safe.
For example, I think that loading things from nibs (using UINib) must be done only from the main thread... and any view can load subviews from nibs.

How can I update the contents of a CALayer while the main thread is blocked?

An instance of AVCaptureVideoPreviewLayer continues to update its contents from the video capture stream even while the main thread is blocked. Is it possible to generally replicate this behaviour with a custom subclass of CALayer? In other words, given raw image data, can we update what is displayed on-screen while the main thread is blocked?
You can't update anything in the view when the main thread is blocked. The whole of UIKit is single-threaded and runs on the main event loop. Video capture is a special case because it draws directly to the screen buffer, but you won't be able to replicate it yourself.
Furthermore, if you do a long-running task on the main thread, iOS will assume your app has crashed and kill it after a few seconds anyway.
Why not perform your other task on a background thread instead? That's the standard practice.
I've found a way to update the UI on non-UI-Thread.
We can excute the code in any thread, and it actually changes the layer's transform even when the main thread is sleeping.
self.labelLayer.transform = CATransform3DMakeScale(1.2, 1.2, 1.0);
So if anyone can explain this, please feel free to concat me!

Updating NSCollectionView from another thread causes it blank

There is a NSCollectionView in my Mac application, and it contains some icons. Meanwhile, I am using NSOperationQueue as a task scheduler to queue some operations. In one NSOperation, I modify the Content of NSCollectionView, the view should update at once when Content changes.
If I update it in the main thread, then it works perfectly well. If I put the same source code at the end of the NSOperation::main(), then the NSCollectionView would be completely blank.
Is this some kind of bug or I do it in the wrong way?
Thanks!
All interaction with UI elements must be performed on the main thread.
You can use the performSelectorOnMainThread:withObject:waitUntilDone: method to help you update UI elements from background threads.

Cancelable loading in background thread

I have a window that displays some data in an NSTableView. This data is loaded in the background. The data-loading-thread is started in the windowDidLoad: method. If the window is closed before loading has finished, the background thread should be cancelled. I do this by signalling the thread in the windowWillClose: delegate method and waiting for the background thread to finish.
Now this all works perfectly. But I have one problem: How can I update the data in the table view? I have tried calling reloadData via performSelectorOnMainThread: but this leads to a race condition: The reloadData call is sometimes queued on the main thread after the window close command, and will execute after the window has closed, and everything goes up in flames.
What's the best way to control and communicate with a background thread?
Well, you know, this is exactly what makes the use of threading complex: you always face synchronization issues.
What I suggest is, instead of calling [tableView reloadData] from your thread, simply signal your controller (by calling a method controllerShouldReloadTable) and let your controller do the check if windowWillClose has been called or not. There might be a chance that your controller has been also released by the time controllerShouldReloadTable, and to fix this you will definitely need to retain the controller from the secondary thread.
On a side note, I would cancel the thread in viewDidUnload (for symmetry).
Most important: I would use asynchronous calls and a delegate class so that the whole multithreading issue is solved at its root.
EDIT: Sending asynchronously a request will not block the sending thread waiting for the response. Instead, asynchronous send (for NSURLConnection is called start) immediately returns (so, no blocking) and when the response is received, a delegate method will be called (i.e., connectionDidFinishLoading:) so that you can updated the model and the UI. Take a look at NSURLConnection docs, but as usual, I strongly suggest using [ASIHTTPRequest][2], which has many advantages.

NSOperation and UIKit problem

I am doing my download with an object which was inherited from NSOperation. I have read the documentation and when my operation finished I must call the
[self.delegate performSelectorOnMainThread:#selector(operationDidFinish:) withObject:self waitUntilDone:YES];
method. It needs to be called on the main thread, because the UIKit is not thread safe and the documentation says this in these non thread safe frameworks cases.
In the delegate method I am drawing a pdf or an image, but because it is drawn on the main thread the User Interface is very laggy until the drawing is finished.
Maybe can you suggest me a good way to avoid this problem?
I am assuming you are downloading image data, decoding it, and rendering the image. The last bit, render, has to happen on the main thread. Can you move the decode part to your download thread? For example, use CGImage calls to decode a png or jpeg, so you have a CGImageRef ready to use before calling operationDidFinish. If you can work with the PDF as images, it would be better to convert it than decode it in the main thread.