I'm trying to retrieve images from array of url..
I have this function that do the same as I won't but it doesn't work so I tried to use URLSession but didn't know how exactly to make it >>
func downloadImages(imageUrls: [String], completion: @escaping (_ images: [UIImage?]) -> Void) {
var imageArray: [UIImage] = []
var downloadCounter = 0
for link in imageUrls {
let url = NSURL(string: link)
let downloadQueue = DispatchQueue(label: "imageDowmloadQueue")
downloadQueue.sync {
downloadCounter += 1
let data = NSData(contentsOf: url! as URL)
if data != nil {
//image data ready and need to be converted to UIImage
imageArray.append(UIImage(data: data! as Data)!)
if downloadCounter == imageArray.count {
DispatchQueue.main.async {
completion(imageArray)
}
}
} else {
print("couldnt download image")
completion(imageArray)
}
}
}
}
The function I work on :
public func imagesFromURL(urlString: [String],completion: @escaping (_ images: [UIImage?]) -> Void) {
var imageArray: [UIImage] = []
var downloadCounter = 0
let downloadQueue = DispatchQueue(label: "imageDowmloadQueue")
for link in urlString {
downloadQueue.sync {
downloadCounter += 1
let dataTask = URLSession.shared.dataTask(with: NSURL(string: link)! as URL, completionHandler: { (data, response, error ) in
if error != nil {
print(error ?? "No Error")
return
}
if data != nil {
imageArray.append(UIImage(data: data! as Data)!)
if downloadCounter == imageArray.count {
completion(imageArray)
}
} else {
print("couldnt download image")
completion(imageArray)
}
} dataTask.resume()
}
}
}
i want to call the function in the collection cell and get the display the first image only from each artwork array..
//download the first image only to display it:
if artwork.ImgLink != nil && artwork.ImgLink.count > 0 {
downloadImages(imageUrls: [artwork.ImgLink.first!]) { (images) in
self.artworkImage.image = images.first as? UIImage
}
}
UIImagefrom an array of urls, you do not design a function trying to download all of them. Instead, try to download from the first url, return the downloadedUIImageif it succeeds, or continue with the second url if it fails, repeat until you get anUIImage.DispatchQueuein a local function looks dangerous to me. A more common practice is to maintain a queue somewhere else and pass it to the function as a parameter, or reuse one of the predefined global queues usingDispatchQueue.global(qos:)if you don't have a specific reason.sync.syncblocks the calling thread until your block finishes in the queue. Generally you useasync.Intcounter to control when to finish multiple async tasks (when to call the completion block) works but can be improved by usingDispatchGroup, which handles multiple async tasks in a simple and clear way.Here's two functions. Both work.
firstImage(inURLs:completion:)only return the firstUIImagethat it downloads successfully.images(forURLs:completion:)tries to download and return them all.