I have an app where I read data from input stream and visualize it to user. When I set up input stream, I set it up in background run loop, open it and then run a background loop. But sometimes my app breaks unexpectedly. I can't repeat this crash so I don't even know where to start to fix it.
The crash I get looks like this:
And the method where it crashes looks like this:
It says that it is Enqueued from background queue (Thread 3). And Thread 3 looks like that:
What could be the reason of this? Where should I start to fix it?
And the strange thing is that in Thread 17, where it crashes variable bg_queue is nil, and anyway it passes the if condition where i do
if (bg_queue != nil)
But in Thread 3 it is not nil:
Thread 17
Thread 3
It seems, you create a run loop from a secondary thread managed by GCD. You should not obtain a run loop from a thread that is managed by GCD!
Create your own dedicated thread or use the main thread to obtain a run loop.
If you create a second runloop, you are more courageous than I am. I would never dare doing that, because I would be just sure that it leads to problems that are too hard for me to fix. As you are finding out.
If you are sure that you are a much more clever developer than I am, then sorry, you're on your own. If you are not sure, then DON'T DO THAT! Stay away from secondary run loops!
Related
If I write accidentally UI updating code on a background thread after fetching data from network req. So Will my application get crash?
From apple docs:
Updating UI on a thread other than the main thread is a common mistake that can result in missed UI updates, visual defects, data corruptions, and crashes. source
So it can crash, but it can also not crash. It might update the UI or it might not. It might crash immediately when the code is called; it might crash in the next runloop, or it might crash minutes later. It might cause weird UI that make you say WTF. In short, its behavior is undefined. Which makes can make it a really hard bug to track down and fix.
If you are asking what is the exact behavior to expect when doing this. The answer is: in a debug environment you should expect the Main Thread Checker to catch it and cause a crash with a good crash report. If it is a production build you can expect some crashes that look like this: Application crashes very rarely with UI update on secondary thread, but they might look different. If you have a small user base you might not see any crashes, but still have a very buggy app.
Straight Answer : Your Application Won't crash.
UI Update must be done in Main thread
Apple Documentation:
DispatchQueue manages the execution of work items. Each work item
submitted to a queue is processed on a pool of threads managed by the
system.
So, use
DispatchQueue.main.async {
//your UI code
}
Why do you want to update UI in the background thread ? it's a bad practice.
You'll get something like this:
I'm running CFRunLoopRun() in Thread A. To terminate the run loop, should I come back to Thread A to call CFRunLoopStop(CFRunLoopGetCurrent())?
What happen if I call CFRunLoopStop(CFRunLoopGetCurrent()) in Thread B? If I'm in Thread B, how could I come back to Thread A to perform this call?
Sorry for this basic question. I just switched from Android to iOS and face a lot of context switch...
Thanks!
If you are using POSIX threads, then you should definitely follow the link provided in the comment by #Robotic Cat. It points to a document that describes adding a source to the CFRunLoop that can be triggered to stop the run loop.
If you are using NSThread subclasses, and you have a handle to the one you want to stop, you should be able to create a method on that NSThread subclass that stops the CFRunLoop with the code you noted above and invoke it with performSelector:onThread:withObject:waitUntilDone:.
I am writing an application that is going to send/receive data over tcp connections and I wanted to schedule the read/write to happen in the run loop of a different thread. Meaning Thread 1 is creating the connection and scheduling it on the run loop of Thread 2. I am unable to find any way of accessing the run loop of a different thread so I wrote a piece of code that the secondary thread will run which will store its run loop in a globally accessible location. I wanted to know if this is the right way to do it or if there is any other/better way to do the same and also if the way I have done it will cause problems like access to the run loop not being thread safe and causing issues if i attempt to schedule multiple things on the run loop of the same thread from multiple threads.
Something like the following.
[NSRunLoop currentRunLoop] --> This I can do from the thread whose runloop I want to access
NSRunLoop * secondthreadrunloop = [secondthread getRunLoop]; -->But is there anything like this?
I encountered the same problem recently and it seems that the answer is - no, you cannot schedule anything on a NSRunLoop running on a different thread. Apple says that NSRunLoop is not thread safe which means that attaching an NSTimer instance to it would result in an undefined behaviour (I have checked it, in my case it randomly generates crashes).
What can be done though is to schedule a repeating timer from the background thread itself and make it pick up the work you want it to do from some atomic property.
I am seeing main thread freezing for a few seconds in my app only on iOS 8 (not on previous iOS versions).
I am using #synchronised (self) at a number of places and also using RemoteIO setup. My question is how do I debug where exactly is the main thread blocking and get additional information, such as what it is doing at that time ?
I am using Xcode 6 so please tell me the best way to debug.
EDIT: Here is the output from Pause.
As a first step to understand what's happening I would suggest to simply press Pause in debugger while you're having a freeze. It will show you which thread is doing what at that point.
You will either see a task that is still executing, or msg_trap row indicating that there's a lock somewhere.
Post here what you found out.
It looks like if a background thread is running when you hit the home button, things are suspended and then resumed when reopening the app. I simply want things to stop when the home button is pressed so that on resume, the user can start things from the beginning. After doing some research, it looks like a simple bool flag to periodically check is the way to go. My question, is the part after that. I have the flag part working using some of the notifications like UIApplicationWillResignActiveNotification, but my question is what action to take to actually stop things. I can do a simple return to stop things, but how does that affect the thread itself? As a general question, if nothing is running, or it gets to the end of the code, will the thread close itself? Or is some sort of explicit exit call needed? In my rough testing, that thread seems to go away, but I wasn't sure.
If you have a thread whose entry point returns, your thread will close. If you install a runloop, your thread may never close, depending on your implementation. In any case, when an app enters background, the main thread is allowed to complete the current runloop run and then the app is suspended. All other threads are suspended also. Once your app returns to the foreground, or when woken up in the background under certain circumstances, your thread will resume work until you end the entry point, suspend it or your app is suspended again.
This is a simplification, of course. In some instances, threads are reused, even if your provided entry point returns. This is the case of thread pools, GCD, etc. In these cases, a thread may appear as alive, but it is actually suspended and takes little resources.