0

I'm making an app in Swift 2.0 and I'm using a table view with an image view in the prototype cell. The app downloads some images from the facebook server and I want to display them. The images are all downloaded from a different url, so I am using a program to loop trough them and download, just like I did with the names to get them from the internet and display, but I'm a little bit stuck..

 func fetchPicture(identifier: String, completion: (image: UIImage) -> Void)
 {
let url2 = NSURL (string: "http://graph.facebook.com/" + identifier + "/picture?type=normal")

 let urlRequest = NSURLRequest(URL: url2!)

 NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue()) { 
 (response, data, error) -> Void in
    if error != nil 
    {
        print(error)
    } 
    else 
    {

         if let pf = UIImage(data: data!)
          {
            dispatch_async(dispatch_get_main_queue())
             {
                     completion(image: pf)
                    self.tableView.reloadData()
             }
     }


   }
 }}

var images = [UIImage]()

let queue2 = dispatch_queue_create("images", DISPATCH_QUEUE_SERIAL)

dispatch_apply(newArray.count, queue2) { index in
    let identifier = newArray[index]
    fetchPicture(identifier) {
        image in dispatch_async(queue2) 
        {

        }
    }
}

I set the imageview in the cell equal to the variable 'image' so basically I will need to do something like self.image = pf but it needs to be different for each user. With names, I did this with an array, but this isn't working with images I assume..

Help is really appreciated guys! Thanks!

Lamour
  • 3,002
  • 2
  • 16
  • 28
Bram Roelandts
  • 470
  • 7
  • 25
  • BTW, if you do implement this yourself, you might consider using `NSURLSession` rather than the recently-deprecated `NSURLConnection`. – Rob Sep 15 '15 at 20:34

2 Answers2

0

You generally would not want to load all images like this. You definitely don't want to reload the whole table after every image (because that causes it to scroll back to the top of the tableview).

Generally it would be advised to fetch the images lazily (i.e. not until they're needed). You might call fetchPicture from cellForRowAtindexPath and in the completion handler update the cell's image view accordingly.

There are a bunch of details you have to worry about, though:

  • First, the cell may have been reused by the time the fetch is done, so you have to check to make sure the cell is still visible.

  • Second, rather than using an array, I'd suggest using a NSCache, and make sure to purge this cache upon memory pressure. You might want to also cache to persistent storage, though some people prefer to rely upon the NSURLCache mechanisms

  • Third, if the cell scrolls out of view, you might want to cancel the request (so that, for example, if you quickly scroll to the 100th row, that image request doesn't get backlogged behind 99 other image requests for cells that are no longer visible).

Personally, given all the work necessary to do this properly, I might suggest that you consider using a well established asynchronous image fetching mechanism, such as SDWebImage, DFImageManager or Kingfisher. Look at the UIImageView categories/extensions that offer asynchronous image loading. To do all of this properly yourself is a non-trivial exercise, so it's better to use some existing library that provides an asynchronous image view retrieval mechanism.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I would not recommend using SDWebImage, it's outdated (no NSURLSession, still has its own failing GIF engine, etc), it has multiple known issues and it doesn't work with Swift well (no nullability annotations). – kean Sep 16 '15 at 06:44
  • Yeah, I don't really have a horse in that race, and have added Kingfisher and your DFImageManager as alternatives. My main point was that the OP shouldn't be writing this himself. – Rob Sep 16 '15 at 07:14
  • 1
    Yes, this problem has been solved multiple times already. You can also throw [AFNetworking](https://github.com/AFNetworking/AFNetworking), [AlamofireImage](https://github.com/Alamofire/AlamofireImage), [PINRemoteImage](https://github.com/pinterest/PINRemoteImage) into the mix. It's up to OP to decide which one to use. – kean Sep 16 '15 at 07:24
0

You would generally want to use a framework that specializes on that kind of stuff. I would not recommend using SDWebImage, it's outdated (no NSURLSession), has a lot of open issues and doesn't work well with Swift (no nullability annotations).

Take a look at those two libraries that are up to date with iOS platform:

  • DFImageManager - advanced framework written in Objective-C but featuring nullability annotations (works great with Swift). Here's a list of things that make it better, than SDWebImage. Disclosure it's written by me, opinion might be biased.
  • Kingfisher - lightweight library written in Swift. Similar to SDWebImage, but has much less features that SDWebImage and DFImageManager.
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
kean
  • 1,561
  • 14
  • 22
  • If the question is a duplicate, *flag the question as such*. In any case, do not deface an accepted answer. Thank you. – Eric Aya Apr 03 '16 at 12:14