UIGraphicsGetImageFromCurrentImageContext() 给了我一个我不想要的强制解包选项的连锁反应 Swift

UIGraphicsGetImageFromCurrentImageContext() is giving me a chain reaction of forced unwrapped optionals I don't want in Swift

我对在 Swift 中使用 UIGraphicsGetImageFromCurrentImageContext() 感到困惑,这让我强制解包它,即使它是用 let 定义的。添加 ?! 会使我的代码看起来很乱,并且让我更改它之后的所有内容。我不想在定义 scaledImage 时要求它。

let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

let scaledCIImage:CIImage = (scaledImage?.ciImage)! // makes me force upwrap

// gives error 'Value of optional type 'CIFilter?' not unwrapped; did you mean to use '!' or '?'?'
let filter = CIFilter(name: "CIAffineTile", withInputParameters:[kCIInputImageKey:scaledCIImage]).outputImage 

! 有很多合法用途,只要您知道何时正确使用它。

来自 UIGraphicsGetImageFromCurrentImageContext 的文档:

If the current context is nil or was not created by a call to UIGraphicsBeginImageContext(_:), this function returns nil.

由于您正在使用 UIGraphicsBeginImageContext 而您当前的上下文不是 nil,那么 UIGraphicsGetImageFromCurrentImageContext() 不会 return 一个 nil 所以它是可以安全地强制展开。

let scaledImage = UIGraphicsGetImageFromCurrentImageContext()!

至于创建 CIImageCIFilter 和文件 CIImage,请使用 if let.

安全解包
if let scaledCIImage = scaledImage.ciImage,
   let filter = CIFilter(name: "CIAffineTile", withInputParameters:[kCIInputImageKey:scaledCIImage]),
   let outputImage = filter.outputImage {
    // Do what you need with outputImage
}

根据您的评论更新:

鉴于 scaledmage.ciImagenil 并且您想尝试从 cgImage 创建一个 CIImage,您可以更新 if let 的链至:

if let cgImage = scaledImage.cgImage {
    let scaledCIImage = CIImage(cgImage: cgImage)

    if let filter = CIFilter(name: "CIAffineTile", withInputParameters:[kCIInputImageKey:scaledCIImage]),
       let outputImage = filter.outputImage {
        // Do what you need with outputImage
    }
}

Adding in the ? or ! is making my code look messy and making me change everything after it.

好吧,它是否凌乱是很主观的。 Swift 以这种方式设计,让您仔细考虑每个可选项。通过这样做,您可以避免很多 "unexpectedly found nil while unwrapping an optional value" 错误。

方法和属性 return nil 是有原因的。通常原因是发生错误,事情无法完成,或者 属性 没有有效值。这些问题你应该好好想想 - "what should my method do if this method returns nil?"

如果您想在值为 nil 时执行其他操作(即它为 nil 对您的逻辑来说不是致命的),请使用 if let 语句。例如

if let scaledCIImage = scaledImage?.ciImage {
    // deal with the scaledCIImage
} else {
    // do something else to remedy. The method can still continue running
}

如果你的方法在值为nil时无法继续,那么你可以考虑写一个guard语句:

guard let scaledCIImage = scaledImage?.ciImage else { 
    // you need to return some value or call "fatalError()" here
}

如果您绝对确定该值不能为 nil,请强制展开它:

let scaledCIImage = scaledImage!.ciImage!

对于第二个错误,你可以这样修正:

// with force unwrapping
let filter = CIFilter(name: "CIAffineTile", withInputParameters:[kCIInputImageKey:scaledCIImage])!.outputImage!

// if let
if let filter = CIFilter(name: "CIAffineTile", withInputParameters:[kCIInputImageKey:scaledCIImage])?.outputImage {
    // ...
}

// guard let
guard let filter = CIFilter(name: "CIAffineTile", withInputParameters:[kCIInputImageKey:scaledCIImage])?.outputImage else {
    // ...
}

您可以像 rmaddy 显示的那样将所有这些链接在一个大的 if letguard let 语句中。