Completion handlers in Swift 3.0

前端 未结 2 1251
终归单人心
终归单人心 2020-12-16 03:27

I am using the code below to sync data with my server. After completing the task, I would like to call:

self.refreshControl?.endRefreshing()
<
相关标签:
2条回答
  • 2020-12-16 04:04

    Swift 4:

    1. Create a completion block.

      func getDataFromJson(url: String, parameter: String, completion: @escaping (_ success: [String : AnyObject]) -> Void) {
      
          //@escaping...If a closure is passed as an argument to a function and it is invoked after the function returns, the closure is @escaping.
      
          var request = URLRequest(url: URL(string: url)!)
          request.httpMethod = "POST"
          let postString = parameter
      
          request.httpBody = postString.data(using: .utf8)
          let task = URLSession.shared.dataTask(with: request) { Data, response, error in
      
              guard let data = Data, error == nil else {  // check for fundamental networking error
      
                  print("error=\(error)")
                  return
              }
      
              if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {  // check for http errors
      
                  print("statusCode should be 200, but is \(httpStatus.statusCode)")
                  print(response!)
                  return
      
              }
      
              let responseString  = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String : AnyObject]
              completion(responseString)
      
      
      
          }
          task.resume()
      }
      
    2. Call method

      getDataFromJson(url: "http://example.com", parameter: "vehicle_type=Car", completion: { response in
              print(response)
      
          })
      
    0 讨论(0)
  • 2020-12-16 04:10

    A completion or closure is just a function wrapped up into a parameter...

    You can create a function with a closure like so...

    func doSomethingAsync(completion: () -> ()) {
    }
    

    The parameter completion is of type () -> () that is... it is a function -> that takes no input parameters () and returns void ().

    You could also make a function like...

    // (inputs) -> (outputs)
    (String) -> ()
    

    Or with any inputs or outputs you want.

    Now, like you have in your question. This function may call some other async function...

    func myAsyncFunction(completion: () -> ()) {
    
        someOtherAsyncFunction() {
    
            // This is the completion of "someOtherAsyncFunction"
    
            // Call YOUR completion here...
            completion()
        }
    
    }
    

    To make sure that YOUR completion is called AFTER the other async method is done put it inside the completion of the other method. Like above.

    Now, to call this you can do...

    self.myAsyncFunction() {
        // your completion block code here.
    }
    

    Your completion block code will now be called AFTER the other async method has finished.

    Of course, if you have several paths in the other completion (like errors etc...) then you have to call your completion at each end point...

    func myAsyncFunction(completion: () -> ()) {
    
        someOtherAsyncFunctionWithAPossibleError() {
            error in
    
            if error != nil {
                completion()
                // this return means the other completion won't be run
                return
            }
    
            completion()
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题