【问题标题】:Get a CGImageRef from an IKImageView in Swift从 Swift 中的 IKImageView 获取 CGImageRef
【发布时间】:2014-06-19 14:40:49
【问题描述】:

我正在尝试获取与视图关联的图像,但 Xcode 向我返回了一个错误。代码如下:

@IBOutlet var imageView: IKImageView // Link to the image view.

func saveImage() {
    var newImage: CGImageRef = imageView.image() // Line with an error.
}

我有一个awakeFromNib函数来设置视图中的图像。上面的代码返回给我'Unmanaged<CGImage>' is not convertible to 'CGImageRef'

我知道类型在 Swift 中是可选的,但我不明白为什么会出现此错误,IKImageView Class Reference 明确表示获取 IKImageView 的图像返回 CGImageRef。

【问题讨论】:

    标签: macos swift ikimageview


    【解决方案1】:

    这与将 Objective C API 桥接到 Swift 有关。 API 的 Swift 版本已通过将原始的 Objective C 标头转换为 Swift 版本来桥接(我相信大部分是自动的)。在许多情况下,转换可以计算出你将要返回什么样的值,因此在 Swift 中你会得到一个“正常”的类型,你可以按照你的期望使用它。

    但是,转换仍在进行中。在这种情况下,您看到的是一种用于帮助您在转换过程不知道您是否要取回为您保留的对象时手动管理内存的类型,因为 API 不没有它可以用来弄清楚的常规注释。

    Unmanaged 类型有效地表示“你必须告诉我如何处理包含的值才能获得正确的内存管理”。一旦你得到一个非托管值,你应该调用它的两个方法之一:

    takeUnretainedValue() 
    takeRetainedValue()
    

    ...取决于您返回的对象是“+0”还是“+1”。因此,您应该执行以下操作:

    var newImage: CGImage = imageView.image().takeUnretainedValue()
    

    一旦你这样做了(你应该立即这样做),你已经给了 Swift 足够的提示,它现在可以使用 ARC 正确地管理对象,并为你自己提供了一个有效的参考正确的类型。

    在今年的“Swift Interoperability in Depth”WWDC 视频的结尾处简要介绍了这一点。

    【讨论】:

    • 感谢您的解释和有用的 WWDC 视频,新行使我的应用程序崩溃(但在构建之前没有更多错误)。我尝试使用takeUnretainedValue()takeRetainedValue() 以防万一,你认为我应该填写错误报告吗?
    • 取决于崩溃及其所在位置。是在新线上(我认为应该相对安全),还是在您尝试使用 newImage 时?是否有可能实际上没有图像(即nil)从image() 调用返回?可能需要更多调试。
    • println(imageView.image().takeUnretainedValue())returns <CGImage 0x6080001a6740>。当我设置newImage时,问题似乎就在线了。
    • 人力资源部。所以你肯定得到了看起来像一个有效的 CGImage 的东西。并将其放入 CGImageRef (我将更改我的答案以遵循@rickster 的建议并在几秒钟内使用 CGImage)应该没问题,因为它们是类型别名。您遇到的实际错误是什么?
    • 何时使用 takeUnretainedValue() 或 takeRetainedValue()?
    【解决方案2】:

    查看the new version of the IKImageView reference that shows Swift declarations 中的image() 方法,您会看到它返回Unmanaged<CGImage>!。这意味着 ImageKit 没有设置为编译器可以在其 API 上自动推断 CoreFoundation 内存管理语义。 (这会影响 Swift 翻译和 ObjC 隐式 ARC 桥接。)应该是 a good bug to file

    Swift 类型Unmanaged<T> 是您在编译器无法自动推断其 ARC 行为时与 CF 类型交互的方式。要获取底层类型,请调用 takeUnretainedValue()takeRetainedValue() — 您必须根据您调用的 API 是否已知已经保留了它返回的值来选择哪个。令人兴奋的猜测! (同样,消除猜测将是a good bug to file。)您可以在Using Swift with Cocoa and Objective-C 中阅读更多相关信息。

    无论如何,在这种情况下,您可能会期望IKImageView 在提供CGImage 时不会增加其保留计数,因此您可以像这样解开Unmanaged

    var newImage: CGImage = imageView.image().takeUnretainedValue()
    

    另请注意,在 Swift 中使用 CF 类型时,您不需要 Ref 后缀。 (CGImageRefCGImage 的别名。)Swift 让您可以将 CF 类型视为 Swift 对象(而不是作为指向不透明 C 类型的 C 指针)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多