diff --git a/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo-Info.plist b/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo-Info.plist index c1e5e66..e9d2540 100644 --- a/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo-Info.plist +++ b/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo-Info.plist @@ -39,11 +39,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.5 + 1.1.3 CFBundleSignature ???? CFBundleVersion - 105 + 113 LSRequiresIPhoneOS UIRequiredDeviceCapabilities diff --git a/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/Controllers/PhotosTableViewController.m b/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/Controllers/PhotosTableViewController.m index cf9723d..aa24936 100644 --- a/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/Controllers/PhotosTableViewController.m +++ b/Demo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/ALAssetsLibraryCustomPhotoAlbum_BasicDemo/Controllers/PhotosTableViewController.m @@ -9,9 +9,7 @@ #import "PhotosTableViewController.h" #import "PhotoViewController.h" - #import "ALAssetsLibrary+CustomPhotoAlbum.h" - #import @@ -21,25 +19,28 @@ @interface PhotosTableViewController () { @private - ALAssetsLibrary * assetsLibrary_; - NSMutableArray * photos_; + ALAssetsLibrary * assetsLibrary_; + NSMutableArray * photos_; + UIImagePickerController * picker_; + PhotoViewController * photoViewController_; } -@property (nonatomic, strong) ALAssetsLibrary * assetsLibrary; -@property (nonatomic, copy) NSMutableArray * photos; +@property (nonatomic, strong) ALAssetsLibrary * assetsLibrary; +@property (nonatomic, copy) NSMutableArray * photos; +@property (nonatomic, strong) UIImagePickerController * picker; +@property (nonatomic, strong) PhotoViewController * photoViewController; - (void)_takePhoto:(id)sender; -- (BOOL)_startCameraControllerFromViewController:(UIViewController *)controller - usingDelegate:(id )delegate; @end @implementation PhotosTableViewController -@synthesize assetsLibrary = assetsLibrary_; -@synthesize photos = photos_; +@synthesize assetsLibrary = assetsLibrary_; +@synthesize photos = photos_; +@synthesize picker = picker_; +@synthesize parentViewController = photoViewController_; - (id)initWithStyle:(UITableViewStyle)style { @@ -71,7 +72,6 @@ - (void)viewDidLoad target:self action:@selector(_takePhoto:)]; [takePhotoButton setStyle:UIBarButtonItemStyleBordered]; - // [navigationController_.navigationItem setRightBarButtonItem:takePhotoButton]; [self.navigationItem setRightBarButtonItem:takePhotoButton]; } @@ -83,7 +83,54 @@ - (void)viewDidUnload - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. + assetsLibrary_ = nil; + picker_ = nil; + photoViewController_ = nil; +} + +#pragma mark - Custom Getter + +- (ALAssetsLibrary *)assetsLibrary +{ + if (assetsLibrary_) { + return assetsLibrary_; + } + assetsLibrary_ = [[ALAssetsLibrary alloc] init]; + return assetsLibrary_; +} + +- (UIImagePickerController *)picker +{ + if (picker_) { + return picker_; + } + + picker_ = [[UIImagePickerController alloc] init]; + picker_.sourceType = UIImagePickerControllerSourceTypeCamera; + + // Displays a control that allows the user to choose picture or + // movie capture, if both are available: + //picker.mediaTypes = + // [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]; + picker_.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage]; + + // Hides the controls for moving & scaling pictures, or for + // trimming movies. To instead show the controls, use YES. + picker_.allowsEditing = NO; + picker_.delegate = self; + + return picker_; +} + +- (PhotoViewController *)photoViewController +{ + if (photoViewController_) { + return photoViewController_; + } + photoViewController_ = [[PhotoViewController alloc] init]; + return photoViewController_; } #pragma mark - Table view data source @@ -119,11 +166,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - PhotoViewController * photoViewController = [[PhotoViewController alloc] init]; - [self.navigationController pushViewController:photoViewController animated:NO]; + [self.navigationController pushViewController:self.photoViewController animated:NO]; // Get image from Custom Photo Album for the selected photo url. - __weak PhotoViewController * weakPhotoViewController = photoViewController; + __weak PhotoViewController * weakPhotoViewController = self.photoViewController; [self.assetsLibrary assetForURL:[NSURL URLWithString:[self.photos objectAtIndex:indexPath.row]] resultBlock:^(ALAsset *asset) { // @@ -145,50 +191,22 @@ - (void) tableView:(UITableView *)tableView // Take photo - (void)_takePhoto:(id)sender { - if (! [self _startCameraControllerFromViewController:self - usingDelegate:self]) { - UIAlertView * alertView = [UIAlertView alloc]; - (void)[alertView initWithTitle:@"Camera Unavailable" - message:@"Sorry, camera unavailable for the current device." - delegate:self - cancelButtonTitle:@"Cancel" - otherButtonTitles:nil, nil]; - [alertView show]; + if (! [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { + [[[UIAlertView alloc] initWithTitle:@"Camera Unavailable" + message:@"Sorry, camera unavailable for the current device." + delegate:self + cancelButtonTitle:@"Cancel" + otherButtonTitles:nil, nil] show]; + return; } - return; -} - -// verifies the prerequisites are satisfied by way of its method signature -// and a conditional test, and goes on to instantiate, configure, -// and asynchronously present the camera user interface full screen -- (BOOL)_startCameraControllerFromViewController:(UIViewController *)controller - usingDelegate:(id )delegate -{ - if (([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO) - || delegate == nil - || controller == nil) return NO; - - UIImagePickerController * picker = [[UIImagePickerController alloc] init]; - picker.sourceType = UIImagePickerControllerSourceTypeCamera; - - // Displays a control that allows the user to choose picture or - // movie capture, if both are available: - //picker.mediaTypes = - // [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]; - picker.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage]; - - // Hides the controls for moving & scaling pictures, or for - // trimming movies. To instead show the controls, use YES. - picker.allowsEditing = NO; - picker.delegate = delegate; - - [controller presentModalViewController:picker animated:YES]; - // No need to release here, as it'll be released after camera action done - // in |imagePickerControllerDidCancel:| method - // [picker release]; - return YES; + if ([self.navigationController respondsToSelector: + @selector(presentViewController:animated:completion:)]) + { + [self.navigationController presentViewController:self.picker animated:YES completion:nil]; + } else { + [self.navigationController presentModalViewController:self.picker animated:YES]; + } } #pragma mark - UIImagePickerController Delegate @@ -196,104 +214,98 @@ - (BOOL)_startCameraControllerFromViewController:(UIViewController *)controller // For responding to the user tapping Cancel. - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { - // Prior to iOS 5.0, if a view did not have a parent view controller - // and was being presented modally, the view controller that was presenting - // it would be returned. - // This is no longer the case. You can get the presenting view controller - // using the presentingViewController property. - // - // Guess |parentViewController| is nil on iOS 5 and that is why the controller - // will not dismiss. - // Replacing |parentViewController| with |presentingViewController| will fix - // this issue. - // - // However, you'll have to check for the existence of presentingViewController - // on UIViewController to provide behavior for iOS versions < 5.0 - if ([picker respondsToSelector:@selector(presentingViewController)]) - [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; - else - [[picker parentViewController] dismissModalViewControllerAnimated:YES]; + if ([self.navigationController respondsToSelector: + @selector(presentViewController:animated:completion:)]) + { + [picker dismissViewControllerAnimated:YES completion:nil]; + } else { + // Prior to iOS 5.0, if a view did not have a parent view controller + // and was being presented modally, the view controller that was presenting + // it would be returned. + // This is no longer the case. You can get the presenting view controller + // using the presentingViewController property. + // + // Guess |parentViewController| is nil on iOS 5 and that is why the controller + // will not dismiss. + // Replacing |parentViewController| with |presentingViewController| will fix + // this issue. + // + // However, you'll have to check for the existence of presentingViewController + // on UIViewController to provide behavior for iOS versions < 5.0 + if ([picker respondsToSelector:@selector(presentingViewController)]) { + [[picker presentingViewController] dismissModalViewControllerAnimated:YES]; + } else { + [[picker parentViewController] dismissModalViewControllerAnimated:YES]; + } + } } // For responding to the user accepting a newly-captured picture or movie - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { - // dismiss image picker view + // Dismiss image picker view [self dismissModalViewControllerAnimated:YES]; - // manage the media (photo) + // Manage the media (photo) NSString * mediaType = [info objectForKey:UIImagePickerControllerMediaType]; - // Handle a still image capture - if (CFStringCompare((CFStringRef)mediaType, kUTTypeImage, 0) == kCFCompareEqualTo) { - // manage tasks in background thread - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - UIImage * imageToSave = nil; - UIImage * editedImage = (UIImage *)[info objectForKey:UIImagePickerControllerEditedImage]; - if (editedImage) imageToSave = editedImage; - else imageToSave = (UIImage *)[info objectForKey:UIImagePickerControllerOriginalImage]; - - UIImage * finalImageToSave = nil; - /* Modify image's size before save it to photos album - * - * CGSize sizeToSave = CGSizeMake(imageToSave.size.width, imageToSave.size.height); - * UIGraphicsBeginImageContextWithOptions(sizeToSave, NO, 0.f); - * [imageToSave drawInRect:CGRectMake(0.f, 0.f, sizeToSave.width, sizeToSave.height)]; - * finalImageToSave = UIGraphicsGetImageFromCurrentImageContext(); - * UIGraphicsEndImageContext(); - */ - finalImageToSave = imageToSave; - - /*/ Get the image metadata - UIImagePickerControllerSourceType pickerType = picker.sourceType; - if (pickerType == UIImagePickerControllerSourceTypeCamera) { - NSDictionary * imageMetadata = [info objectForKey:UIImagePickerControllerMediaMetadata]; - NSLog(@"%@", imageMetadata); - - // Get the assets library - ALAssetsLibrary * library = [[ALAssetsLibrary alloc] init]; - ALAssetsLibraryWriteImageCompletionBlock imageWriteCompletionBlock = - ^(NSURL *newURL, NSError *error) { - if (error) { - NSLog( @"Error writing image with metadata to Photo Library: %@", error ); - } else { - NSLog( @"Wrote image with metadata to Photo Library"); - } - }; - - // Save the new image (original or edited) to the Camera Roll - [library writeImageToSavedPhotosAlbum:[finalImageToSave CGImage] - metadata:imageMetadata - completionBlock:imageWriteCompletionBlock]; - }*/ - - // The completion block to be executed after image taking action process done - void (^completion)(NSURL *, NSError *) = ^(NSURL *assetURL, NSError *error) { - if (error) NSLog(@"!!!ERROR, write the image data to the assets library (camera roll): %@", - [error description]); - NSLog(@"*** URL %@ | %@ || type: %@ ***", assetURL, [assetURL absoluteString], [assetURL class]); - // Add new item to |photos_| & table view appropriately - NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.photos.count - inSection:0]; - [self.photos addObject:[assetURL absoluteString]]; + CFStringRef mediaTypeRef = (__bridge CFStringRef)mediaType; + if (CFStringCompare(mediaTypeRef, + kUTTypeImage, + kCFCompareCaseInsensitive) != kCFCompareEqualTo) + { + CFRelease(mediaTypeRef); + return; + } + CFRelease(mediaTypeRef); + + // Manage tasks in background thread + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + UIImage * imageToSave = nil; + UIImage * editedImage = (UIImage *)[info objectForKey:UIImagePickerControllerEditedImage]; + if (editedImage) imageToSave = editedImage; + else imageToSave = (UIImage *)[info objectForKey:UIImagePickerControllerOriginalImage]; + + UIImage * finalImageToSave = nil; + /* Modify image's size before save it to photos album + * + * CGSize sizeToSave = CGSizeMake(imageToSave.size.width, imageToSave.size.height); + * UIGraphicsBeginImageContextWithOptions(sizeToSave, NO, 0.f); + * [imageToSave drawInRect:CGRectMake(0.f, 0.f, sizeToSave.width, sizeToSave.height)]; + * finalImageToSave = UIGraphicsGetImageFromCurrentImageContext(); + * UIGraphicsEndImageContext(); + */ + finalImageToSave = imageToSave; + + // The completion block to be executed after image taking action process done + void (^completion)(NSURL *, NSError *) = ^(NSURL *assetURL, NSError *error) { + if (error) NSLog(@"!!!ERROR, write the image data to the assets library (camera roll): %@", + [error description]); + NSLog(@"*** URL %@ | %@ || type: %@ ***", assetURL, [assetURL absoluteString], [assetURL class]); + // Add new item to |photos_| & table view appropriately + NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.photos.count + inSection:0]; + [self.photos addObject:[assetURL absoluteString]]; + dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; - }; - - void (^failure)(NSError *) = ^(NSError *error) { - if (error == nil) return; - NSLog(@"!!!ERROR, failed to add the asset to the custom photo album: %@", [error description]); - }; - - // save image to custom photo album - if (! self.assetsLibrary) assetsLibrary_ = [[ALAssetsLibrary alloc] init]; - [self.assetsLibrary saveImage:finalImageToSave - toAlbum:kKYCustomPhotoAlbumName_ - completion:completion - failure:failure]; - }); - } + }); + }; + + void (^failure)(NSError *) = ^(NSError *error) { + if (error == nil) return; + NSLog(@"!!!ERROR, failed to add the asset to the custom photo album: %@", [error description]); + }; + + // Save image to custom photo album + // The lifetimes of objects you get back from a library instance are tied to + // the lifetime of the library instance. + [self.assetsLibrary saveImage:finalImageToSave + toAlbum:kKYCustomPhotoAlbumName_ + completion:completion + failure:failure]; + }); } @end