简体   繁体   中英

UIGraphicsImageRenderer closure doesn't complete and return an image in some cases when invoked from within an extension

I'm attempting to generate an image when a notification service extension receives a push (yes that's within a service extension, not a content extension. I have a requirement to generate an image and add to contacts on receipt of a user directed push). I have noticed however that in some usages UIGraphicsImageRenderer doesn't return, depending upon what its closure contains. Here's an example:

    let mainImageRenderer = UIGraphicsImageRenderer(size: theSize)
    let mainImage = mainImageRenderer.image { context in
        context.cgContext.setFillColor(UIColor.clear.cgColor)
        context.fill(CGRect(origin: .zero, size: screenSize))
        let rectangle = CGRect(x: 0, y: 0, width: 50, height: 50)
        context.cgContext.setFillColor(UIColor.red.cgColor)
        context.cgContext.setStrokeColor(UIColor.black.cgColor)
        context.cgContext.setLineWidth(10)
        context.cgContext.addRect(rectangle)
        context.cgContext.drawPath(using: .fillStroke)
        NSLog("Line 1 - This line logged")
    }
    NSLog("Line 2 - This line not logged and no image is created")

If this code is run within the app itself (or run within a notification content extension for that matter) then it works and Line 2 is reached, but when its run within a notification service extension then Line 2 is never reached. Its similar behavior if the closure includes UIImage.draw(at:) or UIImage.draw(in) for example. However if the closure contains NSAttributedString.draw() then the code executes as expected when called from within the notification extension, here's example code which does workand in this case Line 2 does get reached:

let textImage = textRenderer.image { context in
    context.cgContext.setFillColor(gray.cgColor)
    context.fill(CGRect(origin: .zero, size: textRectangleSize))
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center
    let attrs: [NSAttributedString.Key: Any] = [
        .font: UIFont.systemFont(ofSize: 10),
        .paragraphStyle: paragraphStyle
    ]
    let attributedString = NSAttributedString(string: transcript, attributes: attrs)
    attributedString.draw(with: CGRect(x: 10, y: 10, width: textRectangleSize.width - 20, height:textRectangleSize.height - 20),
                          options: .usesLineFragmentOrigin, context: nil)
    NSLog("Line 1 - This line logged")
}
NSLog("Line 2 - Now this line is logged and image is created")

Is there some fundamental reason/issue preventing UIKit from functioning properly within a notification service extension? If so then why is NSAttributedString.draw not causing any issues with UIGraphicsImageRenderer but other things such as UIImage.draw() do cause issues?

Is there an alternative graphics API that I could use instead of UIGraphicsImageRenderer()? I basically want to be able to draw a rectangle within another UIImage.

UPDATE: After doing some more experimentation, I discovered the size of the image being created affects the results, for example this fails:

private class func createBackdropImage() -> UIImage {
    let screenSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
    let renderer = UIGraphicsImageRenderer(size: screenSize)
    let image = renderer.image { context in
        context.cgContext.setFillColor(UIColor.red.cgColor)
        context.fill(CGRect(origin: .zero, size: screenSize))
    }
    NSLog("May or may not reach here depending upon size")
    return image
}

If I run the following, on my handset the values for width/height are coming out at 375/812 and this causes the code not to execute as expected and the log line not to be reached. However if the size is made smaller then it works as expected. I tried reducing a little from 375/812 down to 370/800 but it still fails, however if I make it smaller, for example 300/700, then it starts working.

Why is the size of the image being created having this affect? And why only within a notification service extension is this behavior happening?

I think this probably is a memory issue. Extensions have limited memory and trying to do image processing with images the size of the screen dimensions might be too much for it, hence why decreasing the overall size of the image being created makes it work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM