Govind
Govind

Reputation: 481

How to load image from url which I got via API calling

I want to use UICollectionView for displaying the images and I am getting that images by api calling.

Question: so I am getting images path via api calling so how can I display it to UICollectionView??

here is my code ::

  func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
    let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell

    cell.imagev.image = dic["image"] as? UIImage
    return cell
}

and here is my api response

(
    {
    image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/esquire.jpg";
    slug = esquire;
},
    {
    image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/forbes.jpg";
    slug = forbes;
},
    {
    image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/tapas.jpg";
    slug = tapas;
}
)

so how can I display this images in my UICollectionView

UPDATE:: While using commented code getting strange issue i am calling my webservice in viewdidload

override func viewDidLoad() {
    super.viewDidLoad()

    webimages()

    // Do any additional setup after loading the view, typically from a nib.
}

and its started to call webservice

func webimages()
{

let url = "http://radio.spainmedia.es/podcasts/"

    request(.GET, url, parameters: nil, encoding: .JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in


           print(response.result.value)

            self.imagearray = (response.result.value) as! NSMutableArray
            print(self.imagearray)


    }

}

but after requesting its suddenly go to cellForItemAtIndexPath so my "imagearray" found nil there. and then its comeback to webimages() and giving me api response.

So how can I solve this?

we have array of string we are passing single string here so can you please tell me that what is the solution

We have array of string we are passing single string here so can you please tell me that what is the solution

enter image description here

Upvotes: 0

Views: 4759

Answers (4)

bhumika
bhumika

Reputation: 13

  if let url = NSURL(string: "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") {
        if let data = NSData(contentsOfURL: url){
            imageURL!.contentMode = UIViewContentMode.ScaleAspectFit
            imageURL!.image = UIImage(data: data)
        }
    }

Upvotes: 0

NSNoob
NSNoob

Reputation: 5608

You are setting a URL string as UIImage. You first have to retrieve image from that URL first. Use the following method for quick remedy:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
    if imagearray.count > 0 
    {
       let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary

       let imgURL: NSString = dic!["image"] as! NSString //Get URL string
       let url = NSURL.URLWithString(imgURL); //Create URL
       var err: NSError?
       var imageData :NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)! //Fetch Image Data
       var cellImage = UIImage(data:imageData) //Create UIImage from Image data
       cell.imagev.image = cellImage //Set image
    }

    return cell
}

Notice that this is fetching content of image URL in a synchronous call so that would freeze your UI until download completes. Also this is not caching the Image so images will be downloaded over and over again when you scroll and cells are recreated. To avoid that I'd suggest caching .

For better results, This is how you load image asynchronously, without freezing the UI and cache the images to avoid network load.

You first have to create a class first like this:

class ImageLoader {

var cache = NSCache() //Create cache

class var sharedLoader : ImageLoader {
    struct Static {
        static let instance : ImageLoader = ImageLoader()
    }
    return Static.instance
}

func imageForUrl(urlString: String , indexPathArg:NSIndexPath!, completionHandler:(image: UIImage?, url: String,indexPathResponse:NSIndexPath?) -> ()) {

    let currentIndexPath: NSIndexPath! = indexPathArg.mutableCopy() as! NSIndexPath

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in

        let data: NSData? = self.cache.objectForKey(urlString) as? NSData
        //Check if image data for this URL already exists in Cache
        if let goodData = data {
            //data exists, no need to download it again. Just send it
            let image = UIImage(data: goodData)
            dispatch_async(dispatch_get_main_queue(), {() in
                completionHandler(image: image, url: urlString,indexPathResponse: currentIndexPath)
            })
            return
        }
        //Data does not exist, We have to download it
        let downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!,completionHandler: { (data: NSData?, response:NSURLResponse?, error: NSError?) -> Void in
            if (error != nil) {
                //Download failed
                completionHandler(image: nil, url: urlString, indexPathResponse: currentIndexPath)
                return
            }

            if data != nil {
                //Download successful,Lets save this downloaded data to our Cache and send it forward as UIImage
                let image = UIImage(data: data!)
                self.cache.setObject(data!, forKey: urlString)
                dispatch_async(dispatch_get_main_queue(), {() in
                    completionHandler(image: image, url: urlString, indexPathResponse: currentIndexPath)
                })
                return
            }

        })
        downloadTask.resume()
    })

}
}

Then you have to modify your collectionview delegate like this:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
    if imagearray.count > 0 
    {
       let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary

       let imgURL: NSString = dic!["image"] as! NSString//Get URL string
       ImageLoader.sharedLoader.imageForUrl(imgURL as String,indexPathArg: indexPath, completionHandler:{(image: UIImage?, url: String, indexPathResponse: NSIndexPath?) in


        let indexArr:NSArray = collectionView!.indexPathsForVisibleItems()

        if indexArr.containsObject(indexPathResponse!)
        {
            cell.imagev.image = image //Set image
        }

    })
    }


    return cell
}

Now it will load your image asynchronously and will download it only if necessary. Great Success! (To quote Borat). I have added comments so that you can understand What's going on in my code and Daniel's code :)

To Fix your crash issue which is not a part of your original question and instead a different problem you created, Return count of items in section to be count of your image array and reload collectionview once you have retrieved your data:

func webimages()
{

let url = "http://radio.spainmedia.es/podcasts/"

    request(.GET, url, parameters: nil, encoding: .JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in


           print(response.result.value)

            self.imagearray = (response.result.value) as! NSMutableArray
            print(self.imagearray)
            //Reload Collection view
            self.collectionView?.reloadData()

    }

}


func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return imagearray.count
}

Credits for Imageloader class: Daniel Sattler

Special Thanks to: CouchDeveloper

Upvotes: 2

Bishal Ghimire
Bishal Ghimire

Reputation: 2600

You can extend UIImageView as following -

extension UIImageView {
    public func imageFromU(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSURLRequest(URL: url)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
                (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
                if let imageData = data as NSData? {
                    self.image = UIImage(data: imageData)
                }
            }
        }
    }
}

Then in any UIImageView you will have a very simple helper method as follows -

yourImageView.imageFromURL("https://yoururl.com/image.png")

And in your case

cell.imagev.image.imageFromURL(dic["image"])

Upvotes: 0

Satheesh
Satheesh

Reputation: 11276

Pretty easy you got to downlaod the image from that url and set it as the image for the image view,

Try this, https://github.com/natelyman/SwiftImageLoader

Add the ImageLoader class to your project and modify the collectionview data source as below,

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell

//cell.imagev.image = dic["image"] as? UIImage

ImageLoader.sharedLoader.imageForUrl(dic["image"], completionHandler:    {(image: UIImage?, url: String) in
     cell.imagev.image = image
})

return cell
}

This is an asynchronous image loading class so UI would not freeze or give you any other problems if you are against using any third party libs or classes please do it manually as @NSNoob 's answer.

Other good image loading libraries are,

https://github.com/nicklockwood/AsyncImageView

https://github.com/onevcat/Kingfisher

https://github.com/MengTo/Spring/blob/master/Spring/AsyncImageView.swift

https://github.com/anas10/AsyncImageView-Swift

Upvotes: 0

Related Questions