I have a common objective-c pattern / practice of a question regarding a problem that I am trying to solve with my application. I could not find a similar objective-c focused question / answer here, though.
My application contains a mutable array of objects, which I call Records. An application collects records and places them in this array in one of two ways:
- It reads data from a SQLite database, available locally in the application window. Reading usually happens very quickly.
- It requests data asynchronously from the web service, waits for completion, then analyzes the data. Reading can be quick, but often it is not.
Sometimes an application reads from a database (1) and requests data from a web service (2) almost at the same time. It often happens that (1) ends before (2) ends and adding entries to the mutable array does not lead to a conflict.
I'm worried that at some point, my SQLite reading process will take a little longer than expected, and it will try to add objects to the mutable array at the same time that the async query completes and does the same; or vice versa. These are edge cases that are difficult to verify, but this will most likely lead to a crash in my application or at least cause problems with my array of records.
I should also indicate that the entries should be concatenated into a mutable array. For example: if (1) starts first and returns 10 records, then soon after (2) finishes and returns 5 records, my modified array will contain all 15 records. I combine data, not rewrite it.
What I want to know:
- Is it safe for me to add objects to the same instance of a mutable array when processes (1) or (2) end?
- Is there a good template / practice for this kind of processing in objective-c?
- Does this include blocking access to the mutable array, so when (1) adds objects to it (2), you cannot add any objects until (1) is done with it?
I appreciate any information you could share.
[EDIT # 1]
For posterity, I found this URL to help you understand how to use NSOperations and NSOperationQueue. It is a bit outdated, but it works nonetheless:
http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
In addition, he does not speak specifically about the problem that I am trying to solve, but the example that he uses is practical and understandable.
[EDIT # 2]
I decided to go with the approach suggested by danh, where I will read locally and hit my web service as needed after completing the local reading (which should be fast anyway). Taht said: I'm going to try to avoid synchronization problems at all. What for? Because Apple says so:
http://developer.apple.com/library/IOS/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW8
Avoid syncing everything
For any new projects you are working on, and even for existing projects, creating your code and data structures to avoid the need for synchronization is the best solution. Although locks and other synchronization tools are useful, they affect the performance of any application. And if the overall design causes a high conflict between specific resources, your threads can wait even longer.
The best way to implement concurrency is to reduce the interaction and interdependencies between your parallel tasks. If each task works with its own personal data set, it does not need to protect this data with locks. Even in situations where two tasks share a common data set, you can look at ways to separate this set or provide each task with its own copy. Of course, copying datasets also has its costs, so before you make a decision, you will have to weigh these costs for synchronization costs.