N4SK N4SK - 11 months ago 39
Swift Question

cannot load images in uicollectionview after resizing in global thread

I have been trying to load images in a uicollectionview after resizing them. how to make images resize on background thread and then load in uicollectionview. I tried following code but images doesn't load in the collectionview.

function for resizing

func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size

let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height

// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}

// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

// Actually do the resizing to the rect using the ImageContext stuff

var newImage = UIImage()
DispatchQueue.global().async {
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.draw(in: rect)
newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
}


return newImage
}


this is in cellForItemAt function :

if let imageView = cell.viewWithTag(499) as? UIImageView {
let image = self.cardImages[indexPath.item]
imageView.image = resizeImage(image: image, targetSize: CGSize(width: 100, height: 100))

}

Answer Source

In the resize image method you are using threading. So you need to use a completionHandler block inside the queue brackets. In your code you are returning an empty image while your global queue is calling asynchronous. If you need the code example, let me know, I will edit my answer

=========EDIT==============

func resizeImage(image: UIImage, targetSize: CGSize, completionHandler: @escaping (_ image: UIImage?) -> ()) {
    let size = image.size

    let widthRatio  = targetSize.width  / image.size.width
    let heightRatio = targetSize.height / image.size.height

    // Figure out what our orientation is, and use that to form the rectangle
    var newSize: CGSize
    if(widthRatio > heightRatio) {
        newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
    } else {
        newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
    }

    // This is the rect that we've calculated out and this is what is actually used below
    let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

    // Actually do the resizing to the rect using the ImageContext stuff

    var newImage = UIImage()
    DispatchQueue.global().async {
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
        image.draw(in: rect)
        newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        //now we need to return to the main thread
        //NOTE! This is Swift 3 code
        DispatchQueue.main.async {
             //return the image
             completionHandler(newImage)
        }
    }
}

Now in the method where you want to get an image:

if let imageView = cell.viewWithTag(499) as? UIImageView {
        let image = self.cardImages[indexPath.item]

        resizeImage(image: image, targetSize: CGSize(width: 100, height: 100)) { image in
            imageView.image = image
        }
}

Btw, I wouldn't using this method in the cellForRow method, I prefer to set it in the Custom cell class. But up to you.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download