I want to create and save a UIImage
in iOS 10. I can create it either by taking a UIView
snapshot or using UIGraphicsImageRenderer
(shown below).
- (UIView *)createIcon
{
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(200, 200)];
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context) {
[[UIColor darkGrayColor] setStroke];
[context strokeRect:renderer.format.bounds];
[[UIColor colorWithRed:158/255.0 green:215/255.0 blue:245/255.0 alpha:0.5] setFill];
[context fillRect:CGRectMake(30, 30, 140, 140)];
[[UIColor colorWithRed:243/255.0 green:122/255.0 blue:216/255.0 alpha:0.3] setFill];
CGContextFillEllipseInRect(context.CGContext, CGRectMake(30, 30, 120, 120));
}];
UIImageView *showImage = [[UIImageView alloc] initWithImage:image];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
return showImage;
}
However, when I try to save using UIImageWriteToSavedPhotosAlbum
by including the second last statement, Xcode goes into Debug with the following error report
(lldb) bt
* thread #5, queue = 'com.apple.root.default-qos', stop reason = signal SIGABRT
* frame #0: 0x00000001101611a6 libsystem_kernel.dylib`__abort_with_payload + 10
frame #1: 0x000000011015b86e libsystem_kernel.dylib`abort_with_payload_wrapper_internal + 89
frame #2: 0x000000011015b89b libsystem_kernel.dylib`abort_with_payload + 9
frame #3: 0x0000000108ab3af7 TCC`__CRASHING_DUE_TO_PRIVACY_VIOLATION__ + 182
frame #4: 0x0000000108ab3a41 TCC`__TCCAccessRequest_block_invoke.77 + 665
frame #5: 0x0000000108ab7273 TCC`__tccd_send_block_invoke + 274
So even though I didn’t use a camera to create the image, saving it to the photo album is a violation of privacy (hiss, boo)! I know it is possible to set up privacy keys in the plist but is there a more sensible alternative?
CLARIFICATION
I hope to use rendered images (or view snapshots) as assets in the app. So instead of is there a more sensible alternative ?
perhaps I should have asked
is there an alternative place to save images (i.e. as PNG or JPG files) so privacy is not an issue?
You can save any UIImage to the photo album but first you must ask the user for permission to do as this as it is indeed a privacy issue. If they don't give you access then you can't save the image at all.
The most sensible approach is to add the required privacy key to the info.plist.
This is the info.plist xml definition although it's easier to add the keys in the property list:
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Message requesting the ability to add to the photo library</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Message requestion the ability to access the photo library</string>
If you add these then when you first try to access or add to the photo library a popup will display with your message allowing the user to decide if they want your app to have access.
One good reason to put it in the info.plist file is that all the requests for access are then in a single easily visible place instead of somewhere random in your project.
EDIT
Here is how to save the image in documents which does not raise and privacy issues:
NSData *imageData = UIImagePNGRepresentation(image);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"image.png"]; //Add the file name
[imageData writeToFile:filePath atomically:YES]; //Write the file
If you want a jpg instead of a png use this instead:
NSData *imageData = UIImageJPEGRepresentation(image, 0.9); // Use whatever compression ratio you want instead of 0.9