Displaying photo library images in UICollectionView - ios

I am trying to display images from Photo Library in UICollectionView through ALAssetsLibrary my codes runs fine , but I have some issues .
The quality of thumbnails are poor .
How can arrange collection view show 100 recent photos by ordering
from
new to old .
here is my codes :
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// collect the photos
NSMutableArray *collector = [[NSMutableArray alloc] initWithCapacity:0];
ALAssetsLibrary *al = [ViewController defaultAssetsLibrary];
[al enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
if (asset) {
[collector addObject:asset];
}
}];
self.photos = collector;
}
failureBlock:^(NSError *error) { NSLog(#"error");}];
}
-(void)setPhotos:(NSArray *)photos {
if (_photos != photos) {
_photos = photos;
[_collectionView reloadData];
}
}
+ (ALAssetsLibrary *)defaultAssetsLibrary {
static dispatch_once_t pred = 0;
static ALAssetsLibrary *library = nil;
dispatch_once(&pred, ^{
library = [[ALAssetsLibrary alloc] init];
});
return library;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _photos.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *collectionImageView = (UIImageView *)[cell viewWithTag:100];
ALAsset *asset = [self.photos objectAtIndex:indexPath.row];
UIImage* img = [UIImage imageWithCGImage:asset.thumbnail];
img = [UIImage imageWithCGImage:img.CGImage scale:2.0 orientation:UIImageOrientationUp];
[collectionImageView setImage:img];
return cell;
}

Use the following code to sort the photos.
self.photos = [collector sortedArrayUsingComparator:^NSComparisonResult(ALAsset *first, ALAsset *second) {
NSDate * date1 = [first valueForProperty:ALAssetPropertyDate];
NSDate * date2 = [second valueForProperty:ALAssetPropertyDate];
return [date1 compare:date2];
}];

You can get the date of an image saved in the library by:
NSDate * date = [asset valueForProperty:ALAssetPropertyDate];
You can compare this date with today's date, and store it an array, and do the same for the 100 Images.
And to your other question,
The thumbnail img you get from asset is of different size depends on iOS. In iOS 9 it is of 75x75 and in iOS 8, it is of 150x150.
You can try this:
[UIImage imageWithCGImage:[asset aspectRatioThumbnail]

Related

Display all videos from gallery to collection view by using ALAssetLibrary

I am trying to fetch the video list from gallery to collection view by using ALAssetLibrary.But the video doesn't display in collection view.
And getting the Error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier cellIdentifier - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
*** First throw call stack:
(0x2ba0749f 0x395fbc8b 0x2ba07375 0x2c6d8d7f 0x2f4cb573 0x2ef26cd1 0x580d7 0x2ef268f5 0x2ef24fc1 0x2ef20c09 0x2eec724f 0x2e8efa0d 0x2e8eb3e5 0x2e8eb26d 0x2e8eac51 0x2e8eaa55 0x2e8e492d 0x2b9cdd95 0x2b9cb453 0x2b9cb85b 0x2b9193c1 0x2b9191d3 0x32cfd0a9 0x2ef28fa1 0x6de09 0x39b7baaf)
libc++abi.dylib: terminating with uncaught exception of type NSException
Please help me to solve this.
my code is here--
Create a collection view by using this code in viewDidLoad():
self.view = [[UIView alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
[collectionView setDataSource:self];
[collectionView setDelegate:self];
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[collectionView setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:collectionView];
Load Asset like this--
loadAssets()
{
allVideos = [[NSMutableArray alloc] init];
ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
[assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
if (group)
{
[group setAssetsFilter:[ALAssetsFilter allVideos]];
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
if (asset)
{
dic = [[NSMutableDictionary alloc] init];
ALAssetRepresentation *defaultRepresentation = [asset defaultRepresentation];
NSString *uti = [defaultRepresentation UTI];
NSURL *videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
NSString *title = [NSString stringWithFormat:#"video %d", arc4random()%100];
UIImage *image = [self imageFromVideoURL:videoURL];
[dic setValue:image forKey:#"image"];
[dic setValue:title forKey:#"name"];
[dic setValue:videoURL forKey:#"url"];
[allVideos addObject:asset];
}
}];
[_collectionView reloadData];
}
}
failureBlock:^(NSError *error)
{
NSLog(#"error enumerating AssetLibrary groups %#\n", error);
}];
}
- (UIImage *)imageFromVideoURL:(NSURL*)videoURL
{
UIImage *image = nil;
AVAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];;
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
imageGenerator.appliesPreferredTrackTransform = YES;
// calc midpoint time of video
Float64 durationSeconds = CMTimeGetSeconds([asset duration]);
CMTime midpoint = CMTimeMakeWithSeconds(durationSeconds/2.0, 600);
// get the image from
NSError *error = nil;
CMTime actualTime;
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:midpoint actualTime:&actualTime error:&error];
if (halfWayImage != NULL)
{
// cgimage to uiimage
image = [[UIImage alloc] initWithCGImage:halfWayImage];
[dic setValue:image forKey:#"ImageThumbnail"];//kImage
NSLog(#"Values of dictonary==>%#", dic);
NSLog(#"Videos Are:%#",allVideos);
CGImageRelease(halfWayImage);
}
return image;
}
-(void)viewDidAppear:(BOOL)animated
{
[self loadAssets];
}
And in collection View--
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [allVideos count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
NSLog(#"allvideo %#", allVideos);
ALAsset *alasset = [allVideos objectAtIndex:indexPath.row];
return cell;
}

Getting all photos from ALAssetsLibrary

This only returns some of the albums from Photos and the albums I'm getting doesn't include the same number of assets as there are images in them in the Photos app.
NSMutableArray *groups = [[NSMutableArray alloc] init];
ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
[assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
[group setAssetsFilter:[ALAssetsFilter allPhotos]];
[groups addObject:group];
} else {
block([groups copy], nil);
}
}
failureBlock:^(NSError *error) {
block(nil, error);
}];
What do I need to do to get all 1000 of them?
something like
- (void)loadLibraryGroups
{
if (self.assetsLibrary == nil) {
_assetsLibrary = [[ALAssetsLibrary alloc] init];
}
if (self.groups == nil) {
_groups = [[NSMutableArray alloc] init];
} else {
[self.groups removeAllObjects];
}
// setup our failure view controller in case enumerateGroupsWithTypes fails
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) {
NSString *errorMessage = nil;
switch ([error code]) {
case ALAssetsLibraryAccessUserDeniedError:
case ALAssetsLibraryAccessGloballyDeniedError:
errorMessage = #"The user has declined access to it.";
break;
default:
errorMessage = #"Reason unknown.";
break;
}
};
// emumerate through our groups and only add groups that contain photos
ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop) {
ALAssetsFilter *onlyPhotosFilter = [ALAssetsFilter allPhotos];
[group setAssetsFilter:onlyPhotosFilter];
if ([group numberOfAssets] > 0)
{
NSLog(#"group ==> %#",group);
[self.groups addObject:group];
}
else
{
NSLog(#"Empty Groups load all items");
for (ALAssetsGroup *group in self.groups) {
[self loadImageForEachGroup:group];
}
}
};
// enumerate only photos
NSUInteger groupTypes = ALAssetsGroupAlbum | ALAssetsGroupEvent | ALAssetsGroupFaces | ALAssetsGroupSavedPhotos;
[self.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:listGroupBlock failureBlock:failureBlock];
NSLog(#"finish load groups");
}
- (void)loadImageForEachGroup:(ALAssetsGroup *)group
{
if (!self.assets) {
_assets = [[NSMutableArray alloc] init];
} else {
[self.assets removeAllObjects];
}
ALAssetsGroupEnumerationResultsBlock assetsEnumerationBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result != nil) {
[self.assets addObject:result];
} else {
[self.collectionView reloadData];
}
};
ALAssetsFilter *onlyPhotosFilter = [ALAssetsFilter allPhotos];
[group setAssetsFilter:onlyPhotosFilter];
[group enumerateAssetsUsingBlock:assetsEnumerationBlock];
}
And Load in collection
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.assets.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"photoCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell
// load the asset for this cell
ALAsset *asset = self.assets[indexPath.row];
CGImageRef thumbnailImageRef = [asset thumbnail];
UIImage *thumbnail = [UIImage imageWithCGImage:thumbnailImageRef];
// apply the image to the cell
UIImageView *imageView = (UIImageView *)[cell viewWithTag:1];
imageView.image = thumbnail;
return cell;
}

Implementing tableView:cellForRowAtIndexPath: with a ALAssetRepresentation image

Here's my method inside of the UITableViewDataSource view controller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"studentCell";
StudentTableCell *cell = (StudentTableCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
// Never gets called
}
Student *student = self.studentList[indexPath.row];
cell.nameFirst.text = student.nameFirst;
cell.nameLast.text = student.portrait.assetURL;
// Portrait
CGImageRef portraitRef = [cell.portrait.image CGImage];
CIImage *portraitImage = [cell.portrait.image CIImage];
if (portraitRef == NULL && portraitImage == nil) {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[NSURL URLWithString:student.portrait.assetURL] resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *representation = [asset defaultRepresentation];
CGImageRef assetRef = [representation fullResolutionImage];
if (assetRef) {
[cell.portrait setImage:[UIImage imageWithCGImage:assetRef]];
}
} failureBlock:^(NSError *error) {}];
}
return cell;
}
This works as expected for the first few rows that fit inside of the initial scroll position of the table.
But as I scroll down, cell.nameFirst.text change as expected, while cell.portrait.image gets recycled and starts repeating the images loaded inside of the first scroll position.
Questions
How do I make sure every cell has the appropriate image
Can cell every be nil?
You need to update image whether it is set or not. Your code only sets the image if there isn't one already. Cells get reused as you scroll. So each cell needs to be updated with the image appropriate for the indexPath.
Also note that assetForURL:resultBlock:failureBlock:. It's asynchronous. This means you need to update the cell on the main thread once you get the image in the resultBlock.
cell.nameFirst.text = student.nameFirst;
cell.nameLast.text = student.portrait.assetURL;
// Portrait
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[NSURL URLWithString:student.portrait.assetURL] resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *representation = [asset defaultRepresentation];
CGImageRef assetRef = [representation fullResolutionImage];
if (assetRef) {
dispatch_async(dispatch_get_main_queue(), ^{
[cell.portrait setImage:[UIImage imageWithCGImage:assetRef]];
});
}
} failureBlock:^(NSError *error) {}];
return cell;
The best way to make sure every cell has the appropriate image is create dictionary and in cellForRowAtIndexPath: check value(image) in the dictionary object at key (I like use indexPath.row as a key). If it is set it up for the cell if it isn't call:
[library assetForURL:[NSURL URLWithString:student.portrait.assetURL] resultBlock:^(ALAsset *asset) {...
and once image is downloaded add it to the dictionary with key (indexPath.row).
You should reload the cell when you download your image, just remember to do it on the main thread.
I would suggest to utilize an image cache. Suppose the image cache has the following API:
typedef void (^completion_t)(id result, NSError* error);
#interface SimpleImageCache : NSObject
/**
Returns the image for the specified URL if it exists, otherwise nil.
*/
- (UIImage*) imageWithURL:(NSURL*)url;
/**
Asychronounsly loads the image from the asset library. The compeltion handler will
be called when the image is available or when an error occured.
The execution context where the compeltion handler will be executed is
implementation defined.
*/
- (void) loadImageWithURL:(NSURL*)url completion:(completion_t)completionHandler;
#end
In your code you would use it as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"studentCell";
StudentTableCell *cell = (StudentTableCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
// Never gets called
}
Student *student = self.studentList[indexPath.row];
cell.nameFirst.text = student.nameFirst;
cell.nameLast.text = student.portrait.assetURL;
// Portrait
NSURL* url = [NSURL URLWithString:student.portrait.assetURL];
UIImage* portrait = [self.imageCache imageWithURL:url];
if (portrait == nil) {
portrait = self.placeholderImage;
[self.imageCache loadImageWithURL:url completion:^(id image, NSError*error){
dispatch_async(dispatch_get_main_queue(), ^{
StudentTableCell* cell = (StudentTableCell *)[tableView cellForRowAtIndexPath:indexPath];
[cell.portrait setImage:image];
});
}];
}
[cell.portrait setImage:portrait];
return cell;
}
Implementation of SimpleImageCache
Warning: It's not tested, but it might give you a jump start, or an idea.
#interface SimpleImageCache ()
#property (nonatomic, strong) NSMutableDictionary* images;
#property (nonatomic, strong) ALAssetsLibrary* assetsLibrary;
#property (nonatomic, strong) UIImage* missingImage;
#end
#implementation SimpleImageCache {
dispatch_queue_t _sync_queue;
}
- (id)init {
self = [super init];
if (self) {
_sync_queue = dispatch_queue_create("sync_queue", NULL);
}
return self;
}
- (NSMutableDictionary*) images {
if (_images == nil) {
_images = [[NSMutableDictionary alloc] init];
}
return _images;
}
- (ALAssetsLibrary*) assetsLibrary {
if (_assetsLibrary == nil) {
_assetsLibrary = [[ALAssetsLibrary alloc] init];
}
return _assetsLibrary;
}
- (UIImage*) imageWithURL:(NSURL*)url {
__block UIImage* image;
dispatch_sync(_sync_queue, ^{
id obj = self.images[url];
if ([obj isKindOfClass:[UIImage class]]) {
image = obj;
}
});
return image;
}
- (void) loadImageWithURL:(NSURL*)url completion:(completion_t)completionHandler {
dispatch_async(_sync_queue, ^{
if (self.images[url] != nil) {
return;
}
self.images[url] = #"pending";
[self.assetsLibrary assetForURL:url resultBlock:^(ALAsset *asset) {
ALAssetRepresentation* representation = [asset defaultRepresentation];
__block UIImage* image = CFBridgingRelease([representation fullResolutionImage]);
dispatch_async(_sync_queue, ^{
if (image == NULL) {
image = self.missingImage;
NSAssert(image, #"image is nil");
}
self.images[url] = image;
if (completionHandler) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
completionHandler(image, nil);
});
}
});
} failureBlock:^(NSError *error) {
if (completionHandler) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
completionHandler(nil, error);
});
}
}];
});
}
#end

Only Last Image Store in Array Get Display in Table view

My code below will produce the correct amount of data in array but the display data will only take the last value and display repeated.
For Example:
When i selected the first image then the first image is successfully display in table view.
When i selected the second image then the array will has 2 data but problem is in table view i will get 2 same image (the second selected image). My expected result will be when selected the second image the first image will still be there and the second display at the subsequence row.
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Collector in photoList %#",self.collector);
for (int i = 0; i < collector.count; i++) {
// define the block to call when we get the asset based on the url (below)
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
CGImageRef iref = [imageRep fullResolutionImage];
if (iref) {
galleryImage = [UIImage imageWithCGImage:iref];
[self.tableView reloadData];
}
NSLog(#"[imageRep filename] : %#", [imageRep filename]);
};
NSLog(#"Collector %#",self.collector);
// get the asset library and fetch the asset based on the ref url (pass in block above)
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc]init];
[assetslibrary assetForURL:[collector objectAtIndex:i] resultBlock:resultblock failureBlock:nil];
}
- (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];
}
cell.imageView.image = galleryImage;
NSLog(#"Gallery image is %#",self.galleryImage);
return cell;
}
EDITED!
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Collector in photoList %#",self.collector);
for (int i = 0; i < collector.count; i++) {
// define the block to call when we get the asset based on the url (below)
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
CGImageRef iref = [imageRep fullResolutionImage];
if (iref) {
galleryImage = [UIImage imageWithCGImage:iref];
//Added mutable array for galleryImage
[photoCollector addObject:galleryImage];
[self.tableView reloadData];
}
NSLog(#"[imageRep filename] : %#", [imageRep filename]);
};
NSLog(#"Collector %#",self.collector);
// get the asset library and fetch the asset based on the ref url (pass in block above)
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc]init];
[assetslibrary assetForURL:[collector objectAtIndex:i] resultBlock:resultblock failureBlock:nil];
}
- (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];
}
//Display image
if(photoCollector.count != 0)
{
cell.imageView.image = [self.photoCollector objectAtIndex:indexPath.row];
}
NSLog(#"This is in cellForRowAtIndexPath");
NSLog(#"Gallery image is %#",self.galleryImage);
// Configure the cell...
return cell;
}
EDITED code at picker didFinishPickingMediaWithInfo!!
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Initialize View Controller
PhotosListViewController *photoListViewController = [[PhotosListViewController alloc]initWithNibName:#"PhotosListViewController" bundle:nil];
ImageModel *imgModel = [[ImageModel alloc]init];
// get the ref url
imageURL = [info valueForKey:UIImagePickerControllerReferenceURL];
//set the imageUrl to the imageModel url in property ?
imgModel.url = imageURL;
[self.collector addObject:imageURL];
photoListViewController.urlCollector = self.collector;
NSLog(#"Collector in root %#",self.collector);
[picker dismissViewControllerAnimated:YES completion:nil];
[self.navigationController pushViewController:photoListViewController animated:YES];
}
EDITED FULL CODE!!
RootViewController.m
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// Initialize View Controller
PhotosListViewController *photoListViewController = [[PhotosListViewController alloc]initWithNibName:#"PhotosListViewController" bundle:nil];
// get the ref url
imageURL = [info valueForKey:UIImagePickerControllerReferenceURL];
[self.collector addObject:imageURL];
photoListViewController.urlCollector = self.collector;
NSLog(#"Collector in root %#",self.collector);
[picker dismissViewControllerAnimated:YES completion:nil];
[self.navigationController pushViewController:photoListViewController animated:YES];
}
ImageModel.h
#import <Foundation/Foundation.h>
typedef void(^handler)(UIImage *image);
#interface ImageModel : NSObject
#property (nonatomic, strong) NSURL *imageUrl;
- (void)getImageWithCompletionHandler:(handler)completionBlock;
#end
ImageModel.m
#import "ImageModel.h"
#import <MobileCoreServices/MobileCoreServices.h>
#import <AssetsLibrary/AssetsLibrary.h>
#implementation ImageModel
#synthesize imageUrl;
- (void)getImageWithCompletionHandler:(handler)completionBlock
{
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
CGImageRef iref = [imageRep fullResolutionImage];
if (iref) {
UIImage *image = [UIImage imageWithCGImage:iref];
completionBlock(image);
}
};
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc]init];
[assetslibrary assetForURL:self.imageUrl resultBlock:resultblock failureBlock:nil];
}
#end
PhotoListViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
test1 = [[UIImage alloc]init];
self.imageModelObjects = [NSMutableArray array];
for(NSURL *url in self.urlCollector)
{
ImageModel *imageModel = [[ImageModel alloc] init];
imageModel.imageUrl = url;
[self.imageModelObjects addObject:imageModel];
}
}
- (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];
}
ImageModel *model = [self.imageModelObjects objectAtIndex:indexPath.row];
[model getImageWithCompletionHandler:^(UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
});
}];
return cell;
}
#interface ViewController () <UITableViewDataSource>
#property (nonatomic, strong) NSMutableArray *images;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.images = [[NSMutableArray alloc] init];
NSLog(#"Collector in photoList %#",self.collector);
for (int i = 0; i < collector.count; i++) {
// define the block to call when we get the asset based on the url (below)
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
CGImageRef iref = [imageRep fullResolutionImage];
if (iref) {
[self.images addObject:[UIImage imageWithCGImage:iref]];
[self.tableView reloadData];
}
NSLog(#"[imageRep filename] : %#", [imageRep filename]);
};
NSLog(#"Collector %#",self.collector);
// get the asset library and fetch the asset based on the ref url (pass in block above)
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc]init];
[assetslibrary assetForURL:[collector objectAtIndex:i] resultBlock:resultblock failureBlock:nil];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.images.count;
}
- (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];
}
cell.imageView.image = self.images[indexPath.row];
return cell;
}
#end
Edited:
ImageModel.h
#import <Foundation/Foundation.h>
typedef void(^handler)(UIImage *image);
#interface ImageModel : NSObject
#property (nonatomic, strong) NSURL *imageURL;
- (void)getImageWithCompletionHandler:(handler)completionBlock;
#end
ImageModel.m
#import "ImageModel.h"
#implementation ImageModel
- (void)getImageWithCompletionHandler:(handler)completionBlock
{
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *imageAsset)
{
ALAssetRepresentation *imageRep = [imageAsset defaultRepresentation];
CGImageRef iref = [imageRep fullResolutionImage];
if (iref) {
UIImage *image = [UIImage imageWithCGImage:iref];
completionBlock(image);
}
};
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc]init];
[assetslibrary assetForURL:self.imageURL resultBlock:resultblock failureBlock:nil];
}
Controller.m
#import "ViewController.h"
#import "ImageModel.h"
#interface ViewController ()
#property (nonatomic, strong) NSMutableArray *imageModelObjects;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageModelObjects = [NSMutableArray array];
for(NSURL *url in self.collector)
{
ImageModel *imageModel = [[ImageModel alloc] init];
imageModel.url = url;
[self.imageModelObjects addObject:imageModel]
}
//You can discard the collecter. IF u want the url, u can get from the self.imageModelObjects.
self.collector = nil;
}
- (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];
}
ImageModel *model = [self.imageModelObjects objectAtIndex:indexPath.row];
[model getImageWithCompletionHandler:^(UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
});
}];
// Configure the cell...
return cell;
}
if (iref)
{
galleryImage = [UIImage imageWithCGImage:iref];
//Added mutable array for galleryImage
[photoCollector addObject:galleryImage];
[photoCollector retain];
//[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"cell %d",indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = #"Hello";
cell.imageView.image = [self.photoCollector objectAtIndex:indexPath.row];
}
// Configure the cell.
return cell;
}

CollectionView is overlaping the cells

My aim is to have a collection view at the footer of my view. The cells are filled with photos from the photo library. I donĀ“t know why but the cells are overlaping each other. Does anybody know why? Here is the code from the ViewController:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return [self.fotoArray count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"foto_cell";
FotoCell *cell = [self.collectionView
dequeueReusableCellWithReuseIdentifier:cellIdentifier
forIndexPath:indexPath];
Foto *currFoto = [self.fotoArray objectAtIndex:indexPath.row];
// Set the selectedFotoID
[CoreDataManager sharedInstance].selectedFotoId = ((Foto*)[self.fotoArray objectAtIndex:indexPath.row]).objectID;
NSURL *u = [NSURL URLWithString:currFoto.f_path];
[self findImage:u in: cell];
return cell;
}
// Get Photo from Asset Library
-(void)findImage:(NSURL*)u in: (FotoCell*) cell
{
__block FotoCell *blockCell = cell;
//
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
if (iref) {
UIImage *largeimage = [UIImage imageWithCGImage:iref];
//[largeimage retain];
UIImage *thumbnail = [UIImage imageWithCGImage:iref scale:0.15 orientation:UIImageOrientationUp];
[blockCell.fotoThumb setImage:thumbnail];
}
};
//
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(#"cant get image - %#",[myerror localizedDescription]);
};
NSURL *asseturl = u;
ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease];
[assetslibrary assetForURL:asseturl
resultBlock:resultblock
failureBlock:failureblock];
}
And here the Code from my Cell.m class:
#implementation FotoCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)dealloc {
[_fotoThumb release];
[super dealloc];
}
#end
I'm not clear about your code.But I had met this problem before.
The reason is that you add visible view(like image, UILabel,...) in cellForItemAtIndexPath:
When collectionView sequence, all Cell views are overlap together when you scrolling.
You can try to init and imageView in you Cell, then set image name in cellForItemAtIndexPath
You have to set the itemSize of your UICollectionViewFlowLayout instance.

Resources