Calling a method on the main thread?
Solution 1
Objective-C
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomething];
});
Swift
DispatchQueue.main.async {
self.doSomething()
}
Legacy Swift
dispatch_async(dispatch_get_main_queue()) {
self.doSomething()
}
Solution 2
There's a saying in software that adding a layer of indirection will fix almost anything.
Have the doSomething method be an indirection shell that only does a performSelectorOnMainThread to call the really_doSomething method to do the actual Something work. Or, if you don't want to change your doSomething method, have the mock test unit call a doSomething_redirect_shell method to do something similar.
Solution 3
Here is a better way to do this in Swift:
runThisInMainThread { () -> Void in
// Run your code
self.doSomething()
}
func runThisInMainThread(block: dispatch_block_t) {
dispatch_async(dispatch_get_main_queue(), block)
}
Its included as a standard function in my repo, check it out: https://github.com/goktugyil/EZSwiftExtensions
Solution 4
And now in Swift 3:
DispatchQueue.main.async{
self.doSomething()
}
aryaxt
Updated on December 21, 2020Comments
-
aryaxt over 3 years
First of all I am writing code for iphone. I need to be able to call a method on the main thread without using
performSelectorOnMainThread
. The reason that I don't want to useperformSelectorOnMainThread
is that it causes problem when I am trying to create a mock for unit testing.[self performSelectorOnMainThread:@Selector(doSomething) withObject:nil];
The problem is that my mock knows how to call
doSomething
but it doesn't know how to callperformSelectorOnMainThread
.So Any solution?
-
aryaxt over 8 yearsThis is not better in any way, you created a function that does nothing but calling another one. by the way that swift syntax can be further simplified "() -> Void in" is not needed
-
Esqarrouth over 8 yearsIts more human readable/writable. Yes autocomplete adds in "() -> Void in". Is there anyway to disable this autocomplete behavior in void>void closures?
-
aryaxt over 8 yearsthe method name you have could be misleading, it sounds like the block would be executed right away on the main thread, but that's not true. dispatch_async on main queue adds the block of code to the next runloop, this important behavior is hidden behind the method that is called "runThisInMainThread
-
aryaxt over 8 yearsand I haven't found a way to configure Xcode to follow the simplified syntax :(
-
Esqarrouth over 8 yearspastebin.com/gReE6Wyr I tried it, you are correct. It not only adds the code to the next runloop, it also delays stuff after it. Why is this happening?
-
aryaxt over 8 yearsthis is the expected behavior, dispatch_async adds the code to the end of the queue. If you want it to get called right away you should do dispatch_sync instead. If you do dispatch_sync on a queue for the thread that you are already in it causes a thread lock. in your example the order of prints are "a", "c", "b". a and c are getting executed in 1 runloop because they are in the same scope. b is added to the end of the queue so it gets called sometimes later when the other existing items in the queue are completed
-
Esqarrouth over 8 yearsso what is a legit way to run something in the background without locking a thread?
-
ToolmakerSteve over 7 years@Esqarrouth - are you SURE your
dispatch_async
blocked code after the call to it? The entire point of usingasync
rather thansync
is to NOT block what follows. (Of course, theblock
of code WILL block anything else on the main thread, since the point of the asked-for code is to execute on the main thread. If you want to run background code, then you would ask for a different queue, notdispatch_get_main_queue
.) -
Felipe Balduino Cassar over 7 yearsYou just made my day with the swift 3 code. Thanks!
-
Jageen over 5 yearsIt is good practice to not use self directly into block. instead use weak reference of it.