Realm.io: Are write / read operations executed on the main thread? - ios

I am curious if read / write operations like this are executed on the main thread:
try! realm.write {
realm.add(myDog)
}
This is important because I want to run operations directly after something has been read or written to realm.

Block is executed on the same thread as the thread that calls the write() method synchronously. In different words, if you call write() on the main thread, the block will be executed on the main thread.
dispatch_async(dispatch_queue_create("background", nil)) {
// Some operations in a background thread ...
try! realm.write {
// this block will be executed on the background thread
}
}
If you'd like to execute the write operation on the main thread, you may need to dispatch to the main thread as needed.
dispatch_async(dispatch_queue_create("background", nil)) {
// Some operations in a background thread ...
dispatch_async(dispatch_get_main_queue()) {
try! realm.write {
// this block will be executed on the main thread
}
}
}

Related

dispatch sync vs dispatch async in main queue ios related query

so what I understood from basics is:
the async task will not block the current queue, sync task will block the current queue until that task finishes.
but when I run code on the main queue, just to print number from 1 to 100, it is giving me the same output.
use case -1
DispatchQueue.global(qos: .default).async {
DispatchQueue.main.async {
for i in 0...100{
print(i)
sleep(arc4random() % 5)
}
}
}
==============
use case -2
DispatchQueue.global(qos: .default).async {
DispatchQueue.main.sync {
for i in 0...100{
print(i)
sleep(arc4random() % 5)
}
}
what can be the reason for getting the same output for async vs sync on the main queue?
Is it because the serial queue will have only one thread associated with it?
When you, a queue, say DispatchQueue.main.sync or DispatchQueue.main.async, that does not affect how the main queue behaves; it affects how you behave, ie whether you wait before doing what comes after the call. But you have nothing after the call so there is no distinction to draw. Your “test” does not test anything.

NSAsynchronousFetchRequest - should update be explicitly done on main thread

I am creating an NSAsynchronousFetchRequest which has a completion block inside it.
I have seen various examples where some include using dispatch queue on the main thread and others don't. For example the Ray Wenderlich core data book doesn't call the result on the main thread.
Should I go back on the main thread when executing the result. Initially I thought I had to but now I don't. Some definitive clarity would be great.
fun exampleFetch(_ completionHandler: #escaping () -> () {
let fetchRequest = NSFetchRequest<NSDictionary>(entityName: "Example")
let asyncFetchRequest = NSAsynchronousFetchRequest<NSDictionary>(fetchRequest: fetchRequest) { result in
// DispatchQueue.main.async { // is this needed
completion()
//}
}
managedContext.performChanges {
do {
try self.managedContext.execute(asyncFetchRequest)
} catch let error {
print("error trying to fetch saving objects:", error.localizedDescription)
}
}
}
You should not explicitly call the completion handler on the main queue. Let the caller decide how to handle it. If anything, document that the completion handler will be called on an arbitrary queue. Then the client calling your exampleFetch method knows that it is their responsibility to be sure that process the result on whatever queue it needs.
This gives the client more control.
This also prevents a lot of needless thread switching. A client may call exampleFetch from a background queue and it may want to process the results in the background. If you explicitly put the completion on the main queue, the client then needs to explicitly switch back to a background queue to process the result. That's two needless queue switches and it's wasted effort on the main queue.

Synchronization of multiple tasks on single thread

How can I prevent a block of code to be repeatedly accessed from the same thread?
Suppose, I have the next code:
func sendAnalytics() {
// some synchronous work
asyncTask() { _ in
completion()
}
}
I want to prevent any thread from accessing "// some synchronous work", before completion was called.
objc_sync_enter(self)
objc_sync_exit(self)
seem to only prevent accessing this code from multiple threads and don't save me from accessing this code from the single thread. Is there a way to do this correctly, without using custom solutions?
My repeatedly accessing, I mean calling this sendAnalytics from one thread multiple times. Suppose, I have a for, like this:
for i in 0...10 {
sendAnalytics()
}
Every next call won't be waiting for completion inside sendAnalytics get called (obvious). Is there a way to make the next calls wait, before completion fires? Or the whole way of thinking is wrong and I have to solve this problem higher, at the for body?
You can use a DispatchSemaphore to ensure that one call completes before the next can start
let semaphore = DispatchSemaphore(value:1)
func sendAnalytics() {
self.semaphore.wait()
// some synchronous work
asyncTask() { _ in
completion()
self.semaphore.signal()
}
}
The second call to sendAnalytics will block until the first asyncTask is complete. You should be careful not to block the main queue as that will cause your app to become non-responsive. It is probably safer to dispatch the sendAnalytics call onto its own serial dispatch queue to eliminate this risk:
let semaphore = DispatchSemaphore(value:1)
let analyticsQueue = DispatchQueue(label:"analyticsQueue")
func sendAnalytics() {
analyticsQueue.async {
self.semaphore.wait()
// some synchronous work
asyncTask() { _ in
completion()
self.semaphore.signal()
}
}
}

Why Quality of service set to background runs in main thread?

Why is the below code running in main thread although i have specified qos to background thread?
func testQueue(){
let queue = DispatchQueue(label: "com.appcoda.myqueue",qos:.background)
queue.sync {
if Thread.isMainThread{
print("is in main thread")
}else{
print("is i background thread")
}
for i in 100..<110 {
print("Ⓜ️", i)
}
}
}
testQueue()
Whenever i try to run the method i get msg in console as is in main threadwhich should not be the case..I am reading in this article.
http://www.appcoda.com/grand-central-dispatch/
See the Getting Started with dispatch queues section.
You have specified a background queue, not a background thread. When you dispatch a task on a queue, GCD looks for a thread to run the task on.
Since you are using a synchronous dispatch, the main queue is blocked, leaving the main thread free to perform work, so your task executes on the main thread.
tasks dispatched on the main queue will run on the main thread
tasks dispatched on another queue may run on the main thread or another thread
Here is the Solution :-
Default for main thread is always sync, so no matter what queue you have created with what properties, it will always run in main thread when it is declared as sync.
Refer this Image
Second thing Main thread can run in async as well and it will guarantees that this new task will execute sometime after the current method finishes.
Third thing is when you will try the same code with async then it will work fine.
Refer this image
See the following code and figure it out :-
func testQueue(){
let queue = DispatchQueue(label: "com.appcoda.myqueue",qos:.background, attributes:DispatchQueue.Attributes.concurrent)
queue.sync { //Sync will always create main thread
if Thread.isMainThread{
print("is in main thread")
}else{
print("is i background thread")
}
}
DispatchQueue.main.async { //Main thread can be async
if Thread.isMainThread{
print("is in main thread")
}else{
print("is i background thread")
}
}
if Thread.isMainThread { //default is Main thread sync
for i in 100..<110 {
print("Ⓜ️", i)
}
}
else{
print("is i background thread")
}
queue.async { //Here your custom async thread will work
if Thread.isMainThread{
print("is in main thread")
}else{
print("is i background thread")
}
}
}
testQueue()

Why is my NSOperationQueue running on main thread?

I have set up an operation queue:
func initialiseOperationQueue(){
self.operationQueue = NSOperationQueue()
self.operationQueue.name = "General queue"
self.operationQueue.maxConcurrentOperationCount = 2
}
Then I added an operation to my queue
let op = HPSyncDataOperation(type: HPSyncDataOperationType.OnlineRecord, delegate: self, date: self.latestLastUpdateAt)
self.operationQueue.addOperation(op)
It is basically using Parse framework to asynchronously download some record data online. Its implementation looks like the following:
PFCloud.callFunctionInBackground("recordPosts", withParameters: param, block: { (objects:AnyObject!, error:NSError!) -> Void in
if error == nil {
let dataObjects = objects as [PFObject]
//TROUBLE HERE:
for object in dataObjects {
object.pinWithName("Received Posts")
}
//abcdefg
}
})
But in execution, when object.pinWithName("Received Posts") is run, it invokes
Warning: A long-running operation is being executed on the main thread.
Should an operation be run on a separate thread? So pinWithName, regardless of its sync or async, should be run on a separate thread as well?
Please help! Why is this?
Your operation will be run on a background thread, but all it's doing is starting another asynchronous process (PFCloud.callFunctionInBackground) which will start another thread. When that other process is complete it calls the completion block on the main thread.
So, in this case your operation and queue are doing basically nothing, and really you should be taking the result of the call to PFCloud.callFunctionInBackground (i.e. objects) and processing that on a background thread if it's likely to be time consuming.

Resources