Cloning UIImagePickerController using the Assets Library Framework

    October 7th, 2010 Posted by: - posted under:Featured » Tutorials

    ELCImagePickerController.h

    #import
    #import
     
    @interface ELCImagePickerController : UINavigationController {
     
            id delegate;
    }
     
    @property (nonatomic, assign) id delegate;
     
    -(void)selectedAssets:(NSArray*)_assets;
    -(void)cancelImagePicker;
    -(id)initImagePicker;
     
    @end

    ELCImagePickerController.m

    #import "ELCImagePickerController.h"
     
    @implementation ELCImagePickerController
     
    @synthesize delegate;
     
    -(id)initImagePicker {
     
            if(self = [super init]) {
                    AlbumPickerController *albumController = [[AlbumPickerController alloc] initWithNibName:@"AlbumPickerController" bundle:[NSBundle mainBundle]];
                    [albumController setParent:self];
     
                    [super initWithRootViewController:albumController];
                    [albumController release];
            }
     
            return self;
    }
    -(void)cancelImagePicker {
     
            if([delegate respondsToSelector:@selector(elcImagePickerControllerDidCancel:)]) {
                    [delegate performSelector:@selector(elcImagePickerControllerDidCancel:) withObject:self];
            }
    }
     
    -(void)selectedAssets:(NSArray*)_assets {
     
            NSMutableArray *returnArray = [[NSMutableArray alloc] init];
     
            for(ALAsset *asset in _assets) {
                    NSMutableDictionary *workingDictionary = [[NSMutableDictionary alloc] init];
                    [workingDictionary setObject:[asset valueForProperty:ALAssetPropertyType] forKey:@"UIImagePickerControllerMediaType"];
                    [workingDictionary setObject:[UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]] forKey:@"UIImagePickerControllerOriginalImage"];
                    [workingDictionary setObject:[[asset valueForProperty:ALAssetPropertyURLs] valueForKey:[[[asset valueForProperty:ALAssetPropertyURLs] allKeys] objectAtIndex:0]] forKey:@"UIImagePickerControllerReferenceURL"];
     
                    [returnArray addObject:workingDictionary];
     
                    [workingDictionary release];
            }
     
            if([delegate respondsToSelector:@selector(elcImagePickerController:didFinishPickingMediaWithInfo:)]) {
                    [delegate performSelector:@selector(elcImagePickerController:didFinishPickingMediaWithInfo:) withObject:self withObject:[NSArray arrayWithArray:returnArray]];
            }
    }
     
    #pragma mark -
    #pragma mark Memory management
     
    - (void)didReceiveMemoryWarning {
        // Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
     
        // Release any cached data, images, etc that aren't in use.
    }
     
    - (void)viewDidUnload {
        [super viewDidUnload];
    }
     
    - (void)dealloc {
        [super dealloc];
    }
     
    @end

    The other callback methods (cancelImagePicker and selectedAssets:) will be discussed later in the post.

    Selecting an Album (ALAssetsGroup)

    The first table view we see is the AlbumPickerController. Here is the header to define that class

    @interface AlbumPickerController : UITableViewController {
     
            NSMutableArray *assetGroups;
            NSOperationQueue *queue;
            id parent;
    }
     
    @property (nonatomic, assign) id parent;
     
    -(void)preparePhotos;
    -(void)selectedAssets:(NSArray*)_assets;
     
    @end

    In the main first we fill in viewDidLoad. We first set the navigation controller to “Loading”. Next we create an NSOperation queue which calls an operation on preparePhotos. The preparePhotos method is where we will ask the AssetsLibrary Framework for the list of Albums I can get access from. Finally I add the dismiss button to the navigation bar. Use the code below.

    - (void)viewDidLoad {
        [super viewDidLoad];
     
        [self.navigationItem setTitle:@"Loading..."];
     
        queue = [NSOperationQueue mainQueue];
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(preparePhotos) object:nil];
        [queue addOperation:operation];
     
        UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss:)];
        [self.navigationItem setRightBarButtonItem:cancelButton];
        [cancelButton release];
    }

    Next we are going to define the dismiss method. This will call the cancelImagePicker method on out parent (ELCImagePickerController). We now get to the preparePhotos method. The first thing we do in this method is declare a block that we call assetGroupEnumerator. It takes an ALAssetGroup and a BOOL as parameters. The blocks checks the ALAssetGroup against nil and adds it to the NSArray class parameter assetGroups. At the end of the block I reload the table view. This is the block that I will use to enumerate through all the ALAssetGroups that the Assets Library Framework gives access to. After defining the block we instantiate the assetGroups array. Next we create an ALAssetsLibrary object. We call the method enumerateGroupsWithTypes:usingBlocks:filureBlocks: passing in assetGroupEnumberator the block we declared at the beginning of the method. We create a small block withing the method as the failureBlocks which will be called upon error. See the code below.

    -(void)dismiss:(id)sender {
     
            [parent cancelImagePicker];
    }
     
    -(void)preparePhotos {
     
            void (^assetGroupEnumerator)(struct ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
                    if(group != nil) {
                            [assetGroups addObject:group];
                            NSLog(@"Number of assets in group %d", [group numberOfAssets]);
                    }
     
                    [self performSelectorOnMainThread:@selector(reloadTableView) withObject:nil waitUntilDone:NO];
            };
     
            assetGroups = [[NSMutableArray alloc] init];
     
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
            [library enumerateGroupsWithTypes:ALAssetsGroupAll
                                                       usingBlock:assetGroupEnumerator
                                                     failureBlock:^(NSError *error) {
                                                             NSLog(@"A problem occured");
                                                     }];
            [library release];
    }

    Next we define the method that will be called when assets have been selected. This, like the dismiss button, makes a call up to our parent with the assets selected.

    -(void)selectedAssets:(NSArray*)_assets {
     
            [(ELCImagePickerController*)parent selectedAssets:_assets];
    }

    Next we define the methods to fill and control the tableview for our class. We will make a method to reload the table view. The table view will only have 1 section, and it will have as many rows as there are objects in the assetsGroup array. For each row we will set the text to the name of the album, followed by the number of photos within the album. Next we will set the imageView of the cell to the conveniently provided posterImage that is provided by ALAssetGroups. We make the cells a bit taller and we set the accessory to a Disclosure Indicator. Finally we define the method to handle when a cell is tapped. We will create an instance of our next table view (AssetTablePicker), pass the selected ALAssetGroup into it and push it onto the navigation stack. The rest of the AlbumPickerController class can be seen below.

    -(void)reloadTableView {
     
            [self.tableView reloadData];
            [self.navigationItem setTitle:@"Select an Album"];
    }
     
    -(void)selectedAssets:(NSArray*)_assets {
     
            [(ELCImagePickerController*)parent selectedAssets:_assets];
    }
     
    #pragma mark -
    #pragma mark Table view data source
     
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        // Return the number of sections.
        return 1;
    }
     
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        // Return the number of rows in the section.
        return [assetGroups count];
    }
     
    // Customize the appearance of table view cells.
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     
        static NSString *CellIdentifier = @"Cell";
     
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        }
     
        cell.textLabel.text = [NSString stringWithFormat:@"%@ (%d)",[(ALAsset*)[assetGroups objectAtIndex:indexPath.row] valueForProperty:ALAssetsGroupPropertyName], [(ALAssetsGroup*)[assetGroups objectAtIndex:indexPath.row] numberOfAssets]];
        [cell.imageView setImage:[UIImage imageWithCGImage:[(ALAssetsGroup*)[assetGroups objectAtIndex:indexPath.row] posterImage]]];
            [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
     
        return cell;
    }
     
    #pragma mark -
    #pragma mark Table view delegate
     
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     
            AssetTablePicker *picker = [[AssetTablePicker alloc] initWithNibName:@"AssetTablePicker" bundle:[NSBundle mainBundle]];
            [picker setParent:self];
            [picker setAssetsGroup:[assetGroups objectAtIndex:indexPath.row]];
            [self.navigationController pushViewController:picker animated:YES];
            [picker release];
    }
     
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
     
            return 57;
    }
     
    #pragma mark -
    #pragma mark Memory management
     
    - (void)didReceiveMemoryWarning {
        // Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
     
        // Relinquish ownership any cached data, images, etc that aren't in use.
    }
     
    - (void)viewDidUnload {
        // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
        // For example: self.myOutlet = nil;
    }
     
    - (void)dealloc {
     
            [assetGroups release];
        [super dealloc];
    }
     
    @end

    Pages: 1 2 3 4