Функция выполняется дважды, если выполняются вложенные асинхронные вызовы, и один раз в противном случае. Нужна помощь в предварительном определении, когда это произойдет

#swift

#swift

Вопрос:

функция handleGetAllPhotoURLs вызывается из строки ниже, и я подтвердил, что строка кода выполняется только один раз с точками останова.

 _ = FlickrClient.getAllPhotoURLs(currentPin: self.currentPin, fetchCount: fetchCount, completion: self.handleGetAllPhotoURLs(pin:urls:error:))
  

Согласно выводам из моих инструкций печати, функция выполняется дважды, потому что она печатает две строки вывода, если urls.count не равен нулю. Однако, если urls.count равно нулю, я получаю только один оператор печати, в котором указано «urls.count —> 0»

handleGetAllPhotoURLs —> urls.count —> 0 // эта строка всегда печатается

handleGetAllPhotoURLs —> urls.count —> 21 // эта строка выводится только в том случае, если параметр urls не является пустым

 func handleGetAllPhotoURLs(pin: Pin, urls: [URL], error: Error?){
    print("handleGetAllPhotoURLs ---> urls.count  ---> (urls.count)")

    let backgroundContext: NSManagedObjectContext! = dataController.backGroundContext
    if let error = error {
        print("func mapView(_ mapView: MKMapView, didSelect... n(error)")
        return
    }

    let pinId = pin.objectID
    backgroundContext.perform {
        let backgroundPin = backgroundContext.object(with: pinId) as! Pin
        backgroundPin.urlCount = Int32(urls.count)
        try? backgroundContext.save()
    }

    for (index, currentURL) in urls.enumerated() {
        URLSession.shared.dataTask(with: currentURL, completionHandler: { (imageData, response, error) in
            guard let imageData = imageData else {return}
            connectPhotoAndPin(dataController: self.dataController, currentPin:  pin , data: imageData, urlString: currentURL.absoluteString, index: index)
        }).resume()
    }
}
  

Кроме того, у меня есть UILabel, который отображается только тогда, когда urls.count равен нулю, и я хочу показывать его только тогда, когда urls пуст.

Прямо сейчас, если urls не пуст, приложение очень быстро выдает пустое сообщение UILabel. Что теперь имеет смысл для меня, потому что оператор print показывает, что массив urls временно пуст.

Есть ли способ для меня определить, чтобы избежать отправки пустого сообщения UILabel пользователю, когда urls.count не равен нулю?

редактировать: добавлен код ниже на основе запроса. Функция, приведенная ниже, вызывается для получения [URL] в обработчике завершения. Затем обработчик завершения передается в: func handleGetAllPhotoURLs(pin: Pin, urls: [URL], ошибка: ошибка?)

 class func getAllPhotoURLs(currentPin: Pin, fetchCount count: Int, completion: @escaping (Pin, [URL], Error?)->Void)-> URLSessionTask?{
    let latitude = currentPin.latitude
    let longitude = currentPin.longitude
    let pageNumber = currentPin.pageNumber


    let url = Endpoints.photosSearch(latitude, longitude, count, pageNumber).url

    var array_photo_URLs = [URL]()
    var array_photoID_secret = [[String: String]]()
    var array_URLString = [String]()
    var array_URLString2 = [String]()
    var count = 0

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        guard let dataObject = data, error == nil else {
            DispatchQueue.main.async {
                completion(currentPin, [], error)
            }
            return
        }

        do {
            let temp = try JSONDecoder().decode(PhotosSearch.self, from: dataObject)
            temp.photos.photo.forEach{
                let tempDict = [$0.id : $0.secret]
                array_photoID_secret.append(tempDict)

                let photoURL = FlickrClient.Endpoints.getOnePicture($0.id, $0.secret)
                let photoURLString = photoURL.toString
                array_URLString.append(photoURLString)

                getPhotoURL(photoID: $0.id, secret: $0.secret, completion: { (urlString, error) in
                    guard let urlString = urlString else {return}
                    array_URLString2.append(urlString)
                    array_photo_URLs.append(URL(string: urlString)!)
                    count = count   1
                    if count == temp.photos.photo.count {
                        completion(currentPin, array_photo_URLs, nil)
                    }
                })
            }
            completion(currentPin, [], nil)
            return
        } catch let conversionErr {
            DispatchQueue.main.async {
                completion(currentPin, [], conversionErr)
            }
            return
        }
    }
    task.resume()
    return task
}
  

Комментарии:

1. Содержимое функции не влияет на то, сколько раз вызывается функция. Мы должны посмотреть, как вы вызываете этот метод.

2. Привет. Внесено редактирование, которое, надеюсь, может предоставить больше информации. класс func getAllPhotoURLs() возвращает обработчик завершения, который затем переходит в функцию handleGetAllPhotoURLs() . Если я могу предоставить что-нибудь еще, чтобы помочь, пожалуйста, дайте мне знать

Ответ №1:

В do блоке вы вызываете completion дважды. Пожалуйста, ознакомьтесь с исправлением,

 do {
    let temp = try JSONDecoder().decode(PhotosSearch.self, from: dataObject)
    if temp.photos.photo.isEmpty == false {
       temp.photos.photo.forEach{
        let tempDict = [$0.id : $0.secret]
        array_photoID_secret.append(tempDict)

        let photoURL = FlickrClient.Endpoints.getOnePicture($0.id, $0.secret)
        let photoURLString = photoURL.toString
        array_URLString.append(photoURLString)

        getPhotoURL(photoID: $0.id, secret: $0.secret, completion: { (urlString, error) in
            guard let urlString = urlString else {return}
            array_URLString2.append(urlString)
            array_photo_URLs.append(URL(string: urlString)!)
            count = count   1
            if count == temp.photos.photo.count {
                completion(currentPin, array_photo_URLs, nil)
            }
        })
      }
    } else {
        completion(currentPin, [], nil)
    }
    return
}
  

Комментарии:

1. Большое вам спасибо. Я искал во всех неправильных местах. Не осознавал, что я дважды возвращал обработчик завершения.