Вложенный запрос Alamofire и очередь асинхронной отправки

Я пытаюсь реализовать вложенный запрос Alamofire: - Первый запрос вызывает код - Второй запрос вызывает результат, используя код, полученный в первом запросе.

Кроме того, я предполагаю, что есть проблема с объектом DispatchQueue, я думал использовать DispatchQueue.main.async для второго запроса, но здесь это не принято.

В строках ниже второй запрос возвращает мне нулевой результат, потому что он не включает код, найденный в первом запросе.

    func fetch(jan: String) {

 AF.request("https://shopping.yahooapis.jp/ShoppingWebService/V1/json/itemSearch?appid=\(appId)&jan=\(jan)&hits=50").responseDecodable(of: Welcome.self , queue: DispatchQueue.main) { response in 
    let boncode1 = String("\(response.value?.resultSet.the0.result.the0?.code)")     
    print(boncode1)

AF.request("https://shopping.yahooapis.jp/ShoppingWebService/V1/json/itemLookup?appid=\(self.appId)&itemcode=\(boncode1)").responseDecodable(of: troisViewController.Welcome.self , queue: DispatchQueue.main) { response in

            print("\(response.value?.resultSet.the0.result.the0?.name ?? "is nil" )")

        }
    }
}

Надеюсь, кто-то уже сталкивался с подобной проблемой,

заранее спасибо


person charlslvn    schedule 24.03.2020    source источник
comment
Параметр queue: получает объект DispatchQueue, тогда как DispatchQueue.main.async — это метод, который ничего не возвращает. Обработчик завершения всегда возвращается асинхронно, поэтому я не думаю, что вам следует беспокоиться об этом. Что вы можете сделать, так это создать собственную очередь DispatchQueue и передать ее вместо DispatchQueue.main. то есть: DispatchQueue(label: "com.your-domain.request-thread", qos: .utility)   -  person Greg de J    schedule 24.03.2020
comment
Что касается второго запроса, который возвращает nil, без запуска кода трудно сказать, связана ли проблема с вызовами, которые вы делаете в API, или на стороне Swift. Например, присвоено ли boncode1 значение, которое вы ожидаете? Вроде правильно интерполировал во 2-м запросе.   -  person Greg de J    schedule 24.03.2020


Ответы (2)


Пока вам нужно 2 служебных вызова, вложенные функции могут соответствовать вашим потребностям. Но представьте, что вам нужно обработать результат 5 или даже более сервисных обращений, это будет Пирамида Doom кошмар точно.

Чтобы избежать этого, я бы порекомендовал вам взглянуть на DispatchGroup API и узнать, как использовать Это.

Группы позволяют объединять набор задач и синхронизировать поведение в группе. Вы присоединяете несколько рабочих элементов к группе и планируете их асинхронное выполнение в одной или разных очередях. Когда все рабочие элементы завершают выполнение, группа выполняет свой обработчик завершения. Вы также можете синхронно дождаться завершения выполнения всех задач в группе.

Таким образом, вы можете реализовать свою функцию следующим образом:

func fetch(jan: String) {

    // Local variable
    var boncode1: String = ""

    // Create group
    let dispatchGroup = DispatchGroup()

    // Fetch data from the first service

    let url_1 = "https://shopping.yahooapis.jp/ShoppingWebService/V1/json/itemSearch?appid=\(appId)&jan=\(jan)&hits=50"

    // Indicate that the first block of work (first service call) has entered the group.
    dispatchGroup.enter()

    AF.request(url_1).responseDecodable(of: Welcome.self) { response in
        // Store data in local variable
        boncode1 = String("\(response.value?.resultSet.the0.result.the0?.code)")

        // Indicate that the first block in the group finished executing.
        dispatchGroup.leave()
    }

    // Fetch data from the second service

    let url_2 = "https://shopping.yahooapis.jp/ShoppingWebService/V1/json/itemLookup?appid=\(self.appId)&itemcode=\(boncode1)"

    //Indicate that the second block of work (second service call) has entered the group.
    dispatchGroup.enter()

    AF.request(url_2).responseDecodable(of: troisViewController.Welcome.self) { response in
        // handle response from the second service if you need it

        // Indicate that the second block in the group finished executing.
        dispatchGroup.leave()
    }

    // This function schedules a notification block to be submitted to the specified queue 
    // when all blocks associated with the dispatch group have completed.
    dispatchGroup.notify(queue: .main) {
        // process results of 2 service calls
    }
}
person Evgeny Karkan    schedule 24.03.2020
comment
Большое спасибо за ваш ответ, я выбрал первый вариант, который, кажется, хорошо работает с простым if else. К сожалению, это не удалось с методом группы рассылки. Поскольку это два разных вызова API, я надеюсь, что метод if else не снизит производительность извлечения данных с точки зрения скорости. - person charlslvn; 29.03.2020
comment
Итак, если у нас есть два или более асинхронных вызова, нам не нужно иметь блоки dispatchGroup.notify(queue: .main) каждый раз, когда мы покидаем группу отправки? - person KamyFC; 28.05.2021

Alamofire не предоставляет собственных асинхронных примитивов. Вместо этого вы можете составить запросы Alamofire из существующих примитивов или предоставить свои собственные. Самое простое, хотя и неэлегантное решение здесь — просто вложить вызовы:

AF.request(...).responseDecodable(of: ...) { outer in
    // Handle outer response.
    AF.request(...).responseDecodable(of: ...) { inner in
        // Handle inner response.
    }
}

Кроме того, нет необходимости передавать DispatchQueue.main в Alamofire, так как это очередь по умолчанию, в которой все равно вызываются ваши обработчики ответов.

person Jon Shier    schedule 24.03.2020