首页 > 解决方案 > Alamofire doesn't execute whole code in response closure

问题描述

I'm trying to get photos of user. On the TableView of friends list I call the function

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard segue.identifier == "showFriendSegue" else {return}
        guard let showFriend = segue.destination as? FriendCollectionViewController else {return}
        let indexPath = self.tableView.indexPathForSelectedRow
        let userKey = usersSectionTitles[indexPath!.section]
        if let userValues = usersDictionary[userKey] {
            let user = userValues[indexPath!.row]
            let id  = userValues[indexPath!.row].id
            showFriend.friend.append(user)
            showFriend.friendImages = Photo.photo.getUserPhotos(id: id)
        }
    }
func getUserPhotos(id: Int) -> [String]{
        let url = URL(string: "https://api.vk.com/method/photos.get")!
        let parameters: Parameters = [
            "owner_id" : id,
            "album_id" : "profile",
            "rev" : 1,
            "access_token" : Session.session.token,
            "v": Session.session.APIVersion
        ]
        
        var userPhotos: [String] = []
    
        AF.request(url, method: .get, parameters: parameters, headers: nil).responseJSON { (response) in
            switch response.result {
            case .success(let value):
                let json = JSON(value)
              
                let photosArray = json["response"]["items"].arrayValue

                for sizes in photosArray {
                    let onlyOneType = sizes["sizes"].arrayValue.filter({$0["type"] == "z"})
                    for url in onlyOneType {
                        userPhotos.append(url["url"].stringValue)
                    }
                }

            case .failure(let error):
                print(error)
            }
        }
        return userPhotos
    }

It seems for me like Alamofire doesn't have enough time to make whole code and it's strange because I expect that code should be executed consistently. When I check code with breakpoints I see that AF.request starts, then right away return userPhotos executes, photosArray is not empty but on the friend's page I have an empty array of photos. How should I fill the array from AF? I thought it was obvious and simple thing but I can't understand what's wrong with this closure.

标签: iosswift

解决方案


Alamofire request runs asynchronously, that's why your code returns empty userPhotos at once. You need to use completion handler for this function. It will be called when your request returns a response with ids.

And I recommend to call this function in the FriendCollectionViewController instead of func prepare(for segue: UIStoryboardSegue, sender: Any?).

Attach code snippet below how to use completion for your case.

func getUserPhotos(id: Int, completion: @escaping (Result<[String], Error>) -> Void) {
        let url = URL(string: "https://api.vk.com/method/photos.get")!
        let parameters: Parameters = [
            "owner_id" : id,
            "album_id" : "profile",
            "rev" : 1,
            "access_token" : Session.session.token,
            "v": Session.session.APIVersion
        ]
        AF.request(url, method: .get, parameters: parameters, headers: nil).responseJSON { (response) in
            switch response.result {
            case .success(let value):
                let json = JSON(value)
              
                let photosArray = json["response"]["items"].arrayValue
                var userPhotos: [String] = []
                for sizes in photosArray {
                    let onlyOneType = sizes["sizes"].arrayValue.filter({$0["type"] == "z"})
                    for url in onlyOneType {
                        userPhotos.append(url["url"].stringValue)
                    }
                }
                completion(.success(userPhotos))

            case .failure(let error):
                print(error)
                completion(.failure(error))
            }
        }
    }

Then you can call your method.

Photo.photo.getUserPhotos(id: friend[0].id, completion: { result in
    switch result {
    case .success(let ids):
      // handle your ids here
    case .failure:(let error):
      // handle error
    }
}) 

推荐阅读