Search code examples
iosswiftflickr

Data Out of Order


I am using the Flickr API to get all albums within a collection and then using the album IDs from to get the primary photo for each of the albums. It works but the photos are not returned to me in order so the primary photo for each album does not match up to the album titles in my collection view.

func getPhotoCollection() {
        let collectionURLString = "https://api.flickr.com/services/rest/?method=flickr.collections.getTree&api_key={API_KEY}&collection_id=72157676119666248&user_id={USER_ID}&format=json&nojsoncallback=1"

        self.session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
        let task = self.session?.dataTask(with: URL(string: collectionURLString)!, completionHandler: { (data, response, error) in
            let json = self.getJSONFrom(urlString: collectionURLString)
            let collections = json["collections"]
            let collection = collections["collection"].arrayObject as! [[String:AnyObject]]
            for collectionObject in collection {
                let sets = collectionObject["set"] as! [[String: AnyObject]]
                for set in sets {
                    let albumId = set["id"] as! String
                    let albumTitle = set["title"] as! String
                    self.albumIds.append(albumId)
                    self.albumTitles.append(albumTitle)
                }
            }

            self.getAlbumPrimary()
        })

        task?.resume()
    }

func getAlbumPrimary() {
        for albumId in self.albumIds {
            let apiURLString = "https://api.flickr.com/services/rest/?method=flickr.photosets.getPhotos&api_key={API_KEY}&photoset_id=\(albumId)&per_page=1&user_id={USER_ID}&format=json&nojsoncallback=1"

            self.session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
            let task = self.session?.dataTask(with: URL(string: apiURLString)!, completionHandler: { (data, response, error) in
                let json = self.getJSONFrom(urlString: apiURLString)
                let photos = json["photoset"]
                let photo = photos["photo"].arrayObject as! [[String:AnyObject]]
                let primaryPic = photo[0]
                let farm = primaryPic["farm"] as! Int
                let server = primaryPic["server"] as! String
                let picId = primaryPic["id"] as! String
                let secret = primaryPic["secret"] as! String

                let urlString = String(format: "https://farm%d.static.flickr.com/%@/%@_%@_b.jpg", farm, server, picId, secret)
                self.albumPrimaryURLs.append(urlString)

                DispatchQueue.main.async {
                    self.collectionView.reloadData()
                    self.loaded = true
                }
            })

            task?.resume()
        }
    }

Solution

  • This is the way multiple asynchronous tasks work ( out of order ) ,you need to create a model instead of seperate arrays then load from the data to fill the last property

    class Item {
      let id,title:String
      var url:String?
      init(id:String,title:String){
       self.id = id
       self.title = title 
      }
      func loadUrl(completion:@escaping () -> () ) {
         // here load and set the url
      }
    }
    

    var items = [Item]() // declare main array 
    
     let albumId = set["id"] as! String
     let albumTitle = set["title"] as! String 
     let item = Item(id:albumId,title:albumTitle)
     self.items.append(item) 
    

    Then to load the collection finally

    let g = DispatchGroup()
    items.forEach {
       g.enter()
       $0.loadUrl {
          g.leave()
       }
    } 
    g.notify(queue:.main) {
      self.collectionView.reloadData()
      self.loaded = true
    }