如何在第一次API请求完成后才发出后续API请求?

时间:2017-02-19 08:00:55

标签: asynchronous swift3 metadata alamofire image-uploading

我需要调用API来上传照片,此API会返回照片的ID。然后,我需要获取该ID并将其用作另一个API的参数。

问题是,在第一个API有机会完成(并返回ID)之前调用第二个API。可以做些什么呢?

我正在使用Alamofire 4和Swift 3。

我的代码:

 // First API - Upload file
func uploadFile(url: String, image: UIImage, callback: @escaping (JSON) -> ()) {

    let imageData = UIImagePNGRepresentation(image)

    let URL2 = try! URLRequest(url: url, method: .post, headers: header)

    Alamofire.upload(multipartFormData: { (multipartFormData) in

        multipartFormData.append(imageData!, withName: "photo", fileName: "picture.png", mimeType: "image/png")

    }, with: URL2, encodingCompletion: { (result) in
        switch result {
        case .success(let upload, _, _):
            upload.responseJSON
                {
                    response in

                    switch response.result {
                    case .success(let value):
                        let json = JSON(value)
                        callback(json)
                    case .failure(let error):
                        print(error)
                    }
            }
        case .failure(let encodingError):
            print(encodingError)
        }
    })
}

 // Second API
 func Post(url: String, parameters: [String:Any], callback: @escaping (JSON) -> ()) {

    Alamofire.request(url, method: .post, parameters: parameters.asParameters(), encoding: ArrayEncoding(), headers: header).responseData { (response) in
        switch response.result {
        case .success(let value):
            callback(json)
        case .failure(let error):
            print(error)
        }
    }
}

// Calling the First API
var uploadedImage: [String:String]!
uploadFile(url: baseUrl, image: image, callback: { (json) in
            DispatchQueue.main.async {
                    uploadedImage = ["filename": json["data"]["photo"]["filename"].stringValue, "_id": json["data"]["photo"]["_id"].stringValue]
                }
        })

// Calling the Second API
Post(url: baseUrl, parameters: uploadedImage) { (json) in
        DispatchQueue.main.async {
            self.activityIndicator.stopAnimating() 
        }
}

1 个答案:

答案 0 :(得分:0)

为了避免您描述的竞争条件,您必须能够以某种方式序列化两个呼叫。想到的解决方案是障碍,阻止呼叫或回调。由于您已经在使用异步(非阻塞)调用,因此我将重点关注最后一项。

我希望伪代码解决方案对您有所帮助。

假设1 st 调用总是在2 nd 之前执行,你会做类似的事情:

firstCall(paramsForFirstOfTwo){
  onSuccess {
    secondCall(paramsForSuccess)
  }

  onFailure {
    secondCall(paramsForFailure)
  }
}

但是,如果1 st 电话是可选,您可以这样做:

if (someCondition){
  // The above example where 1->2
} else {
  secondCall(paramsForNoFirstCall)
}

如果您必须在执行2 nd 之前执行1次 st 调用,您可以:

let n = 3; var v = 0; // assuming these are accessible from within completedCounter() 
firstCall1(...){/* after running code specific to onSuccess or onFailure call c..C..() */}
firstCall2(...){/* same as previous */}
firstCall3(...){/* same as previous */}

function completedCounter(){
  // v must be locked (synchronized) or accessed atomically! See: 
  //    http://stackoverflow.com/q/30851339/3372061 (atomics)
  //    http://stackoverflow.com/q/24045895/3372061 (locks)
  lock(v){ 
    if (v < n)
      v += 1
    else 
      secondCall(paramsBasedOnResultsOfFirstCalls);
  }

}