In development, we often use multithreading. When you use multithreading to access the same data, you may accidentally crash. As follows:
Workaround:
1. Add lock
= Since this object's properties are non-thread-safe, the lock makes it thread safe. You can customize a lock for each object, or you can directly use the attribute indicator atomic supported in OC:
@property (atomic) Nsarray *arr;
This will not worry about multi-threaded simultaneous reading and writing problems. However, the large-scale use of locks in the app will likely lead to unpredictable problems, lock competition, priority reversal, deadlock, etc., will make the entire app complexity, the problem is difficult to troubleshoot, not a good solution.
2. Split Thread Cache
Another scenario is that a thread creates a cache, and each thread reads and writes only the cache corresponding to that thread, so there is no thread-safety issue. CoreData and Realm are doing this, but there are two drawbacks to this scenario:
A. The consumer needs to know which thread the current code is executing on.
B. Cache data for multiple line thread needs to be synchronized.
CoreData in different threads to create their own nsmanagedobjectcontext, this context maintains its own cache, if a thread does not create nsmanagedobjectcontext, to read the data need to pass Performblockandwait: The interface runs to other threads to read. If multiple context needs to synchronize the cache data, it is necessary to invoke its Merge method, or to do so by parent-children the context hierarchy. This causes it to be cumbersome to use multithreaded, with extremely low API friendliness.
Realm does a bit better, it will automatically synchronize the data when the thread Runloop begins execution, but if the threads do not have runloop, they need to manually tune Realm.refresh () synchronization. The consumer still needs to know exactly which thread the code is executing on, and avoid passing objects between threads.
3. Data is not variable
Our problem is the multi-threaded simultaneous reading and writing caused, if only read and write, there is no problem. Data immutable refers to the creation of a data object, the object's property values will no longer change, do not allow like the above example book.fav = YES directly set, if an object property value changed, then create a new object, the entire replacement of the old object directly:
Wrcache
@implementation wrcache
+ (void) Updatebookwithid: (NSString *) bookId params: (nsdictionary *) params
{
[wrdbcenter updatebookwithid:@ "10000" params:{@ "fav": @ (YES)}];//update DB data
wrbook *book = [Wrdbcenter Readbookwithid:bookid]; Re-read from DB, new object
[Self.cache setobject:book forkey:bookid]; Replace the entire object in the cache
}
@end
self.book = [Wrcache bookwithid:@ "10000"];
Book.fav = YES; Do not write
[Wrcache updatebookwithid:@ "10000" params:{@ "fav": @ (YES)}];//In the cache the entire update
Self.book = [Wrcache bookwithid:@ "10000"]; Re-reading objects
This will not be a thread security problem, once the property has been modified, the entire data is re-read from the DB, the properties of these objects are no longer write operations, and multi-threaded simultaneous reading is no problem.
However, this scheme has a flaw, that is, after the data is modified, the entire cache layer will replace the object, but then the upper layer of the old object is thrown, does not automatically update the object:
So how to get the upper layer to update the data. There are two ways of push and pull.
A. push
Push is the cache layer to update push to the upper layer, the cache to replace the entire object update, send a broadcast notification upper layer, where the granularity of the notification can be considered as required, the upper level of monitoring their own concerns notice, if found that they hold the object updated, it is necessary to update their data, But the update data here is also a very troublesome thing.
For example, reading has an idea list Wrreviewcontroller, with an array reviews, holds the idea review data object, each review in the array holds the book that this idea corresponds to, namely Review.book holds a Wrbook the data object. Then the cache layer notifies this wrreviewcontroller, a book object has a property change, then this Wrreviewcontroller how to deal with it. There are two options:
Iterate through the reviews array, and then iterate through each book object in the review, replacing the book object with updates if it is updated.
No matter what, as long as there is a notification of data updates, all the data is re-read to the cache layer, re-assemble the data, the interface is refreshed.
The first is the refinement of the practice, the advantage is not affect performance, the disadvantage is the egg pain, increased workload, but also easy to leak updates, need to know clearly what the current module holds what data, what needs to be updated. The second is the rough approach, the advantage is easy to worry, all the big brush over the line, the disadvantage is that in some complex pages need to assemble data, will have a large impact on performance.
B. Pull
Another way to pull is to refer to the upper layer at a specific time to determine whether the data is updated.
First, all data objects will have a property, temporarily named Dirty, before the cache layer updates the replacement data object, the old object's Dirty property is set to Yes, indicating that the old object has been discarded from the cache, is dirty data, need to be updated. Then the upper layer at the appropriate time to determine whether the object you hold the Dirty property is YES, if you re-fetch the latest data in the cache.
In fact, the multithreading read-write Dirty property, is a thread security problem, but because the dirty property reads infrequently, you can directly give this property read-write lock, will not like all properties locking as a result of a variety of problems, to solve the dirty property read and write thread security issues.
The main question here is what time the upper layer should be able to pull data updates. Can be in each interface display-viewwillappear or user action after checking, such as the user points like, you can trigger a check, to update the likes of the data, in these two places to do the inspection can solve 90% of the problem, the rest is the same interface linkage problems, such as the IPad The message left and right two columns two controller, to the left of the details of a collection, the list of icons on the top of the icon should also be highlighted, this situation can be done special treatment, can also be combined with the above push way to do the notice.
Push and pull two kinds of can be combined together, pull the way to make up for the push after all the data re-read the large brush caused by the performance of the problem, push to make up for the timing of the pull update, the actual use of some of the pre-established rules or frameworks together with better results.