Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making deep copy of UIImage

My class contains an UIImage property which I want to enforce as a 'copy' property by any external clients accessing it. But, when I try to do a copy in my custom setter, I get the runtime error about UIImage not supporting copyWithZone. So what's a good way to ensure that the correct ownership policy is followed?

// 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];
    }
}
like image 823
Justin Galzic Avatar asked Oct 23 '10 01:10

Justin Galzic


People also ask

What is the difference between a UIImage and a UIImageView?

UIImage contains the data for an image. UIImageView is a custom view meant to display the UIImage .

How do I find my UIImage path?

Once a UIImage is created, the image data is loaded into memory and no longer connected to the file on disk. As such, the file can be deleted or modified without consequence to the UIImage and there is no way of getting the source path from a UIImage.

How do you declare UIImage in Objective C?

For example: UIImage *img = [[UIImage alloc] init]; [img setImage:[UIImage imageNamed:@"anyImageName"]]; My UIImage object is declared in .


2 Answers

A deep copy

When talking about deep copies we must first understand that UIImage is a container. It doesn't actually contain the image data. The underlying data can be a CIImage or a CGImage. In most cases the backing data is a CGImage which is in turn a wrapping struct and copying the CGImage is just copying the metadata and not the underlying data. If you want to copy the underlying data you can draw the image into a context or grab a copy of the data as a PNG.

UIImagePNGRepresentation

Creating a playground with the following demonstrates the method.

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
like image 20
Cameron Lowell Palmer Avatar answered Oct 21 '22 13:10

Cameron Lowell Palmer


Here is a way to do it:

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

The reason I needed this is that I had an image variable initialized with imageWithContentsOfFile:, and I wanted to be able to delete the file from disk but keep the image variable. I was surprised to find that when the file is deleted the image variable goes crazy. It was displaying wacky random data even though it was initialized before the file was deleted. When I deep copy first it works fine.

like image 77
user1139733 Avatar answered Oct 21 '22 14:10

user1139733