Asset Libraries and Blocks in iOS 4

July 8th, 2010 Posted by: Collin - posted under:Tutorials

iOS 4 presented a million billion new API’s by Apple’s count, but for this post I am going to show a quick demo of the new Assets Library API where you can now get to users photos and videos with more access than ever before. This new API relies on the new programming device called Blocks that has been introduced with iOS 4. Blocks are used through many of the new API’s as a kind of extended @selector. We will look into this new development device and make a small project to create our own UIImagePickerController. In the end we are going to create a tableview that is filled with all the photos within our library. Check out the video below or follow the steps typed out below.

Screencast

from on .

Creating the Project

Create a new project in xCode. Make it for the iPhone since this is an iOS 4 framework. A view based application will create a view controller for us, so lets use that. Call your project MyImagePicker.

Adding in the framework

This project will revolve around taking advantage of the AssetsLibrary framework introduced with iOS 4. Due to this you must have the newest xCode and iPhone SDK installed with iOS 4.0 support. If this is done you should be able to expand the frameworks folder of your project. Right click on UIKit.framework and select “Reveal in Finder”. This will open up the folder that contains all of the frameworks you can use in an iOS 4 project. Find AssetsLibrary.framework and drag into the Frameworks folder of your project. Once dragged in make sure that the Copy items into destination folder options is deselected and that it is set to recursively create groups for any added folders.

Using the framework with blocks

iOS 4.0 introduces a totally new programming concept for Objective C developers to take advantage of when creating their own code and when using Apple’s API. Blocks in the most simple terms are Objective C objects that are methods. A block uses the special character ^ to denote its beginning and is a required parameter of many of the API’s introduced within iOS 4.0. Apple has some great documentation on blocks, and how they conceptually fit into the current objective C landscape. You can see their concise but effective overview . For our purposes I am just going to review the simple syntax of a block.

Before we dive into blocks lets take a look at the AssetsLibrary framework methods that will require them. The general flow of the object access we will be doing is as follows.

We are going to create an ALAssetsLibrary and call a method on it that will enumerate through all the ALAssetsGroups it has access to. For every ALAssetsGroup we will call a method on it which will enumerate through the ALAssets it has access to. We will save each ALAsset into an array we will use to populate our tableview. The two different enumerations we are going to perform is where the blocks will come in. But lets first set up our view controller appropriately.

MyImagePickerViewController.h

#import <UIKit/UIKit.h>;
#import <AssetsLibrary/AssetsLibrary.h>;
@interface MyImagePickerViewController : UIViewController {
 
        IBOutlet UITableView *tableview;
        IBOutlet UIActivityIndicatorView *activity;
 
        NSMutableArray *assets;
}
 
@property (nonatomic, retain) IBOutlet UITableView *tableview;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activity;
 
@end

We are going be using the assets array here to hold the assets that we are going to pull using the AssetsLibrary Framework.

Now open up MyImagePickerViewController.xib and drag in a UITableView and a UIActivityIndicatorView. With these in place connect them to the IBOutlets you created for this class. Also make sure to connect the UITableViewDataSource and UITableViewDelegate to the MyImagePickerViewController as well. With that done we can start to use the AssetsLibrary Framework.

Using the Asset Library

Now we are going to use our AssetsLibrary framework. This will be done within the viewDidLoad method of your MyImagePickerViewController.m. Put the following code in there.

1 - (void)viewDidLoad {
2
3    [super viewDidLoad];
4    [activity startAnimating];
5
6    void (^assetEnumerator)(struct ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
7  if(result != NULL) {
8          NSLog(@"See Asset: %@", result);
9          [assets addObject:result];
10
11 }
12    };
13
14    void (^assetGroupEnumerator)(struct ALAssetsGroup *, BOOL *) =  ^(ALAssetsGroup *group, BOOL *stop) {
15 if(group != nil) {
16         [group enumerateAssetsUsingBlock:assetEnumerator];
17 }
18
19
20 [self.tableView reloadData];
21 [self.activity stopAnimating];
22 [self.activity setHidden:YES];
23    };
24
25    assets = [[NSMutableArray alloc] init];
26    library = [[ALAssetsLibrary alloc] init];
27    [library enumerateGroupsWithTypes:ALAssetsGroupAlbum
28                                    usingBlock:assetGroupEnumerator
29                                  failureBlock: ^(NSError *error) {
30                                          NSLog(@"Failure");
31                                  }];
32 }

We are going to be going though this code line by line. On line 4, we start animating our activity indicator. I will explain why we have to do that a little bit later. Lines 6 – 23 are the lines that will  declare the two blocks that we will use to fill our tableview with pictures. We are going to declare two blocks to use as parameters to methods within a ALAssetLibrary object and a ALAssetGroup object. The first method call we will make will be on our ALAssetLibrary object. So for the moment lets skip passed the block declarations and look at line 25. On line 25 we instantiate our NSMutableArray to hold the ALAssets that we will pull out from the AssetsLibrary. On line 26 we will create our ALAssetsLibrary object. We will call a single method on this object to loop through all of the assets in a library. The method is:

– enumerateGroupsWithTypes:usingBlock:failureBlock:

This method takes in 3 parameters. An ALAssetGroup type, a block to be performed on each group and a block to be performed on failure. Lets talk about block syntax. A block is a native Objective C object. It is a subclass of NSObject. With that said it is also an Objective C method. An objective C method is composed of three things. A return type, a parameter list and a piece of code to be executed. We are going to pass the assetsGroupEnumerator block object that declare on line 14 into this method. Lets take a look at how the block is declared.

You begin by specifying a return type for the block. Void in this case. Next you enclose a name for the block which is proceeded by a carrot ^ character. This is the special character Apple has decided on to denote blocks. You begin block names with blocks as well as the actual declaration of what a block is. This name is wrapped in parenthesis. This is followed by the parameter list that the block will accept. In this case it is a ALAssetsGroup object and a Boolean indicating whether to stop. Now I did not come up with these parameters by myself. Since I will be passing this block into an ASAssetLibrary the documentation will tell us what will be passed into the block. ALAssetsLibrary objects documentation can be seen . With that all said, lets take a look at the code that will actually compose this block. Starting on line 15 we will make sure that we are seeing a valid group. If the ALAssetsGroup object that we are passed is valid then we will call another enumeration on the group which will enumerate through assets. This enumeration method also requires a block. We declared this block above. This block is called assetEnumerator. Once again we retrieved the parameters list from the documentation of the object asking for, in this case an .

For this block, which begins on line 6, the block is passed an ALAsset object, an index and a stopping condition boolean. Within the code of the block we will ensure that the returned ALAsset is valid and if it is we will add it to our array which will hold all of our assets. With this block declared we pass it into the call to our ALAssetsLibrary object on line 16.  Once every group has been enumerated and our array is filled with all of our ALAssets we will tell the tableview to reload its data and get rid of our UIActivityIndicatorView.

With all of this done all that remains if filling in the required UITableViewDataSource methods. The tableview will be filled with the assets we collected. ALAsset objects are cool in that they include a method called -thumbnail which returns a CGImageRef to a thumbnail we will use. I won’t explain the development of these methods any further since they are pretty straight forward.

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
 
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [assets 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];
    }
 
        ALAsset *asset = [assets objectAtIndex:indexPath.row];
        [cell.imageView setImage:[UIImage imageWithCGImage:[asset thumbnail]]];
        [cell.textLabel setText:[NSString stringWithFormat:@"Photo %d", indexPath.row+1]];
 
    return cell;
}
  • http://icode.dreamvision-soft.com/blog/?p=60 Asset Libraries and Blocks in iOS 4 | iCode

    [...] Original post on iCodeBlog [...]

  • Shaun

    Hey,

    Nice tutorial! I have a slight issue though – this works for me in the iPhone Simulator but not on my iPhone itself – it’s a 3GS upgraded to iOS4 – should this be working for me, do you know? When I had no images saved on the Simulator, I got ‘Failure’ in the console, and that’s exactly what I get on the device, even though I have a few images saved, both in the Image Library and in Camera Roll. When I create an image on the simulator, like you do in this tutorial, I get the expected fixed console output, and everything works fine.

    Cheers

  • http://adamburkepile.com Adam Burkepile

    Very nice tutorial; good example of block use and the asset framework.

  • Shaun

    Okay, I turned on Location Services (had it completely turned off) because I saw a similar issue on another site, where someone was explicitly dealing with location information on those images. Can you tell me if that is a given when using the ALAssetLibrary? Is there no way to access images or assets belonging to the device without it being inherently tied with Location Services?
    Also, any thoughts on what could be done if Location Services is disabled? Is there a way to discern that the reason for the failure was only that the Location Services were turned off? Not by checking that Location Services are on before beginning (though that would be a reasonable alternative) but to know when it does fail that it’s because of Location Services! (I’ll now go and check for this myself, it’s just to get some discussion going!)

    Cheers

  • Sumir Bharati

    Hi Collin,

    Can you pls tell me how to get synced images using asset library.
    Iam able to see [ Asset thumbnails] works but when [ representation fullscreenimage]
    doesnt work for those images who are synced.

    Note:First time when application launched (and it asks user that “Application wants to user your current location”) all images are shown and works perfectly but at runtime if i sync new images it doesnt work in case of fullscrren but thumbnail can be seen.

  • satish

    Great tutorial, well explained.

    Cheers

  • Sumir Bharati

    Anybody got success in getting fullscreen images of synced photos from library.

  • Mors Venit

    Sumir I’m having the same problem. I’m accessing the ALAsset and inserting it into a UIScrollView. (I’m still a noob) but I am able to get the images to load as they are going into my array. I think its the way I’m calling them into the UIImage that’s the problem. If you watch his video he mentions that the thumbnail instance is outputed w an imageWithCGImage.

    [[cell imageView] setImage:[UIImage imageWithCGImage:[[assets objectAtIndex:indexPath.row] thumbnail]]];

    I”m reading thru the documentation in both the ALAsset and UIImage documents to find my answer. If you resolve the issue please drop a post here.

    thanks!!

  • Sumir Bharati

    hey mors ..got any solution?

  • http://ryanlopez.me ryan

    I’m able to load images with the asset framework. I’ve noticed that access to the photos is slow sometimes, but fast other times. Does anyone know if this is common with the asset library? Does anyone know why there is a delay with enumerating assets?

  • http://icodeblog.com/2010/09/07/cloning-uiimagepickercontroller-using-the-assets-library-framework/ Cloning UIImagePickerController using the Assets Library Framework | iCodeBlog

    [...] iCoders. This is a follow up post to my initial post on the Assets Library Framework and Blocks. We came across an interesting problem when working on the application for Animoto.com. They have [...]

  • http://icode.dreamvision-soft.com/blog/?p=83 Cloning UIImagePickerController using the Assets Library Framework | iCode

    [...] iCoders. This is a follow up post to my initial post on the Assets Library Framework and Blocks. We came across an interesting problem when working on the application for Animoto.com. They have [...]

  • http://www.ios4jailbreak.com/2010/09/cloning-uiimagepickercontroller-using-the-assets-library-framework/ iOS4 Jailbreak » Cloning UIImagePickerController using the Assets Library Framework

    [...] iCoders. This is a follow up post to my initial post on the Assets Library Framework and Blocks. We came across an interesting problem when working on the application for Animoto.com. They have [...]

  • Mughila

    Hai,
    I have used your code for photo library now in the advanced part selecting multiple rows in the table and moving the selected rows another view’s table .The problem is the index path remains the same after some count i.e., the indexpath for row 1 and row 11 are same.Please help me with it.

    Thanks

  • bangdel

    Hey, great tutorial! Excellent for beginners in ALAsset Framework… I have one question though. You have shown how to access the thumbnail using [asset thumbnail] but how are we to access the actual image? I tired using the ALAsset object URLs but to avail. Please help…

  • http://iphonetuts.com/?p=107091 Cloning UIImagePickerController using the Assets Library Framework | Iphone tutorials

    [...] iCoders. This is a follow up post to my initial post on the Assets Library Framework and Blocks. We came across an interesting problem when working on the application for Animoto.com. They have [...]

  • http://www.chriszamanillo.com/2009/01/cloning-uiimagepickercontroller-using-the-assets-library-framework/ CHRISZAMANILLO.COM :: Cloning UIImagePickerController using the Assets Library Framework :: http://www.chriszamanillo.com

    [...] iCoders. This is a follow up post to my initial post on the Assets Library Framework and Blocks. We came across an interesting problem when working on the application for Animoto.com. They have [...]

  • Sneha

    i want to access image and video through url but unable to do so can anyone help!!!!

  • http://alones.kr/2284 [iPhone Dev] Asset Libraries and Blocks in iOS 4 | Alones world

    [...] Asset Libraries and Blocks in iOS 4 [...]

  • http://alones.kr/2290 links for 2011-01-10 | Alones world

    [...] Asset Libraries and Blocks in iOS 4 | iCodeBlog Asset Libraries and Blocks in iOS 4 (tags: assets lib) [...]

  • Adam

    Nice, love this site.

  • sam

    Hi there!
    First of all thanks for your tutorial, It helped me find an entry into the Asset Library.
    I sucessfully managed to gain acces to synced photoalbums, however I failed at accessing the iphone camera roll.
    Even if I use enumerateGroupsWithTypes:ALAssetsGroupAll i just get the images from within all albums, but no the pictures I actually took with my iPhone. …

    Do you have any thoughts on that issue??

    thank you very much.
    cheers,
    sam