I\'m trying to create a custom album in the Photo Library of an iPhone and then save photos that I\'ve taken with the camera, or chosen from the phones Camera Roll to that c
If you are using iOS6, Fernando's answer will not work, because the saveImage selector is no longer available.
The process is pretty confusing, and I have not seen any clear answers posted, so here is the method I've used to solve this in iOS6.
You will need to use a combination of the following:
Create the Album:
[self.library addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
NSLog(@"added album:%@", albumName);
}
failureBlock:^(NSError *error) {
NSLog(@"error adding album");
}];
Find the Album:
__block ALAssetsGroup* groupToAddTo;
[self.library enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if ([[group valueForProperty:ALAssetsGroupPropertyName] isEqualToString:albumName]) {
NSLog(@"found album %@", albumName);
groupToAddTo = group;
}
}
failureBlock:^(NSError* error) {
NSLog(@"failed to enumerate albums:\nError: %@", [error localizedDescription]);
}];
Save the Image to Asset Library, and put it into the album:
CGImageRef img = [image CGImage];
[self.library writeImageToSavedPhotosAlbum:img
metadata:[info objectForKey:UIImagePickerControllerMediaMetadata]
completionBlock:^(NSURL* assetURL, NSError* error) {
if (error.code == 0) {
NSLog(@"saved image completed:\nurl: %@", assetURL);
// try to get the asset
[self.library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
// assign the photo to the album
[groupToAddTo addAsset:asset];
NSLog(@"Added %@ to %@", [[asset defaultRepresentation] filename], albumName);
}
failureBlock:^(NSError* error) {
NSLog(@"failed to retrieve image asset:\nError: %@ ", [error localizedDescription]);
}];
}
else {
NSLog(@"saved image failed.\nerror code %i\n%@", error.code, [error localizedDescription]);
}
}];
The code from @Scott Allen was close but would not save the image for me the first time. So if I did not already have the album created, the image would not save. My solution was to move this snippet that creates the album to the app delegate didFinishLaunchingWithOptions:
NSString *albumName=@"album name";
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library addAssetsGroupAlbumWithName:albumName
resultBlock:^(ALAssetsGroup *group) {
NSLog(@"added album:%@", albumName);
}
failureBlock:^(NSError *error) {
NSLog(@"error adding album");
}];
Fernando's answer worked for me in iOS 7.
Steps :
1) Download the ALAssetsLibrary+CustomPhotoAlbum code from here: http://www.touch-code-magazine.com/wp-content/uploads/2011/11/ALAssetsLibrary_CustomPhotoAlbum.zip?a071b6 and copy the 2 files for the category inside your Xcode project.
2)In your header file,add the following lines
#import <AssetsLibrary/AssetsLibrary.h>
#import "ALAssetsLibrary+CustomPhotoAlbum.h"
@property (strong, atomic) ALAssetsLibrary* library;
3) In your implementation file,add the following lines
@synthesize library=_library;
EDIT: 4) initialise the asset library instance, preferably in "viewDidLoad" method, otherwise the saveImage method below won't execute. (CONFIRMED):
[I am resubmitting the suggested edit because someone with non-iphone skills rejected the previous submission. This is undoubtedly a great answer by @santhu & Fernando and helped me a lot, however, the initialisation piece of code was missing so it took me a bit of time to figure out why the code didn't work. Hence, I would appreciate if a moderator with iPhone development skillset reviews the edit.]
_library = [[ALAssetsLibrary alloc] init];
5) Add this in the method where you wish to save
//Add this in the method where you wish to save
[self.library saveImage:(UIImage *) toAlbum:(NSString *) withCompletionBlock:^(NSError *error) {
if (error!=nil) {
NSLog(@"Big error: %@", [error description]);
}
}];
For swift users:- I made function to do the same thing.
declare closure outsize class definition (above class definition)
typealias CompletionHandler = (success:Bool!) -> Void
declare library variable inside class
var library:ALAssetsLibrary?;
initialize variable in viewDidLoad
library = ALAssetsLibrary();
method to add Image to Particular Album
func addImage(image:UIImage, metaData:NSDictionary, toAlbum albumName:String, handler:CompletionHandler){
library?.addAssetsGroupAlbumWithName(albumName, resultBlock: {(group:ALAssetsGroup!) -> Void in
print("\nAlbum Created:= \(albumName)");
/*-- Find Group --*/
var groupToAddTo:ALAssetsGroup?;
self.library?.enumerateGroupsWithTypes(ALAssetsGroupType(ALAssetsGroupAlbum),
usingBlock: { (group:ALAssetsGroup?, stop:UnsafeMutablePointer<ObjCBool>) -> Void in
if(group != nil){
if group!.valueForProperty(ALAssetsGroupPropertyName) as String == albumName{
groupToAddTo = group;
print("\nGroup Found \(group!.valueForProperty(ALAssetsGroupPropertyName))\n");
self.library?.writeImageToSavedPhotosAlbum(image.CGImage, metadata:metaData, completionBlock: {(assetURL:NSURL!,error:NSError!) -> Void in
if(error == nil){
self.library?.assetForURL(assetURL,
resultBlock: { (asset:ALAsset!) -> Void in
var yes:Bool? = groupToAddTo?.addAsset(asset);
if (yes == true){
handler(success: true);
}
},
failureBlock: { (error2:NSError!) -> Void in
print("Failed to add asset");
handler(success: false);
});
}
});
}
} /*Group Is Not nil*/
},
failureBlock: { (error:NSError!) -> Void in
print("Failed to find group");
handler(success: false);
});
}, failureBlock: { (error:NSError!) -> Void in
print("Failed to create \(error)");
handler(success: false);
});
}
call this method as :--
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]){
var image:UIImage = info[UIImagePickerControllerOriginalImage] as UIImage;
var metadata:NSDictionary = info[UIImagePickerControllerMediaMetadata] as NSDictionary;
self.addImage(image, metaData: metadata, toAlbum: "SwiftAlbum") { (success) -> Void in
print("Image Added : \(success)");
}
picker.dismissViewControllerAnimated(true, completion: nil);
}
I haven't seen really clear answers and code to these questions. For me, I wanted to make sure that the album was found or created, before I fire up the camera. This code seems to be about right, and I think it is a bit cleaner and easier to steal^H^H^H^H^Hstart from.
// find or create our photo album. If either works
// we fire up the camera. Crazy asynchronous code here.
__weak PhotoVC *weakSelf = self;
__block BOOL found = NO;
ALAssetsLibraryGroupsEnumerationResultsBlock
assetGroupEnumerator = ^(ALAssetsGroup *group, BOOL *stop){
if (group) {
NSString *thisGroup = [group valueForProperty:ALAssetsGroupPropertyName];
if ([album isEqualToString:thisGroup]) {
NSLog(@"album found!");
[weakSelf startCamera: group];
*stop = YES;
found = YES;
}
} else { // not found, create the album
if (found)
return;
NSLog(@"album not found, try making album");
ALAssetsLibraryGroupResultBlock addGroup =
^(ALAssetsGroup *group){
NSLog(@"album created");
[weakSelf startCamera: group];
};
ALAssetsLibraryAccessFailureBlock addGroupFailed =
^(NSError *err){
NSLog(@"add group failed: %@", [err localizedDescription]);
};
[library addAssetsGroupAlbumWithName:album resultBlock:addGroup failureBlock:addGroupFailed];
}
};
[library enumerateGroupsWithTypes:ALAssetsGroupAlbum
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {
NSLog(@"album access denied");
}];
Tom Duff's law: steal code whenever you can.