is it possible to detect disk operations on main thread? ie queries to sqlite executed on main thread. In android there is Strict mode which will crash application every time when app does disk operation on main thread but. Is there something like this in ios?
I have inherited big codebase and randomly discovered database queries executing on main thread. I would like to have some option to simply discover all. (I used instruments but something like throwing exception every time there is unallowed operation on main thread will be better)
Only possible solution which I see is to check Thread.current.isMainThread before every disk operation
Thanks
You can enable Core data concurrency debug mode which is like a Strict mode, it will throw an exception when core data entities are accessed from an incorrect thread.
You can enable it by passing the following argument when running
-com.apple.CoreData.ConcurrencyDebug 1
You can get more information and a more in-depth explanation here
Related
Why is it the responsibility of the programmer to call UI related methods on the main thread with:
DispatchQueue.main.async {}
Theoretically, couldn’t this be left up to the compiler or some other agent to determine?
The actual answer is developer inertia and grandfathering.
The Cocoa UI API is huge—nay, gigantic. It has also been in continuous development since the 1990's.
Back when I was a youth and there were no multi-core, 64-bit, anything, 99.999% of all applications ran on the main thread. Period. (The original Mac OS, pre-OS X, didn't even have threads.)
Later, a few specialized tasks could be run on background threads, but largely apps still ran on the main thread.
Fast forward to today where it's trivial to dispatch thousands of tasks for background execution and CPUs can run 30 or more current threads, it's easy to say "hey, why doesn't the compiler/API/OS handle this main-thread thing for me?" But what's nigh on impossible is re-engineering four decades of Cocoa code and apps to make that work.
There are—I'm going to say—hundreds of millions of lines of code that all assume UI calls are executing concurrently on the main thread. As others have pointed out, there is no cleaver switch or pre-processor that's going to undo all of those assumptions, fix all of those potential deadlocks, etc.
(Heck, if the compiler could figure this kind of stuff out we wouldn't even have to write multi-threaded code; you'd just let the compiler slice up your code so it runs concurrently.)
Finally, such a change just isn't worth the effort. I do Cocoa development full time and the number of times I have to deal with the "update control from a background thread problem" occurs, at most, once a week or so. There's no development cost-benefit analysis that's going to dedicate a million man-hours to solving a problem that already has a straight forward solution.
Now if you were developing a new, modern, UI API from scratch, you'd simply make the entire UI framework thread safe and whole question goes away. And maybe Apple has a brand new, redesigned-from-the-ground-up, UI framework in a lab somewhere that does that. But that's the only way I see something like this happening.
You would be substituting one kind of frustration for another.
Suppose that all UI-related methods that require invocation on the main thread did so by:
using DispatchQueue.main.async: You would be hiding asynchronous behaviour, with no obvious way to "follow up" on the result. Code like this would now fail:
label.text = "new value"
assert(label.text == "new value")
You would have thought that the property text just harmlessly assigned some value. In fact, it enqueued a work item to asynchronously execute on the main thread. In doing so, you've broken the expectation that your system has reached its desired state by the time you've completed that line.
using DispatchQueue.main.sync: You would be hiding a potential for deadlock. Synchronous code on the main queue can be very dangerous, because it's easy to unintentionally block (on the main thread) yourself waiting for such work, causing deadlock.
I think one way this could have been achieved is by having a hidden thread dedicated to UI. All UI-related APIs would switch to that thread to do their work. Though I don't know how expensive that would be (each switch to that thread is probably no faster than waiting on a lock), and I could imagine there's lots of "fun" ways that'll get you to write deadlocking code.
Only on rare instances would the UI call anything in the main thread, except for user login timeouts for security. Most UI related methods for any particular window are called within the thread that was started when the window was initialized.
I would rather manage my UI calls instead of the compiler because as a developer, I want control and do not want to rely on third party 'black boxes'.
check https://developer.apple.com/documentation/code_diagnostics/main_thread_checker
and UPDATE UI FROM MAIN THREAD ONLY!!!
Is there a way to take action, thus execute code, when an iOS application crashes? Specifically, I would like to save the core data storage. Is this possible? I would say that this is possible since, for example, Firebase has to send information online for making crashlytics work. How can this be achieved? Thanks
Yes, but it is very difficult, and "save core data storage" would be far too much (and very dangerous, to boot).
Most crashes result from a signal (often SIGSEGV, but also SIGABRT, SIGILL or others), and you can install a signal handler to run code in that case. However, that code must be very, very carefully written because you will be in a special execution state. There are a small number of C functions you are permitted to use (see the man page for sigaction for the list). Most notably, you can't allocate memory. Allocating memory in a signal catching function can deadlock the program in a tight spinlock (done that myself when I tried to write my own crash handler in my more naive days; it's really bad).
The way that crash handlers like Crashlytics do it is that they do as little as possible during the signal handler, mostly just writing the stack trace to storage (using pre-allocated buffers). When you restart, they see that there's an unhandled stack trace from a previous run, and then they do all the complicated stuff like uploading it to a server, or displaying UI, or whatever.
But even if you could write to Core Data in the middle of a signal handler, you would never want to do that. During a signal handler, the system is in an undefined state. Various invariants may not currently hold (such as whether the object graph is consistent). The fact that you're crashing this way indicates that something illegal has happened. The last thing you should do in that state is take data that is highly untrustworthy and overwrite the good data on disk.
I am developing an application in which huge amount of data has to fetched from web server and then this data has to be stored in core data.
I am using private Contexts for that like:
[privateContext performBlockAndWait:^{ //Code }];
Firstly I was calling this block from background thread by using dispatch queues. But the core data was not functioning well. Then I read the documentation and found out that this block has to be called from the main thread. And after that everything worked fine.
But now the problem is that during data storing if I press the home button and come back again to application the UI of application hangs and after sometime the application crashes with no crash log. And I cannot figure out what the problem is.
Another thing if I call this block from background thread this problem does not happen, but then the other issues starts arriving.
Can you post the complete code that is performing the block?
Are you receiving any memory warnings during the execution of the app?
Are you storing and fetching in small batches or are you fetching all your data and storing it at once?
My educated guess is the following:
performBlockAndWait is blocking the main thread. When you suspend the app and resume it again, the main thread will continue to be blocked (therefore the UI will not be updated as the main thread is in charge of UI updates). If you have large amounts of data in memory for storage AND your app is blocking the main thread, your app is being terminated due to memory usage or non responsiveness.
I don't understand why do you have problems doing this operation in a background thread, I've used it multiple times and everything worked like a charm. I've used NSOperationQueue with block and in the applicationWillResignActive I create a background task to ensure that the operation is finished up before suspending the app.
If you can provide more info.
Thanks!
beside heavy processing, should multithreading mainly be used when you have a not quite responsive UI? or does it have other considerations?
How can I know if my application should have multithreading or not?
One of the Important Application of thread in ios is during network communication.Whole your app is communication with server and if you want to show busy view on UR UI you need to create thread in such scenario to perform network communication in background thread.
In IOS 5,You can opt for GCD(Grand Central Dispatch)Instead of thread to perform same functionality..
Basically in iOS development Threads are used when you don't want to affect you UI by a process which will take long time to complete. for example when you make a connection to parse xml,json,image data etc then you don't want to stop user interaction at that time you can use threads.
you can start a thread by using NSThread.
Things to have in mind before using threads -
You should never do a graphical change in a thread. If you need to
that in a thread then you can do only on main thread.
Never use a NSTimer in a secondary thread, because your thread may
complete before timer execution so timer may not run.
whenever you want to perform a long process then you can use thread.
The use of threading in ios is to ensure hussle-free and seamless experience by the end-users.
You can implement thread whenever you want to extract some resource over the network such as parsing or data retrieval and you don't want the ui to be affected as application would run on main thread and the web-operation on your custom thread.
You may want to use the thread when you need to have concurrent operations or simultaneous such as in game when you hae to have multiple animations on same object at same time.There can be quite a large number of scenarios which may need threading.
You may read Concurrency Programming Guide By Apple
and Thread Management
but threads may be an overhead in the application as it needs memory allocation and large operations on thread may affect the performance so use it when it can't be avoided.
You can use NSThread,NSOperations to create threads .GCD is deprecated now.
The Apple "Concurrency with Core Data" documentation states the following when discussing using core data with background threads.
Saving in a Background Thread is Error-prone
Asynchronous queues and threads do not prevent an application from
quitting. (Specifically, all NSThread-based threads are “detached”—see
the documentation for pthread for complete details—and a process runs
only until all not-detached threads have exited.)
and in particular:
If you need to save on a background thread, you must write additional code such that the main thread prevents the application from quitting until all the save operation is complete.
What is the recommended approach for achieving this inside an IOS application?
In the app delegates applicationWillTerminate and related methods, you need to check if any background threads have unsaved changes and save them before allowing the app to terminate or go into the background.
I recommend taking a look at using Magical Record (https://github.com/magicalpanda/MagicalRecord/). It greatly simplifies dealing with core data on background threads. I recently found this and used it for a project. We've now undertaken a maintenance effort to update a variety of existing apps to use the new Magical Record Core Data wrapper. It has saved us tons of time and frustration in the few weeks we have been using it.