10

I have a connection in a thread, so I add it to the run loop to get all data:

  [[NSRunLoop currentRunLoop] run];
  [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

But I can't find any way to stop it

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    if([NSRunLoop currentRunLoop]){
        [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget:self];
    }
    [connection cancel];
}

How can I stop this loop?

jscs
  • 63,694
  • 13
  • 151
  • 195
Makio
  • 465
  • 6
  • 15

2 Answers2

18

You can stop the runloop by Core Fundation API :

CFRunLoopStop(CFRunLoopGetCurrent());
hrchen
  • 1,223
  • 13
  • 17
  • While I've got this to work, I'm not sure I understand how this really works? Does a Core Foundation Run Loop method terminate a NSRunloop? – absessive Oct 29 '13 at 17:51
  • `NSRunLoop` and `CFRunLoopRef` are two interfaces for the same underlying structure, @absessive (although they are not "toll-free bridged" as it's called). So `[NSRunLoop currentRunLoop]` and `CFRunLoopGetCurrent()` essentially provide you with access to the same thing, but only the CF API has a "stop" button. – jscs Sep 08 '14 at 19:24
  • Can be also written as `CFRunLoopStop(RunLoop.current.getCFRunLoop())`. – Vlad Feb 18 '23 at 18:25
0

Here is an example when RunLoop used in conjunction with a dedicated Thread.

class MyClass {
  
  private weak var cancellableThread: Thread? // Need to be `weak` as we want thread to delloc after it's job is done.
  
  // Say your UI allow user to start / stop some job.
  func handleStartStopButtonClick() {
      if let thread = cancellableThread {
         print("Will inform thread about job end.")
         thread.threadDictionary["my-status-key"] = true
      } else {
         print("Will start threаd.")
         cancellableThread = startCancellableRunLoop()
      }
  }
  
  func startCancellableRunLoop() -> Thread {
     let thread = Thread() {
        let timer = Timer(timeInterval: 2, repeats: true) { _ in
           print("Timer is fired: \(Date().timeIntervalSinceReferenceDate)")
           if let statusValue = Thread.current.threadDictionary["my-status-key"] as? Bool, statusValue == true {
              CFRunLoopStop(RunLoop.current.getCFRunLoop())
           }
        }
        let rl = RunLoop.current
        let rlMode = RunLoop.Mode.default
        rl.add(timer, forMode: rlMode)
        let status = rl.run(mode: rlMode, before: Date.distantFuture)
        print("Job is completed: status=\(status)")
     }
     thread.start()
     return thread
  }

}
Vlad
  • 6,402
  • 1
  • 60
  • 74