2016-10-06 8 views
1

다른 비트의 코드를 실행하기 전에 업로드를 완료하고 응답을 얻으려는 요청을 보내는 작업을 기다리는 방법을 알고 싶습니다. 나는 NSOperations이 작업을 수행하려고 시도했습니다다음 작업을 실행하기 전에 요청이 완료되기를 기다리는 중

let testOp = BlockOperation { 
     var result = 0 

     for i in 1...1000000000 { 
      result += i 
     } 
    } 

    let logOp = BlockOperation { 
     self.debug.log(tag: "test", content: "testing") 
    } 

    logOp.completionBlock = { 
     print("------- logOp completed") 
    } 

    logOp.addDependency(testOp) 

    let sendOp = BlockOperation { 
     self.debug.sendLog() //uploads log, using URLSession.shared.dataTask 
    } 

    sendOp.completionBlock = { 
     print("------- sendOp completed") 
    } 

    sendOp.addDependency(logOp) 

    let emptyOp = BlockOperation { 
     self.debug.empty() 
    } 

    emptyOp.completionBlock = { 
     print("------- emptyOp completed") 
    } 

    emptyOp.addDependency(sendOp) 

    let queue = OperationQueue() 
    queue.addOperations([testOp, logOp, sendOp, emptyOp], waitUntilFinished: false) 

출력 : 나는 수 출력을 예상 내 코드를 기반으로

------- logOp completed 
*** Sending debug log (coming from self.debug.sendLog()) 
------- sendOp completed 
------- emptyOp completed 
*** sendLog uploaded (coming from self.debug.sendLog()) 

:

------- logOp completed 
*** Sending debug log 
*** sendLog uploaded 
------- sendOp completed 
------- emptyOp completed 

가 어떻게 그렇게해야합니까 ? NSOperations에서이 작업을 수행 할 수 있습니까? debug.sendLog() 함수에 대한

추가 세부 사항 :

func sendLog() { 
    ... 
    var urlRequest = URLRequest(url: url!) 
    urlRequest.httpMethod = "POST" 
    ... 

    let session = URLSession.shared 
    let task = session.dataTask(with: urlRequest, completionHandler: { 
     (data, response, error) in 

     ... 

     DispatchQueue.main.async { 
      print("*** sendLog uploaded") 

     } 
    }) 

    task.resume() 
} 
+0

"내 코드를 기반으로 내가 될 수있는 출력을 예상 ...". 분명히 말하면, 그 기대는 잘못되었습니다. 'print ("*** sendLog uploaded")'는 * 메인 큐 *에서 비동기 적으로 실행되는 반면 NSOperationQueue는 디폴트로 글로벌 동시 디폴트 (우선 순위) 디스패치 큐 *로 실행됩니다. – makadev

+0

'DispatchQueue.main.async' 블록을 완전히 제거하도록 코드를 조정했습니다. 이것은 결과를 바꾸는 것처럼 보이지 않습니다. 세마포어를 사용하여 요청을 대기 상태로 만들 수 있었지만이 경우에는 해킹이 느껴집니다. 나는 어떻게 NSoperations가 유용한지 보지 않는다. 물론 상태를 확인할 수 있고 모든 작업을 쉽게 취소 할 수 있습니다. 코드를 잘 구조화했다면 취소해야 할 트랙까지 멀리 떨어져서는 안됩니다. – toast

+1

사실, 또 다른 문제점은 dataTask가 이미'task.resume()'과 비동기 적으로 실행된다는 것입니다. 언급 한대로 비동기 "콜백"/ "미래"/ "약속"또는 단순성 - [동기 요청] (http://stackoverflow.com/a/34308158/3828957)을 처리 할 수있는 또 다른 개념이 필요할 수 있습니다. * 또는 다른 메커니즘 *. 세마포어 변종은 hackish로 보일 수도 있고 느낄 수도 있지만, 짧고 유지 보수가 쉬운 해결책이며, 과도하게 사용하지 않고 주 큐를 막지 않도록주의해야합니다. – makadev

답변

2

당신은 바로 sendLog 방법에 완료 블록을 추가하고 모든 블록 작업 물건을 도랑 수 있습니다.

func sendLog(withCompletion completion: (() -> Void)) { 
    ... 
    var urlRequest = URLRequest(url: url!) 
    urlRequest.httpMethod = "POST" 
    ... 

    let session = URLSession.shared 
    let task = session.dataTask(with: urlRequest, completionHandler: { 
     (data, response, error) in 

     ... 
     completion?() 
    }) 

    task.resume() 
} 

은 다음과 같이 당신의 sendLog 메소드를 호출

sendLog(withCompletion: { 
    // Execute the code you want to happen on completion here. 
}) 
관련 문제