2017-02-05 7 views
1

URLSession.shared.downloadTask 요청을 수행했지만 downloadTask이 (가) 실행 된 동일한 스레드에서 코드를 실행하려고합니다. 예 :스레드 인스턴스에서 블록을 실행하는 방법은 무엇입니까?

func sample() { 
    let thread = Thread.current 

    URLSession.shared.downloadTask(with: file) { 
     someFunc() //How to execute on thread variable? 
    }.resume() 
} 

완료 핸들러는 백그라운드 스레드에서 실행됩니다. 그러나 sample()이 (가) 호출 된 동일한 스레드에서 someFunc() (으)로 전화하려고합니다. 나는 Thread.current.async {...} 같은 그래서 나는이 작업을 수행 할 수 있습니다 어떻게해야합니까 : 특정 Thread에 뭔가를 실행하려면

func sample() { 
    let thread = Thread.current 

    URLSession.shared.downloadTask(with: file) { 
     thread.async { someFunc() } //Doesn't compile 
    }.resume() 
} 

답변

1

, 차라리 그냥이 GCD API를 사용하지만,하지 않을 :

perform(#selector(someMethod), on: thread, with: nil, waitUntilDone: false, modes: [RunLoopMode.commonModes.rawValue]) 

물론 즉, 실행 루프와 스레드, 예를 만든 가정

let thread = Thread(target: self, selector: #selector(threadEntryPoint), object: nil) 
thread.start() 

func threadEntryPoint() { 
    autoreleasepool { 
     Thread.current.name = "com.domain.app.background" 
     let runLoop = RunLoop.current 
     runLoop.add(NSMachPort(), forMode: .defaultRunLoopMode) 
     runLoop.run() 
    } 
} 

자세한 내용은 Threading Programming Guide을 참조하십시오.

개인적으로 나는 개인적으로 가능하다면 개인적으로 GCD에 머무를 것이지만, 당신은 다른 곳에서 당신이 그것을 배제하는 특별한 요구 사항을 가지고 있다고 말했습니다.

+0

이것은 문제를 해결할 수 있지만 스레드는 매우 낮고 복잡합니다. 'perform' :을 통해이 특정 쓰레드에 전달 될'sample' 메소드의 호출을 수정해야합니다. 'sample'과'someFunc' 사이에 다른 쓰레드에 의해 생성 된 out-of-order 이벤트를 처리해야 할 수도 있습니다 ... 같은 방법은 선호되는 방법 인 'OperationQueue'와 같은 고급 API를 사용하여 보관할 수 있습니다. – andih

+0

나는 동의한다. 그래서 "할 수 있으면 GCD 사용"으로 마감했다. 하지만 이는 작업 대기열의 좋은 사용 사례는 아닙니다. 그리고 답을 할 때처럼 호출 스레드를 차단하는 것은 결코 좋은 생각이 아닙니다. – Rob

+0

맞습니다. 차단 접근법은 피해야합니다. 차단을 피하는 또 다른 접근법은 종속적 인 작업을 사용하는 것입니다. – andih

0

Thread.current.async와 같은 것이 없으므로 컴파일되지 않습니다.

samplesomeFunc을 같은 스레드에서 실행하려면 OperationOperationQueue을 사용할 수 있습니다. 이 방법의 단점은 하나의 스레드를 차단하고있는 사용자가 입니다.

var myQueue:OperationQueue = { 
    let q = OperationQueue() 
    q.name = "downloadQueue" 
    // if you want to limit concurrent operation 
    q.maxConcurrentOperationCount = 5 
    return q 
}() 


class DowloadOperation :Operation { 

    enum State { 
     case Ready, Executing, Finished 
     // ... 
    } 

    var state = State.Ready { 
     willSet { 
      ... 
     } 
     didSet { 
      ... 
     } 
    }  

    override func start() { 
     if self.isCancelled { 
      state = .Finished 
     } else { 
      state = .Ready 
      main() 
     } 
    } 

    override var isFinished: Bool { 
     get { 
      return state == .Finished 
     } 
    } 

    override var isAsynchronous: Bool { 
     get { 
      return true 
     } 
    } 

    override var isExecuting: Bool { 
     get { 
      return state == .Executing 
     } 
    } 


    override func main() { 
     if self.isCancelled { 
      self.state == .Finished 
      return 
     } 

     state = .Executing 

     URLSession.shared.downloadTask(with: file) { 
      // ... 
      state = .Finished 
     } 

     }.resume() 
    } 
} 

func someFunc() { 
    ... 
} 

// sample and someFunc are executed on the same thread 
// you loose the advantage of the async download. 
func sample() { 
    downloadOp = DownloadOperation() 
    myQueue.addOperation(downloadOp) 
    downloadOp.waitUntilFinished() 
    someFunc() 
} 
+0

말할 필요도없이, 비동기'Operation' 서브 클래스 (위대한 패턴)를 할 경우, 독자는 필요한 키 - 값 통지를해야한다는 것에주의해야합니다. 'willSet'과'didSet'에 줄임표가있는 곳에서 그렇게하기를 의도 했었습니다. 그러나 그것은 필수적인 세부 사항이거나 의존성 등은 단순히 작동하지 않습니다. – Rob