【问题标题】:Making deep copy of UIImage制作 UIImage 的深拷贝
【发布时间】:2011-04-29 11:00:12
【问题描述】:

我的类包含一个 UIImage 属性,我希望任何访问它的外部客户端都将其强制为“复制”属性。但是,当我尝试在我的自定义设置器中进行复制时,我收到关于 UIImage 不支持 copyWithZone 的运行时错误。那么什么是确保遵循正确的所有权政策的好方法呢?

// declared in the interface as:
@property (nonatomic, readonly, copy) UIImage *personImage;

// class implementation
- (void)setPersonImage:(UIImage *)newImage
{
    if (newImage != personImage) 
    {
        [personImage release];

        // UIImage doesn't support copyWithZone
        personImage = [newImage copy];
    }
}

【问题讨论】:

    标签: iphone objective-c memory-management


    【解决方案1】:

    这是一种方法:

    UIImage *imageToCopy = <# Your image here #>;
    UIGraphicsBeginImageContext(imageToCopy.size);
    [imageToCopy drawInRect:CGRectMake(0, 0, imageToCopy.size.width, imageToCopy.size.height)];
    UIImage *copiedImage = [UIGraphicsGetImageFromCurrentImageContext() retain];
    UIGraphicsEndImageContext();   
    

    我需要这个的原因是我有一个使用 imageWithContentsOfFile: 初始化的图像变量,并且我希望能够从磁盘中删除文件但保留图像变量。我惊讶地发现,当文件被删除时,图像变量变得疯狂。它显示古怪的随机数据,即使它在文件被删除之前被初始化。当我首先进行深度复制时,它工作正常。

    【讨论】:

      【解决方案2】:

      深拷贝

      在谈到深拷贝时,我们首先要了解UIImage 是一个容器。它实际上并不包含图像数据。基础数据可以是CIImageCGImage。在大多数情况下,支持数据是CGImage,它又是一个包装结构,复制CGImage只是复制元数据而不是基础数据。如果您想复制基础数据,您可以将图像绘制到上下文中或获取数据的副本作为 PNG。

      UIImagePNG 表示

      使用以下内容创建一个 Playground 演示该方法。

      let zebra = UIImage(named: "an_image_of_a_zebra")
      print(zebra?.CGImage) // check the address
      let shallowZebra = UIImage(CGImage: zebra!.CGImage!) 
      print(shallowZebra.CGImage!) // same address
      
      let zebraData = UIImagePNGRepresentation(zebra!)
      let newZebra = UIImage(data: zebraData!)
      print(newZebra?.CGImage) // new address
      

      【讨论】:

        【解决方案3】:

        为什么需要复制语义? UIImage 是不可变的,因此设置复制策略没有任何好处。如果存在其他人可能修改您的图像的风险,您只需要一个复制策略。由于 UIImage 是不可变的,因此没有发生这种情况的风险,因此保留属性很好。

        如果你多解释一下你想要做什么,可能还有其他方法可以实现它。

        【讨论】:

        • 我不确定 OP 是否有充分的理由,但复制 UIImage 的一个原因是它是否来自压缩文件格式。它在需要之前不会解压缩,如果将其应用于 UIImageView,则解压缩将在 UI 线程上进行,这可能会很麻烦。复制强制解压到内存中。
        【解决方案4】:

        因为图像本身就是一个指针,所以需要创建一个图像上下文,将图像绘制到上下文中,然后从上下文中获取原始图像。也许你需要使用 UIImage.CGImage。

        【讨论】:

          【解决方案5】:
           CGImageRef newCgIm = CGImageCreateCopy(oldImage.CGImage);
           UIImage *newImage = [UIImage imageWithCGImage:newCgIm scale:oldImage.scale 
                               orientation:oldImage.imageOrientation];
          

          【讨论】:

          • 如果问题是深拷贝,那么这会导致只拷贝 CGImage 结构,而不是底层数据。
          【解决方案6】:

          Swift 5.1 的代码:

              let imageToCopy = <# your_image #>
              UIGraphicsBeginImageContext(imageToCopy.size)
              imageToCopy.draw(in: CGRect(x: 0, y: 0, width: imageToCopy.size.width, height: imageToCopy.size.height))
              let copiedImage = UIGraphicsGetImageFromCurrentImageContext()
              UIGraphicsEndImageContext()
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-09-07
            • 2012-06-01
            • 2012-04-12
            • 2017-05-13
            • 1970-01-01
            • 2015-01-13
            • 2011-09-05
            • 1970-01-01
            相关资源
            最近更新 更多