iosswiftuiimageciimage

imageView.image = UIImage(ciImage: ) won't update a second time


Case: I have a UISwitch button in view. When switch is off, the imageView will display a QRCode image generated from a string. When on, it will display a barcode image generated from string. I copied the QRCode and barcode generation functions from https://www.hackingwithswift.com/ and they are working fine.

The problem is the imageView displays the generated image only for the first time. When switching between QRCode and barcode, the imageView won't update anymore. I am 100% sure the UISwitch is working, the functions are called and returning the generated image. I have tested multiple times with break points and printing, the functions are not returning nil or empty images.

Here is QRCode generation code

func generateQRCode(from string: String) -> UIImage? {
    let data = string.data(using: String.Encoding.ascii)

    if let filter = CIFilter(name: "CIQRCodeGenerator") {
        filter.setValue(data, forKey: "inputMessage")
        let transform = CGAffineTransform(scaleX: 3, y: 3)

        if let output = filter.outputImage?.transformed(by: transform) {
            return UIImage(ciImage: output) //<== it always returns this
        }
    }
    return nil
}

Here is barcode generation code

func generateBarcode(from string: String) -> UIImage? {
    let data = string.data(using: String.Encoding.ascii)

    if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
        filter.setValue(data, forKey: "inputMessage")
        let transform = CGAffineTransform(scaleX: 3, y: 3)

        if let output = filter.outputImage?.transformed(by: transform) {
            return UIImage(ciImage: output) //<== it always returns this
        }
    }
    return nil
}

Here is how I switch between QRCode and barcode and the logic is correct

func toggleBarcode(isBarcode : Bool) {
    if isBarcode {
        qrImageView.image = generateBarcode(from: "Hacking with Swift")
    } else {
        qrImageView.image = generateQRCode(from: "Hacking with Swift")
    }
}

When testing with something like

qrImageView.image = UIImage(named: "myimage")

it works everytime.

The imageView won't just update with UIImage(ciImage: )

I even tested with a few different versions of QR and barcode generation codes they all don't update the imageView for a second time.

I tried

qrImageView.setNeedsDisplay()

but no luck.


Solution

  • Quick searching ... seems to be either a "bug" or a change...

    Changing your generator code to this seems to correct the issue:

    func generateQRCode(from string: String) -> UIImage? {
        let data = string.data(using: String.Encoding.ascii)
    
        let context = CIContext()
    
        if let filter = CIFilter(name: "CIQRCodeGenerator") {
            filter.setValue(data, forKey: "inputMessage")
            let transform = CGAffineTransform(scaleX: 3, y: 3)
            
            if let output = filter.outputImage?.transformed(by: transform) {
                if let retImg = context.createCGImage(output, from: output.extent) {
                    return UIImage(cgImage: retImg)
                }
            }
        }
        return nil
    }
    
    func generateBarcode(from string: String) -> UIImage? {
        let data = string.data(using: String.Encoding.ascii)
    
        let context = CIContext()
    
        if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
            filter.setValue(data, forKey: "inputMessage")
            let transform = CGAffineTransform(scaleX: 3, y: 3)
            
            if let output = filter.outputImage?.transformed(by: transform) {
                if let retImg = context.createCGImage(output, from: output.extent) {
                    return UIImage(cgImage: retImg)
                }
            }
        }
        return nil
    }