Calling a method on the main thread?

85,893

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()
}
Share:
85,893
aryaxt
Author by

aryaxt

Updated on December 21, 2020

Comments

  • aryaxt
    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 use performSelectorOnMainThread 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 call performSelectorOnMainThread.

    So Any solution?

  • aryaxt
    aryaxt over 8 years
    This 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
    Esqarrouth over 8 years
    Its more human readable/writable. Yes autocomplete adds in "() -> Void in". Is there anyway to disable this autocomplete behavior in void>void closures?
  • aryaxt
    aryaxt over 8 years
    the 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
    aryaxt over 8 years
    and I haven't found a way to configure Xcode to follow the simplified syntax :(
  • Esqarrouth
    Esqarrouth over 8 years
    pastebin.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
    aryaxt over 8 years
    this 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
    Esqarrouth over 8 years
    so what is a legit way to run something in the background without locking a thread?
  • ToolmakerSteve
    ToolmakerSteve over 7 years
    @Esqarrouth - are you SURE your dispatch_async blocked code after the call to it? The entire point of using async rather than sync is to NOT block what follows. (Of course, the block 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, not dispatch_get_main_queue.)
  • Felipe Balduino Cassar
    Felipe Balduino Cassar over 7 years
    You just made my day with the swift 3 code. Thanks!
  • Jageen
    Jageen over 5 years
    It is good practice to not use self directly into block. instead use weak reference of it.