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];
}
}
UIImage contains the data for an image. UIImageView is a custom view meant to display the UIImage .
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.
For example: UIImage *img = [[UIImage alloc] init]; [img setImage:[UIImage imageNamed:@"anyImageName"]]; My UIImage object is declared in .
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With