Tuesday 5 March 2013

Cloning UIImagePickerController using the Assets Library Framework

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 had an app in the store since the very early days of the app store, and one of our biggest struggles has been creating at interface to allow users to select multiple photos from their photo album for a slideshow. While the iPhone photos application allows for this, the UIImagePicker does not. With the release of the Assets Library framework we can now recreate the experience of the UIImagePicker, with some additional custom functionality to fit our needs. As a result we created a new cloned version of the UIImagePicker that Allows for multiple photo selection just like the photos app We have decided to open source the controller for other developers to use. This post will explain the process of creating the new image picker as well as the method of incorporating it into your code.

The ELCImagePickerController

The ELCImagePickerController is only possible because of the newly Introduced Assets Library framework. This framework gives you raw (more or less) access to the photo and video elements of a user. We looked at UIImagePickerController and saw a lot of weaknesses with it. You can only select one photo at a time, and even in Apple's photo app, where you can choose several pictures at a time, you can not use multitouch to do your selection. To solve these problems we rolled our own solution that works very closely to UIImagePickerController.

How to use it

First I am going to explain using the picker since to many people the process of creating it will not be very interesting. The image picker is created and displayed in a very similar manner to the UIImagePickerController. The sample application that is part of the GitHub project, where I distribute the controller, shows its use, but I will go into detail here. To display the controller you instantiate it and display it modally like Sun
ELCImagePickerController * controller = [[ELCImagePickerController alloc] init image picker];
[Controller setDelegate: self];
[Self presentModalViewController: controller animated: YES];
[Release];
The ELCImagePickerController will return select the images back to the ELCImagePickerControllerDelegate. The delegate contains to methods very similar to the UIImagePickerControllerDelegate. Instead of returning one dictionary representing a single image the controller sends back an array of similarly structured dictionaries. The two delegate methods are:]
-  ( void ) elcImagePickerController : ( ELCImagePickerController * ) picker  

GIT Hub

You can find this project now on GitHub . Please let me know any issues you may have and look for future releases with feature enhancements

General Structure

The ELCImagePicker is a collection of UITableViewControllers that are placed inside a UINavigationController. While the ELCImagePickerController is actually 5 separate custom classes I have written, I have put them all within a single header and main.I chose this to make the classes that were required to be imported into a project when using this as few as possible. While usually when presenting a UINavigationController you would create one yourself in code and use the initWithRootViewController method, in this case we have created a UINavigationController subclass called ELCImagePickerController Which does all this behind the scenes. In the end all a developer has to do is use the init method and present the image picker controller modally. This lets the class match the functionality of UIImagePickerController closer. You can see the Header and Main for the ELCImagePickerController class on the next page.

# Import 
# import
 
@ Interface ELCImagePickerController : UINavigationController {
 
 id delegate;
 }
 
@ Property  ( nonatomic, assign )  id delegate;
 
- ( void ) selectedAssets : ( NSArray * ) _assets;
 - ( void ) cancelImagePicker;
 - ( id ) init image picker;
 
@ End

ELCImagePickerController.m

# Import "ELCImagePickerController.h"
 
@ Implementation ELCImagePickerController
 
@ Synthesize delegate;
 
- ( id ) init image picker {
 
 if ( self =  [ super init ] )  { 
  album picker controller * album controller =  [ [ Album Picker alloc ] initWithNibName : @ "Album Picker Controller" bundle : [ NSBundle main bundle ] ] ,
   [ album controller SetParent : self ] ;
 
  [ super initWithRootViewController : controller album ] ,
   [ album controller release ] ;
  }
 
 return self;
 }
- ( void ) cancelImagePicker {
 
 if ( [ delegate respondsToSelector : @ selector ( elcImagePickerControllerDidCancel : ) ] )  { 
  [ delegate performSelector : @ selector ( elcImagePickerControllerDidCancel : ) withObject : self ] ;
  } 
}
 
- ( void ) selectedAssets : ( NSArray * ) _assets {
 
 NSMutableArray  * return array =  [ [ NSMutableArray alloc ] init ] ;
 
 setObject : [ asset valueForProperty : ALAssetPropertyType ] forKey : @ "UIImagePickerControllerMediaType" ] ,
   [ working dictionary setObject : [ UIImage imageWithCGImage : [ [ asset setObject : [ [ asset valueForProperty : ALAssetPropertyURLs ] valueForKey : [ [ [ asset 
    
 
  [ return array addObject : working dictionary ] ;
 
  [ working dictionary release ] ;
  }
 
 if ( [ delegate respondsToSelector : @ selector ( elcImagePickerController : didFinishPickingMediaWithInfo : ) ] )  { 
  [ delegate performSelector : @ selector ( elcImagePickerController : didFinishPickingMediaWithInfo : ) withObject : self withObject : [ NSArray array with array : return array ] ] ;
  } 
}
 
# Pragma mark - 
# pragma mark Memory management
 
-  ( void ) didReceiveMemoryWarning { 
    / / Releases the view if it does not have a superview. 
    [ super didReceiveMemoryWarning ] ;
 
    / / Release any cached data, images, etc that are not 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 album Picker controller. Here is the header to define that class
@ Interface album picker controller : UITableViewController {
 
 NSMutableArray  * asset groups;
  NSOperationQueue  * queue,
  id parent;
 }
 
@ Property  ( nonatomic, assign )  id parent;
 
- ( void ) preparePhotos;
 - ( void ) selectedAssets : ( NSArray * ) _assets;
 
@ End
In the main we first fill in viewDidLoad. We first set the navigation controller to "Loading". Next we create an NSOperation queue Which calls to surgery on preparePhotos. The preparePhotos method is where we will ask the Asset Library Framework for the list of album 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 ..." ] ;
 selector : @ selector ( preparePhotos ) object : nil ] ;
     [ queue addOperation : surgery ] ;   
 
    UIBarButtonItem * cancelButton =  [ [ UIBarButtonItem alloc ] initWithBarButtonSystemItem : UIBarButtonSystemItemCancel target : self action : @ selector ( dismiss : ) ] ,
     [ self.navigationItem setRightBarButtonItem : cancelButton ] ,
     [ cancelButton release ] ;
 }
Next we are going to define the method dismiss. This will call the method on cancelImagePicker 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 at ALAssetGroup and a BOOL as parameters.The block checks the ALAssetGroup against nil and adds it to the NSArray class parameter asset groups. 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 asset groups array. Next we create at ALAssetsLibrary object. We call the method enumerateGroupsWithTypes: using blocks: filureBlocks: passing assetGroupEnumberator in the block we declared at the beginning of the method.We create a small block withing the method as the failure blocks whichwill be called upon error. See the code below.
- ( void ) dismiss : ( id ) sender {
 
 [ parent cancelImagePicker ] ;
 }
 
- ( void ) preparePhotos {
 
  addObject : group ] ;     
    
   
   NSLog ( @ "Number of assets in group% d" , [ group numberOfAssets ] ) ;
   }
 
  [ self performSelectorOnMainThread : @ selector ( tableView reload ) withObject : nil waitUntilDone : NO ] ;
  } ;
 
 asset groups =  [ [ NSMutableArray alloc ] init ] ;
 
 ALAssetsLibrary * library =  [ [ ALAssetsLibrary alloc ] init ] ;
  [ library enumerateGroupsWithTypes : ALAssetsGroupAll
         using block : assetGroupEnumerator
       failure block : ^ ( NSError  * error )  { 
        NSLog ( @ "A problem occurred" ) ;
        } ] ,
  [ 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 selected assets.
- ( void ) selectedAssets : ( NSArray * ) _assets {
 
 [ ( ELCImagePickerController * ) parent selectedAssets : _assets ] ;
 }
Next we define the methods to fill and control the table view for our class. We will make a method to reload the tableView. The tableView will only have one section, and it will have as many rows as there are objects in the asset group 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 image view of the cell to the conveniently provided poster image 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. At instance of our next tableView (Table Asset Picker), pass the selected ALAssetGroup into it and push it onto the navigation stack The rest of the album picker controller class can be seen below.
- ( void ) tableView reload {
 
 [ 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  [ asset groups count ] ;
 }
 
/ / Customize the appearance of table view cells. 
-  ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath  * ) indexPath {
 
    static  NSString  * Cell Identifier =  @ "Cell" ;
 
    UITableViewCell * cell =  [ tableView dequeueReusableCellWithIdentifier : Cell Identifier ] ,
     if  ( cell ==  nil )  { 
        cell =  [ [ [ UITableViewCell alloc ] initWithFrame style : UITableViewCellStyleDefault reuse identifier : Cell identifier ] autorelease ] ;
     }
 
    cell.textLabel.text =  [ NSString stringWithFormat : @ "% @ (% d)" , [ ( ALAsset * ) [ asset groups objectAtIndex : indexPath.row ] numberOfAssets ] ] ,
     [ cell.imageView setImage : [ UIImage imageWithCGImage : [ ( ALAssetsGroup * ) [ asset groups objectAtIndex : indexPath.row ] poster image ] ] ] ,
  [ cell setAccessoryType : UITableViewCellAccessoryDisclosureIndicator ] ;
 
    return cell;
 }
 
# Pragma mark - 
# pragma mark Table view delegate
 
-  ( void ) tableView : ( UITableView * ) tableView didSelectRowAtIndexPath : ( NSIndexPath  * ) indexPath {
 
 Asset Table Picker * picker =  [ [ Asset Table Picker alloc ] initWithNibName : @ "Asset Table Picker" bundle : [ NSBundle main bundle ] ] ,
  [ picker SetParent : self ] ;
  [ picker setAssetsGroup : [ asset groups 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 does not have a superview. 
    [ super didReceiveMemoryWarning ] ;
 
    / / Relinquish ownership any cached data, images, etc that are not in use. 
}
 
-  ( void ) viewDidUnload { 
    . / / Relinquish ownership of anything that can be recreated in viewDidLoad or on demand 
    / / For example: self.myOutlet = nil; 
}
 
-  ( void ) dealloc {
 
 [ asset groups release ] ;
     [ super dealloc ] ;
 }
 
@ End


The second table view we see is the Asset table picker. Here is the header to define that class
@ Interface Table Asset Picker : UITableViewController
 { 
 ALAssetsGroup * asset group;
 
 NSMutableArray  * assets;
  NSMutableArray  * assetURLDictionaries;
  int selectedAssets;
 
 id parent;
 
 NSOperationQueue  * queue;
 }
 
@ Property  ( nonatomic, retain ) IBOutlet UILabel * selectedAssetsLabel;
 @ property  ( nonatomic, assign )  id parent;
 
- ( void ) setAssetsGroup : ( ALAssetsGroup * ) _Group;
 - ( IBAction ) dismiss : ( id ) sender;
 
@ End
This class is a bit more complicated than the album picker, but despite its complexity, its basic principals are similar. It has the same properties as the class with the addition of AlbumPickerConrtroller an array to keep track of the URLs of all the assets it encounters. Lets get into the main and see exactly what happen to fill this table. First in the view didLoad we do some house keeping with the navigation controller and call the method preparePhotos in the background. Since we are calling preparePhotos to run in the background the first thing we must do is to declare NSAutoreleasePool, at the end we will release it. This helps manage background operations within iOS. Next to prepare photos, we do the same as we did in Operation album picker controller except this time we add assets to the array assets.The asset object is instantiated with an object and ALAsset is a UIView subclass. It will be covered in greater detail later in this post Every time we see an asset we add its URL to the assetURLDictionaries array. This is due to accidental duplicates handed back from the Assets Library Framework. It is. An odd workaround now, but seems to work fine With that done we reload the table view.
@ Implementation Table Asset Picker
 
@ Synthesize parent;
 @ synthesize selectedAssetsLabel;
 
- ( void ) viewDidLoad {
 
 [ self.tableView setSeparatorColor : [ UIColor clearColor ] ] ,
  [ self.tableView setAllowsSelection : NO ] ;
 
 UIBarButtonItem * doneButtonItem =  [ [ UIBarButtonItem alloc ] initWithBarButtonSystemItem : UIBarButtonSystemItemDone target : self action : @ selector ( dismiss : ) ] ,
  [ self.navigationItem setRightBarButtonItem : doneButtonItem ] ,
  [ self.navigationItem setTitle : @ "Loading ..." ] ;
 
 [ self performSelectorInBackground : @ selector ( preparePhotos ) withObject : nil ] ;
 }
 
-  ( void ) setAssetsGroup : ( ALAssetsGroup * ) _Group {
 
 asset group = _Group;
 }
 
- ( void ) preparePhotos {
 
 NSAutoreleasePool  * pool =  [ [ NSAutoreleasePool alloc ] init ] ;
 
 void  ( ^ assetEnumerator ) ( struct ALAsset * , NSUInteger, BOOL  * )  =  ^ ( ALAsset * result, NSUInteger index, BOOL  * stop )  {
 
  if ( result ! =  nil )  {
 
   if ( ! [ assetURLDictionaries containment object : [ result valueForProperty : ALAssetPropertyURLs ] ] )  { 
    if ( ! [ [ result valueForProperty : ALAssetPropertyType ] isEqualToString : ALAssetTypeVideo ] )  { 
     [ assetURLDictionaries addObject : [ result valueForProperty : ALAssetPropertyURLs ] ] ;
     Asset * asset =  [ [ Asset alloc ] initWithFrame asset : result ] ;
      [ assets addObject : asset ] ;
     } 
   } 
  } 
 } ;
 
 assets =  [ [ NSMutableArray alloc ] init ] ;
 assetURLDictionaries =  [ [ NSMutableArray alloc ] init ] ;
 
 [ asset group enumerateAssetsUsingBlock : assetEnumerator ] ;
 
 [ self.tableView reloadData ] ;
  [ self.navigationItem setTitle : @ "Pick photos" ] ;
 
 [ pool release ] ;
 }
So now we are at a point where we have an array (assets) of all the ALAssets ALAssetGroup Represented in the selected objects as assets. We now have to figure out a way to display thumbnails of each of these images (4 per row). In a tableViewWe will accomplish this be creating a custom UITableViewCell that we will call Asset Cell. An asset cell will accept an array of Asset objects and utilize it as the UIView subclass that it is to lay them out. We will get to that in the next section, but it is important to know now as we need to create the method that will prepare the subarray of assets that we will pass to our asset Cell cells. This method is called assetsForIndexPath. The method will look at the index path and then convert it to the indices of the actual objects ALAsset the index path will be displaying. After it has done this it checks that it is not going to look for more assets then there are in the array. This method will always return. An array of size 4 except for the last row of the table view whichwill be either 1, 2, 3 or 4 assets in length See the code below.
- ( NSArray * ) assetsForIndexPath : ( NSIndexPath * ) _indexPath {
 
 int index =  ( _indexPath.row * 4 ) ;
  int MaxIndex =  ( _indexPath.row * 4 + 3 ) ;
 
 if ( MaxIndex & lt; [ assets count ] )  {
 
  return  [ NSArray arrayWithObjects : [ assets objectAtIndex : index ] ,
     [ assets objectAtIndex : index + 1 ] ,
     [ assets objectAtIndex : index + 2 ] ,
     [ assets objectAtIndex : index + 3 ] ,
     nil ] ;
  }
 
 else  if ( MaxIndex - 1  & lt; [ assets count ] )  {
 
  return  [ NSArray arrayWithObjects : [ assets objectAtIndex : index ] ,
     [ assets objectAtIndex : index + 1 ] ,
     [ assets objectAtIndex : index + 2 ] ,
     nil ] ;
  }
 
 else  if ( MaxIndex - 2  & lt; [ assets count ] )  {
 
  return  [ NSArray arrayWithObjects : [ assets objectAtIndex : index ] ,
     [ assets objectAtIndex : index + 1 ] ,
     nil ] ;
  }
 
 else  if ( MaxIndex - 3  & lt; [ assets count ] )  {
 
  return  [ NSArray arrayWithObject : [ assets objectAtIndex : index ] ] ;
  }
 
 return  nil ;
 }
With this convenience method in place we can move into the UITableViewDataSource methods for this tableView. # In which the way we get it to look so unlike a normal table view will become clear when we look into the implementation of the asset and the asset Cell UITableViewCell UIView. For now we will just inject the asset Cells with the arrays provided by our assetsForIndexPath method.
# Pragma mark UITableViewDataSource Delegate Methods
 
-  ( 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  ceil ( [ count assets ] / 4.0 ) ;
 }
 
/ / Customize the appearance of table view cells. 
-  ( UITableViewCell * ) tableView : ( UITableView * ) tableView cellForRowAtIndexPath : ( NSIndexPath  * ) indexPath {
 
    static  NSString  * Cell Identifier =  @ "Cell" ;
 
    Asset Cell * cell =  ( Asset Cell * ) [ tableView dequeueReusableCellWithIdentifier : Cell Identifier ] ,
     if  ( cell ==  nil )  {
 
        cell =  [ [ [ Cell Asset alloc ] initWithFrame assets : [ self assetsForIndexPath : indexPath ] reuse identifier : Cell identifier ] autorelease ] ;
     }
 
 else  {
 
  [ cell setAssets : [ self assetsForIndexPath : indexPath ] ] ;
  }
 
    return cell;
 }
 
-  ( CGFloat ) tableView : ( UITableView * ) tableView heightForRowAtIndexPath : ( NSIndexPath  * ) indexPath {
 
 return  79 ;
 }
 
-  ( void ) dealloc {
 
    [ super dealloc ] ;
 }
The final method contained within our Asset Table Picker is a method used when the user has selected all the assets that they want. This method looks through the assets we have within our assets array. An asset object has a class method called selected Which returns a BOOL. If the asset has been selected this will return true.We make a subarray of all the selected asset object, bundle them up and pass them to our parent (album picker controller). This will become clearer near the end of the post the code for the lake dismiss method below.
- ( IBAction ) dismiss : ( id ) sender {
 
 NSMutableArray  * selectedAssetsImages =  [ [ NSMutableArray alloc ] init ] ;
 
 for ( Asset * asset in assets )  {
 
  if ( [ asset selected ] )  {
 
   [ selectedAssetsImages addObject : [ asset asset ] ] ;
   } 
 }
 
 [ ( Album Picker Controller * ) parent selectedAssets : [ NSArray array with array : selectedAssetsImages ] ] ;
 }

Displaying assets using Asset Cell

The next class we encounter is asset Cell, a UITableViewCell subclass. The main header and can be see below. The only interesting code within this class is the code to layout each of the assets located in layout subviews. This method goes through every object Asset Which it was handed and Applies a frame to it. The UIImagePickerController has a 4 pixel border between each of the assets it lists. We do the same and smartly calculate the frame for each asset as the for loop executes.So within this loop we create a UITapGestureRecognizer for each asset object.Essentially we tell each asset view to call the method toggleSelection: on itself every time it is tapped. You will see the implementation of the toggleSelection method in a moment. For now see the code below for specifics on asset Cell.

AssetCell.h

@ Interface Asset Cell : UITableViewCell
 { 
 NSArray  * assets;
 }
 
- ( id ) initWithFrame assets : ( NSArray * ) _assets reuse identifier : ( NSString * ) _identifier;
 - ( void ) setAssets : ( NSArray * ) _assets;
 
@ End

AssetCell.m

@ Implementation Asset Cell
 
- ( id ) initWithFrame assets : ( NSArray * ) _assets reuse identifier : ( NSString * ) _identifier {
 
 if ( self =  [ super init with style : UITableViewStylePlain reuse identifier : _identifier ] )  {
 
  assets = _assets;
   [ assets retain ] ;
  }
 
 return self;
 }
 
- ( void ) setAssets : ( NSArray * ) _assets {
 
 for ( UIView * view in  [ self subviews ] )  {
 
  [ view removeFromSuperview ] ;
  }
 
 assets =  nil ;
 assets = _assets;
  [ assets retain ] ;
 }
 
- ( void ) layoutSubviews {
 
 CGRect frame = CGRectMake ( 4 , 2 , 75 , 75 ) ;
 
 for ( Asset * asset in assets )  {
 
  [ asset setFrame : frame ] ,
   [ asset addGestureRecognizer : [ [ UITapGestureRecognizer alloc ] initWithFrame target : asset action : @ selector ( toggleSelection ) ] ] ,
   [ self addSubview : asset ] ;
 
  frame.origin.x = frame.origin.x + frame.size.width +  4 ;
   [ asset release ] ;
  } 
}
 
- ( void ) dealloc {
 
 [ assets release ] ;
  [ super dealloc ] ;
 }
@ End

Asset is the final class Which Comprises the ELCImagePickerController. Asset is a UIView subclass Which takes in to ALAsset and creates a view that represents it. The final view will be a square thumbnail of the ALAsset that is passed in along with a check mark overlay that is very similar to the check mark used in Apple's Photos application. In Asset Cell we set up the UITapGestureRecognizer that wants to call this method whenever asset is tapped. ALAssets, Which We inject into. Asset to object when creating, have a convenience method called thumbnail that we can utilize to get the actual image that will represent the asset After adding to the view that we add the image view for the overlay and set it as hidden. Our toggleOverlay: method will check Whether that view is hidden. Finally we have a checker to see if the asset is selected with the method selected. If the overview is the hidden asset is not selected and if it is visible it is selected. All this comes together to form the final smarts we need to make our picker functional. See the header and main below.

Asset.h

@ Interface Asset : UIView { 
 ALAsset * asset;
 UIImageView * overlay view;
  BOOL selected;
  id parent;
 }
 
@ Property  ( nonatomic, retain ) ALAsset * asset;
 @ property  ( nonatomic, assign )  id parent;
 
- ( id ) initWithFrame asset : ( ALAsset * ) _asset;
 - ( BOOL ) selected;
 
@ End

Asset.m

@ Implementation Asset
 
@ Synthesize asset;
 @ synthesize parent;
 
-  ( id ) initWithFrame : ( CGRect ) frame { 
    if  ( ( self =  [ super initWithFrame : frame ] ) )  { 
        / / Initialization code 
    } 
    return self;
 }
 
- ( id ) initWithFrame asset : ( ALAsset * ) _asset {
 
 if  ( self =  [ super initWithFrame : CGRectMake ( 0 , 0 , 0 , 0 ) ] )  {
 
  asset = _asset;
   [ asset retain ] ;
 
  CGRect view frames = CGRectMake ( 0 , 0 , 75 , 75 ) ;
 
  UIImageView * asset imageview =  [ [ UIImageView alloc ] initWithFrame : view frames ] ,
   [ asset imageview setContentMode : UIViewContentModeScaleToFill ] ,
   [ asset imageView setImage : [ UIImage imageWithCGImage : [ asset thumbnail ] ] ] ;
 
  [ self addSubview : imageView asset ] ,
   [ asset imageView release ] ;
 
  overlay view =  [ [ UIImageView alloc ] initWithFrame : view frames ] ,
   [ overlay view setImage : [ UIImage imageNamed : @ "Overlay.png" ] ] ,
   [ overlay view setHidden : YES ] ;
   [ self addSubview : overlay view ] ;
     }
 
 return self;
 }
 
- ( void ) toggleSelection {
 
 overlayView.hidden =  ! overlayView.hidden;
 }
 
- ( BOOL ) selected {
 
 return  ! overlayView.hidden;
 }
 
- ( void ) setSelected : ( BOOL ) _Selected {
 
 [ overlay view setHidden !: _Selected ] ;
 }
 
-  ( void ) dealloc {
 
 [ asset release ] ;
  [ overlay view release ] ;
     [ super dealloc ] ;
 } 
@ end

Passing the Assets Back Up

So now that all the assets can be displayed and selected lets take a look at how they are passed up the chain. First thing to know is that the ELCImagePickerController passes up asset objects, since they contain references to the ALAsset Which they represent. With that said the place we start is in the Asset Table Picker. When I dismiss the class there is clicked dismiss calls the method which looks through the array and checks for assets which one is selected. It adds the selected asset objects to an array and then calls album picker controller selectedAssets: method. The selectedAssets method just passes along this array to the method ELCImagePickerController selectedAssets. Here a dictionary is constructed to represent every asset that was selected. The dictionary contains the same information that is delivered by UIImagePickerController when it delivers assets.This way the ELCImagePickerController can be included into projects as simply as possible. Below you will see each of the passback methods Described above as well as the definition of the ELCImagePickerControllerDelegate Which protocol defines the methods that should be implemented on the calling class.
- ( IBAction ) dismiss : ( id ) sender {
 
 NSMutableArray  * selectedAssetsImages =  [ [ NSMutableArray alloc ] init ] ;
 
 for ( Asset * asset in assets )  {
 
  if ( [ asset selected ] )  {
 
   [ selectedAssetsImages addObject : [ asset asset ] ] ;
   } 
 }
 
 [ ( Album Picker Controller * ) parent selectedAssets : [ NSArray array with array : selectedAssetsImages ] ] ;
 }
- ( void ) selectedAssets : ( NSArray * ) _assets {
 
 [ ( ELCImagePickerController * ) parent selectedAssets : _assets ] ;
 }
- ( void ) selectedAssets : ( NSArray * ) _assets {
 
 NSMutableArray  * return array =  [ [ NSMutableArray alloc ] init ] ;
 
 for ( ALAsset * asset in _assets )  {
 
  NSMutableDictionary  * working dictionary =  [ [ NSMutableDictionary alloc ] init ] ;
   [ working dictionary setObject : [ asset valueForProperty : ALAssetPropertyType ] forKey : @ "UIImagePickerControllerMediaType" ] ,
   [ working dictionary setObject : [ UIImage imageWithCGImage : [ [ asset setObject : [ [ asset valueForProperty : ALAssetPropertyURLs ] valueForKey : [ [ [ asset
 
  [ return array addObject : working dictionary ] ;
 
  [ working dictionary release ] ;
  }
 
 if ( [ delegate respondsToSelector : @ selector ( elcImagePickerController : didFinishPickingMediaWithInfo : ) ] )  { 
  [ delegate performSelector : @ selector ( elcImagePickerController : didFinishPickingMediaWithInfo : ) withObject : self withObject : [ NSArray array with array : return array ] ] ;
  } 
}
@ Protocol ELCImagePickerControllerDelegate
 
-  ( void ) elcImagePickerController : ( ELCImagePickerController * ) picker  
 
@ End

GIT Hub

You can find this project now on GitHub . Please let me know any issues you may have and look for future releases with feature enhancements.

Reference From : icodeblog 


No comments:

Post a Comment