Implementing tableView:cellForRowAtIndexPath: with a ALAssetRepresentation image - ios

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

Related

Displaying photo library images in UICollectionView

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]

Register Nib in ViewDidLoad Thread 1 exc bad access table view

I am getting a Thread 1, EXC: BAD ACCESS error on my [self.tableView registerNib:nib forCellReuseIdentifier:#"InboxCell"]; line. Everything was working fine but then I tried to bring in a BackroundView swift file, which was more of a headache then it was worth.
I deleted the BackgroundView swift file and cleaned it but now I have an error I cant figure out. I have a InboxCell.xib custom cell. Please hold my hand through it. Any help would be much appreciated! Here is my code:
//InboxTableViewController.h
#import "InboxCell.h"
#interface InboxTableViewController : UITableViewController
//this is property for the data source
#property (nonatomic, strong) NSArray *messages;
//something for showing image
#property (nonatomic, strong) PFObject *selectedMessage;
//for showing video
#property (nonatomic, strong) MPMoviePlayerController *moviePlayer;
- (IBAction)logout:(id)sender;
//set thumbnail
#property (nonatomic, strong) UIImage *thumbnail;
-(void)setThumbnailFromImage:(UIImage *)image;
#end
//.m
#interface InboxTableViewController ()
#end
#implementation InboxTableViewController
-(void)loadView
{
}
- (void)viewDidLoad {
[super viewDidLoad];
//THIS IS CUSTOM CELL!!!!!!!
UINib *nib = [UINib nibWithNibName:#"InboxCell" bundle:nil];
//register this nib to contain cell
/*THIS IS EXC ERROR*/
[self.tableView registerNib:nib forCellReuseIdentifier:#"InboxCell"];
//video alloc here so its reused for every video in inbox.
self.moviePlayer = [[MPMoviePlayerController alloc] init];
//Determining if a current user is logged in
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
NSLog(#"%#", currentUser.username);
} else {
[self performSegueWithIdentifier:#"showLogin" sender: self];
}
}
//// In case it hasnt been logged in after a while
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//return nav and controller bar
[self.navigationController.navigationBar setHidden:NO];
[self.tabBarController.tabBar setHidden:NO];
PFQuery *query = [PFQuery queryWithClassName:#"Messages"];
// prevents error when running for first time in a while
if ([[PFUser currentUser] objectId] == nil) {
NSLog(#"No objectID");
} else {
[query whereKey:#"recipientIds" equalTo:[[PFUser currentUser] objectId]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"error %# %#", error, [error userInfo]);
} else {
self.messages = objects;
[self.tableView reloadData];
NSLog(#"Got %lu messages", (unsigned long)[self.messages count]);
}
}];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showLogin"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
}
else if ([segue.identifier isEqualToString:#"showImage"]) {
//setting it so image tab wont pop up
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
ImageViewController *imageViewController = (ImageViewController *)segue.destinationViewController;
imageViewController.message = self.selectedMessage;
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedMessage = [self.messages objectAtIndex:indexPath.row];
NSString *fileType = [self.selectedMessage objectForKey:#"fileType"];
if ([fileType isEqualToString:#"image"]) { //if image file
[self performSegueWithIdentifier:#"showImage" sender:self];
}
else {
//file type is video
PFFile *videoFile = [self.selectedMessage objectForKey:#"file"]; //getting the file
//now getting the URL property which is a string
NSURL *fileUrl = [NSURL URLWithString:videoFile.url];
//set the url for the movie player
self.moviePlayer.contentURL = fileUrl;
//prepare for file
[self.moviePlayer prepareToPlay];
//this is a quick thumbnail while it loads
// [[self.moviePlayer ]; NOT WORKING HERE
//Add video to view controller so you can see it
[self.view addSubview:self.moviePlayer.view];
//setting it to screen size CAN SET TO ANYSIZE!!!!!!!
[self.moviePlayer setFullscreen:YES animated:YES];
}
/* //this portion is to delete it after its viewed
NSMutableArray *recipientIds = [NSMutableArray arrayWithArray:[self.selectedMessage objectForKey:#"recipientIds"]];
//this is for each one individually
if ([recipientIds count] == 1) {
//last recipient delete
[self.selectedMessage deleteInBackground];
}
else {
//remove the recipients and save it
[recipientIds removeObject:[[PFUser currentUser] objectId]];
//now you have to update recipients array with new data
[self.selectedMessage setObject:recipientIds forKey:#"recipientIds"];
[self.selectedMessage saveInBackground];
} */
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// always use the count of data source
return [self.messages count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
/*CUSTOM CELL CODE */
InboxCell *cell = [tableView dequeueReusableCellWithIdentifier:#"InboxCell" forIndexPath:indexPath];
PFObject *message = [self.messages objectAtIndex:indexPath.row];
cell.titleLabel.text = [message objectForKey:#"senderName"];
//Date
NSDate *updated = [message updatedAt];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE, MMM d, h:mm a"];
cell.createdAtLabel.text = [NSString stringWithFormat:#"Filmed At: %#", [dateFormat stringFromDate:updated]];
// customizing the image next to the message to determine whether its a video or image.
NSString *fileType = [message objectForKey:#"file_type"];
if ([fileType isEqualToString:#"image"]) { // must add icons
cell.thumbnailView.image = [UIImage imageNamed: #"icon_image.png"];
// cell.imageView.image is the way to have a picture in a cell.
}
else {
cell.thumbnailView.image = [UIImage imageNamed:#"icon_video"];
}
return cell;
}
//this is used as a thumbnail before video plays
//- (UIImage *)thumbnailFromVideoAtURL:(NSURL *)url
//{
// AVAsset *asset = [AVAsset assetWithURL:url];
//
// // Get thumbnail at the very start of the video
// CMTime thumbnailTime = [asset duration];
// thumbnailTime.value = 0;
//
// // Get image from the video at the given time
// AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
//
// CGImageRef imageRef = [imageGenerator copyCGImageAtTime:thumbnailTime actualTime:NULL error:NULL];
// UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
// CGImageRelease(imageRef);
//
// return thumbnail;
//}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
return 100;
}
else {
return 100;
}
}
- (IBAction)logout:(id)sender {
[PFUser logOut];
[self performSegueWithIdentifier:#"showLogin" sender:self];
}
- (IBAction)refresh:(id)sender {
[self.tableView reloadData];
[sender endRefreshing];
}
//setting thumbnail for cell
-(void)setThumbnailFromImage:(UIImage *)image
{
CGSize origImageSize = image.size;
CGRect newRect = CGRectMake(0, 0, 104, 76);
float ratio = MAX(newRect.size.width / origImageSize.width, newRect.size.height / origImageSize.height);
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 0.0);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect cornerRadius:5.0];
[path addClip];
CGRect projectRect;
projectRect.size.width = ratio * origImageSize.width;
projectRect.size.height = ratio * origImageSize.height;
projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
[image drawInRect:projectRect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
self.thumbnail = smallImage;
UIGraphicsEndImageContext();
}
#end
Your issue is being caused by the empty loadView method. Never leave that method empty. Either remove the method or give it a proper implementation of creating the view controller's main view and setting self.view.

SDWebImage loading issue.!

hello i am loading remote images into my collection view with SDWebImage.
for the first time its loading fine like first showing placeholder image and when image is retreived then change the image of cell... but second time i load the same image the top visible rows are not showing image but when i scroll down to other images, they load fine. then i load back to top, images are there.
In my collectionview class -
- (void)startIconDownload:(TrialImages *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
TrialPicDownloader *iconDownloader = [_imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[TrialPicDownloader alloc] init];
iconDownloader.productRecord = appRecord;
[iconDownloader setCompletionHandler:^{
MyCollectionViewCell *cell = (MyCollectionViewCell *)[self.myCollectionView cellForItemAtIndexPath:indexPath];
cell.trialImageView.image = appRecord.trialImage;
[_imageDownloadsInProgress removeObjectForKey:indexPath];
}];
[_imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
}
}
this method is in TrialPicDownloader class -
- (void)startDownload
{
[[SDWebImageManager sharedManager] downloadWithURL:
[NSURL URLWithString:self.productRecord.TrialImagesUrl]
options:SDWebImageCacheMemoryOnly
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
if (image != NULL) {
self.productRecord.trialImage = image;
if (self.completionHandler)
self.completionHandler();
}
}];
}
NeverMind i was able to solve my issue by this code ...
- (void)startIconDownload:(TrialImages *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
TrialPicDownloader *iconDownloader = [_imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[TrialPicDownloader alloc] init];
iconDownloader.productRecord = appRecord;
[iconDownloader setCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
MyCollectionViewCell *cell = (MyCollectionViewCell *)[self.myCollectionView cellForItemAtIndexPath:indexPath];
cell.trialImageView.image = appRecord.trialImage;
[UIView animateWithDuration:0.3f animations:^{
[self.myCollectionView.collectionViewLayout invalidateLayout];
}];
[_imageDownloadsInProgress removeObjectForKey:indexPath];
});
}];
[_imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
[iconDownloader startDownload];
}
}
i used dispatch_async to process the completion handler on main queue and now its working great..!!

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