I have an iPad app that receives data using UDP sockets. And it has a UIWebView to browse webpages.
But while doing scroll in the UIWebView, everything freezes and no data is received.
I've been searching and it has something to do with runloops and threads. But if the UIWebView can't run in another thread other than the main one, how can I receive data while doing scroll? It is critical to keep receiving data.
The project uses the AsyncUdpSocket class from Cocoa AsyncSocket that works quite well. And also the singleton class from Matt Gallagher. Everything is running in the main thread, UDP reception and UI.
Thanks in advance!
When you do a scroll, the runloop enters a different mode (UITrackingRunLoopMode) and stops responding to network activity on the main thread. This is done for performance reasons.
You should be able to schedule those updates on the proper runloop mode (UITrackingRunLoopMode I believe). Though, I wouldn't recommend this.
Instead, try setting up your UDP networking code on another thread (or queue, yay GCD!) and schedule callbacks on the main thread to update the UI. This will guarantee the networking thread has the proper runloop mode when getting data back on the socket.
Related
I'm using GPUImageFilter in a chain, and most of the time it works OK. I've recently come across a few random crashes that match the symptoms in this github issue (albeit I'm using GPUImageFilter not live capture or video). I'm trying to find a suitable method that can ensure I've cleared the frame buffer and any other GPUImage-related activities in willResignActive.
Currently I have:
[[GPUImageContext sharedFramebufferCache] purgeAllUnassignedFramebuffers];
Is this sufficient? Should I use something else instead/in addition to?
As indicated there, seeing gpus_ReturnNotPermittedKillClient in a stack trace almost always is due to OpenGL ES operations being performed while your application is in the background or is just about to go to the background.
To deal with this, you need to guarantee that all GPUImage-related work is finished before your application heads to the background. You'll want to listen for delegate notifications that your application is heading to the background, and make sure all processing is complete before that delegate callback exits. The suggestion there by henryl is one way to ensure this. Add the following near the end of your delegate callback:
runSynchronouslyOnVideoProcessingQueue(^{
// Do some operation
});
What that will do is inject a synchronous block into the video processing pipeline (which runs on a background queue). Your delegate callback will block the main thread at that point until this block has a chance to execute, guaranteeing that all processing blocks before it have finished. That will make sure all pending operations are done (assuming you don't add new ones) before your application heads to the background.
There is a slight chance of this introducing a deadlock in your application, but I don't think any of my code in the processing pipeline calls back into the main queue. You might want to watch out for that, because if I do still have something in there that does that, this will lock your application. That internal code would need to be fixed if so.
I have an app where the network activity is done in its separate thread (and the network thread continuously gets data from the server and updates the display - the display calls are made back on the main thread). When the user logs out, the main thread calls a disconnect method on the network thread as follows:
[self performSelector:#selector(disconnectWithErrorOnNetworkThread:) onThread:nThread withObject:e waitUntilDone:YES];
This selector gets called most of the time and everything works fine. However, there are times (maybe 2 out of ten times) that this call never returns (in other words the selector never gets executed) and the thread and the app just hang. Anyone know why performSelector is behaving erratically?
Please note that I need to wait until the call gets executed, that's why waitUntilDone is YES, so changing that to NO is not an option for me. Also the network thread has its run loop running (I explicitly start it when the thread is created).
Please also note that due to the continuous nature of the data transfer, I need to explicitly use NSThreads and not GCD or Operations queues.
That'll hang if:
it is attempting to perform a selector on the same thread the method was called from
the call to perform the selector is to a thread from which a synchronous call was made that triggered the perform selector
When your program is hung, have a look at the backtraces of all threads.
Note that when implementing any kind of networking concurrency, it is generally really bad to have synchronous calls from the networking code into the UI layers or onto other threads. The networking thread needs to be very responsive and, thus, just like blocking the main thread is bad, anything that can block the networking thread is a bad, too.
Note also that some APIs with callbacks don't necessarily guarantee which thread the callback will be delivered on. This can lead to intermittent lockups, as described.
Finally, don't do any active polling. Your networking thread should be fully quiescent unless some event arrives. Any kind of looped polling is bad for battery life and responsiveness.
As my first Mac application, I'm building an app that displays incoming MIDI timecode.
Therefore, I am having an instance of the RtMidi "library" which wraps the MIDI in and out stuff.
The Mac OS Core MIDI callback is in blank C and is called on multiple threads internally. The RtMidi stuff in in C++ and forwards this multi-threaded call to one single (the main) thread.
As I need a Cocoa function to notify other classes that a new MIDI timecode has arrived ( which happens about every 7-9 ms ), I implemented a Singleton which all necessary classes observe.
So, the order in which the functions are called is :
Core MIDI callback -> RtMidi function -> user callback -> Notification ( via Singleton )
Basically, this works!
The problem is that I right now have everything on the same thread ( the main thread). If I post a notification from the MIDI callback and the called functions take longer to complete than the above mentioned 7-9 ms, the Core MIDI callback gets blocked which causes the whole application to freeze.
I tried debugging and it seems that there is some kind of deadlock occurring.
Anyone has some directions on how to implement multithreading in this case?
As I also do UI updating in the notification observers, I would need all notifications to appear on the main thread. What I don't understand is how everything goes with C / C++ / Objective-C in this particular case.
I would suggest that at the stage that you forward your call from your background thread to the main thread that you do so in a non-blocking manner, if possible. For example, you could use performSelectorOnMainThread:withObject:waitUntilDone:, passing NO for the last argument, or some other mechanism like dispatch_async(dispatch_get_main_queue(), ^{ ... }). This will prevent your background thread from getting blocked, and allow the UI to be updated whenever it has time to do so.
I want to send data to my web server while the app is closed. Is that possible? I've read I can send the position, but I waant to send some id of the phone too.
If it's not possible to have the app running, could I at least communicate with it from my server and then do stuff in the background?
Thanks
When the app goes into the background the applicationDidEnterBackground method on your App Delegate will get called.
In that method you can use the beginBackgroundTaskWithExpirationHandler on UIApplication object to start background processing.
Just realise that you don't get forever to perform tasks in the background. You can find out how long you have left by reading the backgroundTimeRemaining property in UIApplication if you need to know if you're running out of time.
If your processing is short you should be fine, but remember if your processing requires network access then you can't be sure how long that will take.
When my application loads, using the didFinishLaunchingWithOptionsi parse data from the internet to nsarrays. My question is, when the user exists the application by using the 'home' button, and then loads the application again how can the data be re-loaded? (because if the data does not reload - if there are any updates on websites, the new updates will not be seen).
Add an applicationWillEnterForeground method to your app delegate. Load the data there, or start a thread to load it if you like.
You should probably also periodically check for new data even while the app remains open, because the user could go idle for a long time.
As an aside, you shouldn't do anything which might block in applicationDidFinishLaunchingWithOptions. If you are using synchronous NSURLConnection APIs there is a danger the OS might kill your app for taking too long to launch. Best to either use the asynchronous/NSURLConnectionDelegate APIs or do the networking on a background thread and call back to the main thread when you need to update UI (UIKit does NOT like being called from background threads, as it is not thread safe. It might appear to work sometimes, but it will come back to bite you sooner or later).