2017-02-19 56 views
0

Мне нужно вызвать API для загрузки фотографии, этот API возвращает идентификатор фотографии. Затем мне нужно получить этот идентификатор и использовать его в качестве параметра для другого API.Как выпустить следующий запрос API только после первого?

Проблема в том, что второй API вызывается до того, как первый 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() 
     } 
} 
+0

Как правило, способ избежать параллелизма в таких случаях ставит вызов 2 API в «обратный вызов успеха» 1-го (это означает, что 1-й должен быть завершен к тому времени). –

+0

@ Dev-iL Вы правы. но в моем случае иногда нет изображения для загрузки, поэтому мне нужно сразу перейти к второму API. – NST

+0

Затем либо сделайте некоторое 'if' /' else', чтобы пропустить 1-й запрос, либо, возможно, вызовите 1-й с некоторыми нулевыми параметрами, которые либо сбой, либо прерыв сразу, а затем по-прежнему вызовут 2-й в обратном вызове .... –

ответ

0

Для того, чтобы избежать состояния гонки, что вы описываете, вы должны быть в состоянии сериализовать два звонка как-то. Решения, которые приходят на ум, - это либо барьеры, либо блокирующие вызовы, либо обратные вызовы. Поскольку вы уже используете асинхронные (неблокирующие) вызовы, я сосредоточусь на последнем элементе.

Я надеюсь, что решение псевдокода будет полезно для вас.

Предполагая 1 й вызова является всегда выполняется до 2 я, вы могли бы сделать что-то вроде:

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

    onFailure { 
    secondCall(paramsForFailure) 
    } 
} 

Однако, если 1 улицы вызова опционально, вы можете сделать:

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

Если вы должны p erform 1 ST позвонить в определенное количество раз до того, как выполняется 2 й, вы можете:

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); 
    } 

}  
+0

@Dev_iL Спасибо за ваши усилия. Все еще есть проблема, потому что перед вторым API загружаются четыре необязательные фотографии. Я думаю, что этот подход не подходит для моего случая – NST

+0

@ user3316585 Как я должен был знать это? В любом случае у вас может быть счетчик неудачных/успешных запросов и каждый обратный вызов вызывает метод, который либо увеличивает счетчик, либо достигнет целевого значения - выдаст второй вызов. –

+0

Спасибо. Это полезно – NST