2016-11-12 6 views
1

요청에 오류가없는 경우 https 요청을 실행하는 데 문제가 있습니다. 메시지를받지 못했지만 명령 줄 도구 응용 프로그램이고 plist가 있습니다. http 요청을 허용하기 위해, 나는 항상 완료 블록을 보았다.Swift에서 동시 https 요청하는 방법 3

typealias escHandler = (URLResponse?, Data?) -> Void 

func getRequest(url : URL, _ handler : @escaping escHandler){  
let session = URLSession.shared 
var request = URLRequest(url:url) 
request.cachePolicy = .reloadIgnoringLocalCacheData 
request.httpMethod = "GET" 
let task = session.dataTask(with: url){ (data,response,error) in 
     handler(response,data) 
} 

task.resume() 
} 


func startOp(action : @escaping() -> Void) -> BlockOperation{ 

let exOp = BlockOperation(block: action)  
exOp.completionBlock = { 

print("Finished") 

} 
return exOp 
} 

    for sUrl in textFile.components(separatedBy: "\n"){ 
    let url = URL(string: sUrl)! 

     let queu = startOp { 
      getRequest(url: url){ response, data in 

       print("REACHED") 



      } 

     } 
     operationQueue.addOperation(queu) 
     operationQueue.waitUntilAllOperationsAreFinished() 
+0

https://github.com/ankitthakur/SwiftNetwork에서 볼 수 있습니다. swift3에서 동시 http 요청을 지원합니다. –

답변

3

하나의 문제는 당신의 작업은 단순히 요청을 시작하지만, 요청이 비동기 적으로 수행되기 때문에, 작업이 즉시 요청이 완료 될 때까지 실제로 대기, 완료된다는 점이다. 비동기 요청이 완료 될 때까지 조작을 완료하지 않으려 고합니다.

작업 대기열에서이 작업을 수행하려는 경우 NSOperation 서브 클래스를 지정해야하고 trueisAsynchronous에서 반환해야한다는 것이 트릭입니다. 그런 다음 요청을 시작하면 isExecuting을 변경하고 요청을 완료하면 isFinished을 변경하여 두 요청에 모두 필요한 KVO를 수행합니다. 이것은 모두 Concurrency Programming Guide: Defining a Custom Operation Object, 특히 Configuring Operations for Concurrent Execution 섹션에 설명되어 있습니다. 참고로이 가이드는 다소 구식입니다 (대체 된 isConcurrent 속성은 isAsynchronous이며 Objective-C 등에 초점을 맞추고 있습니다).

어쨌든, 이것은 나는이 비동기 작업의 어리 석음의 모든 캡슐화하는 데 사용하는 추상 클래스입니다 :

// AsynchronousOperation.swift 

import Foundation 

/// Asynchronous Operation base class 
/// 
/// This class performs all of the necessary KVN of `isFinished` and 
/// `isExecuting` for a concurrent `NSOperation` subclass. So, to developer 
/// a concurrent NSOperation subclass, you instead subclass this class which: 
/// 
/// - must override `main()` with the tasks that initiate the asynchronous task; 
/// 
/// - must call `completeOperation()` function when the asynchronous task is done; 
/// 
/// - optionally, periodically check `self.cancelled` status, performing any clean-up 
/// necessary and then ensuring that `completeOperation()` is called; or 
/// override `cancel` method, calling `super.cancel()` and then cleaning-up 
/// and ensuring `completeOperation()` is called. 

public class AsynchronousOperation : Operation { 

    override public var isAsynchronous: Bool { return true } 

    private let stateLock = NSLock() 

    private var _executing: Bool = false 
    override private(set) public var isExecuting: Bool { 
     get { 
      return stateLock.withCriticalScope { _executing } 
     } 
     set { 
      willChangeValue(forKey: "isExecuting") 
      stateLock.withCriticalScope { _executing = newValue } 
      didChangeValue(forKey: "isExecuting") 
     } 
    } 

    private var _finished: Bool = false 
    override private(set) public var isFinished: Bool { 
     get { 
      return stateLock.withCriticalScope { _finished } 
     } 
     set { 
      willChangeValue(forKey: "isFinished") 
      stateLock.withCriticalScope { _finished = newValue } 
      didChangeValue(forKey: "isFinished") 
     } 
    } 

    /// Complete the operation 
    /// 
    /// This will result in the appropriate KVN of isFinished and isExecuting 

    public func completeOperation() { 
     if isExecuting { 
      isExecuting = false 
     } 

     if !isFinished { 
      isFinished = true 
     } 
    } 

    override public func start() { 
     if isCancelled { 
      isFinished = true 
      return 
     } 

     isExecuting = true 

     main() 
    } 
} 

는 그리고 나는 확실히 내가 위의 상태 변경 동기화 할 NSLock이 애플 확장자를 사용

extension NSLock { 

    /// Perform closure within lock. 
    /// 
    /// An extension to `NSLock` to simplify executing critical code. 
    /// 
    /// - parameter block: The closure to be performed. 

    func withCriticalScope<T>(block:() -> T) -> T { 
     lock() 
     let value = block() 
     unlock() 
     return value 
    } 
} 

을 그런 다음,

class NetworkOperation: AsynchronousOperation { 

    let url: URL 
    let session: URLSession 
    let requestCompletionHandler: (Data?, URLResponse?, Error?) ->() 

    init(session: URLSession, url: URL, requestCompletionHandler: @escaping (Data?, URLResponse?, Error?) ->()) { 
     self.session = session 
     self.url = url 
     self.requestCompletionHandler = requestCompletionHandler 

     super.init() 
    } 

    private weak var task: URLSessionTask? 

    override func main() { 
     let task = session.dataTask(with: url) { data, response, error in 
      self.requestCompletionHandler(data, response, error) 
      self.completeOperation() 
     } 
     task.resume() 
     self.task = task 
    } 

    override func cancel() { 
     task?.cancel() 
     super.cancel() 
    } 

} 

어쨌든, 그 일을하는 데, 지금 네트워크 요청 예에 대한 작업을 만들 수 있습니다 : 나는 것을 사용하는 NetworkOperation 만들 수 있습니다 위의 예에서

let queue = OperationQueue() 
queue.name = "com.domain.app.network" 

let url = URL(string: "http://...")! 
let operation = NetworkOperation(session: URLSession.shared, url: url) { data, response, error in 
    guard let data = data, error == nil else { 
     print("\(error)") 
     return 
    } 

    let string = String(data: data, encoding: .utf8) 
    print("\(string)") 
    // do something with `data` here 
} 

let operation2 = BlockOperation { 
    print("done") 
} 

operation2.addDependency(operation) 

queue.addOperations([operation, operation2], waitUntilFinished: false) // if you're using command line app, you'd might use `true` for `waitUntilFinished`, but with standard Cocoa apps, you generally would not 

참고, 내가 추가 된 네트워크 요청이 완료 될 때까지 첫 번째 작업이 완료되지 않았 음을 보여주기 위해 첫 번째 작업에 종속적으로 만드는 무언가를 방금 인쇄 한 두 번째 작업.

분명히 원래 예제의 waitUntilAllOperationsAreFinished이나 waitUntilFinished 옵션을 addOperations으로 사용하지 않을 것입니다. 그러나 이러한 요청이 완료 될 때까지 종료하고 싶지 않은 명령 행 응용 프로그램을 다루기 때문에이 패턴을 사용할 수 있습니다. (저는 보통 waitUntilFinished의 무료 휠링 사용에 놀란 미래의 독자들을 위해 이것을 언급합니다.)

+0

다시 한번 감사드립니다, Rob, 완벽하게 일했습니다. – eduardo