I'm working on an iOS application where I want to have a vertical tableview with large-ish pictures of a user's friends. (200x200px, 100x100pt)
I have it working, but it is super slow! I can barely move the tableview at all!
How can I do this asynchronously and in an expedient manner?
This is my current code:
In viewDidload:
FBRequest* friendsRequest = [FBRequest requestForMyFriends];
[friendsRequest startWithCompletionHandler: ^(FBRequestConnection *connection,
NSDictionary* result,
NSError *error)
{
self.friends = [result objectForKey:#"data"];
NSLog(#"Found: %u friends", (unsigned)self.friends.count);
[self.leftTableView reloadData];
[self.rightTableView reloadData];
}];
CellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
cell.backgroundColor = [UIColor clearColor];
}
NSDictionary<FBGraphUser> *friend = [self.friends objectAtIndex:indexPath.row];
if (friend)
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?width=200&height=200", friend.id]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 4, 100, 100);
imageView.layer.cornerRadius = 50.0f;
imageView.clipsToBounds = YES;
[cell.contentView addSubview:imageView];
}
return cell;
}
It might be easier for you if you made a custom UITableViewCell, then you can place a UIView (instead of UIImageView) and in InterfaceBuilder give it the class FBProfilePictureView. Now, all you need to do is set the profileID property on that view, and the Facebook SDK will handle getting the profile picture for the profile with the provided id and displaying it.
Facebook SDK Reference
The UIImageView+AFNetworking class from AFNetworking Framework is one of the most used methods to do this. You can easy import this Framework to your project:
https://github.com/AFNetworking/AFNetworking
And use like this:
#import "UIImageView+AFNetworking.h"
NSDictionary<FBGraphUser> *friend = [self.friends objectAtIndex:indexPath.row];
if (friend)
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?width=200&height=200", friend.id]];
UIImageView *imageView = [[UIImageView alloc] init];
imageView.frame = CGRectMake(0, 4, 100, 100);
imageView.layer.cornerRadius = 50.0f;
imageView.clipsToBounds = YES;
[imageView setImageWithURL:url];
[cell.contentView addSubview:imageView];
}
If you use [NSData dataWithContentsOfURL:url] the images will be fetched synchronous. Also when ever you scroll the table view they will be fetched again.
Use https://github.com/rs/SDWebImage for asynchronous image loading. It will also cache the images.
Download the files from EgoImageView. This link ask you to download a file. Unzip it. Add those file into your app. Import EgoImageView.h in your class. Change this code instead of your code. First time, it will take time to load. If you are converting URL as data, it will take long time.
if (friend)
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?width=200&height=200", friend.id]];
UIImageView *imageView = [[UIImageView alloc] init];
[imageView setImageURL:url];
imageView.frame = CGRectMake(0, 4, 100, 100);
imageView.layer.cornerRadius = 50.0f;
imageView.clipsToBounds = YES;
[cell.contentView addSubview:imageView];
}
Hope, it helps you.
Related
I have a UICollectionView inside a popupview which is just a simple view in a xib file. In the same xibfile I have my UICollectionViewCell like this:
The View is connected to SampleViewController class and the UICollectionViewCell is connected to PekProfil class
The code I use for displaying the cells is
[_collectionView registerClass:[PekProfil class] forCellWithReuseIdentifier:#"vinnare"];
_collectionView.delegate = self;
_collectionView.dataSource = self;
and:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"vinnare";
PekProfil * cellen = (PekProfil *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
cellen.backgroundColor = [UIColor grayColor];
if (cellen==nil) {
cellen = [[PekProfil alloc] init];
}
NSString * iden = [_winners objectAtIndex:indexPath.row];
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
initWithGraphPath:iden
parameters:nil
HTTPMethod:#"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
id result,
NSError *error) {
// Handle the result
NSLog(#"fetched friends:%#", result);
cellen.pekProfilNamn.text = [result objectForKey:#"name"];
NSString * ideno = [NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?width=640&height=640", iden];
NSLog(#"IDEN:%#", ideno);
NSString *pictureUrl = ideno;
NSURL * url = [NSURL URLWithString:pictureUrl];
NSLog(#"PICURL:%#", pictureUrl);
NSData *data = [NSData dataWithContentsOfURL:url];
NSLog(#"%#", data);
UIImage *img = [[UIImage alloc] initWithData:data];
//roundpic
CALayer *imageLayer = cellen.profilePicView.layer;
[imageLayer setCornerRadius:5];
[imageLayer setBorderWidth:1];
[imageLayer setMasksToBounds:YES];
[cellen.profilePicView.layer setCornerRadius:cellen.profilePicView.frame.size.width/2];
[cellen.profilePicView.layer setMasksToBounds:YES];
//END
cellen.profilePicView.image = img;
}];
return cellen;
}
And I know that the facebookcode works since I use the same code in other places.
However running this only displays this:
Any ideas why the content is not displaying?
You should create a custom subclass of UiCollectionViewCell. If you want to layout your cell in IB check include XIB file. It's not possible to combine classes like this in objective C. Register you nib your reuse identifier and make your image view and label public properties that you can then set in cellForItemAtIndexPath
I have a tableview in which i load some cells, and insert some images in. The images is downloaded with the help of SDWebImage library. There is one problem though: It seems the function to download the image is never called (or abruptet before completion), and therefore the complete method is never called on the imageView iv. It just inserts the placeholder image instead, which is a transparent png (yeah, i checked, it is there ^^).
No error is NSLogged in the if statement either.
Any ideas?
code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *myIdentifier = #"defaultcell";
UIActivityIndicatorView *spinner;
UIImageView *iv;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:myIdentifier forIndexPath:indexPath];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:myIdentifier];
//build spinner
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(160, 47);
spinner.tag = 101;
[cell.contentView addSubview:spinner];
//build ImageView
iv = [[UIImageView alloc] initWithFrame:(CGRect){.size={80, 60}}];
iv.contentMode = UIViewContentModeScaleAspectFill;
iv.clipsToBounds = YES;
iv.tag = 102;
iv.frame = CGRectMake(15, 17, 80, 60);
[cell.contentView addSubview:iv];
} else {
spinner = (UIActivityIndicatorView*)[cell viewWithTag:101];
iv = (UIImageView*)[cell viewWithTag:102];
}
[spinner startAnimating];
//the rest goes here
cell.textLabel.hidden = YES;
cell.detailTextLabel.hidden = YES;
cell.imageView.hidden = YES;
NSString *profilePicName = [NSString stringWithFormat:#"%#%#", [self.dbhandler getPicturesPath], [[gallery objectAtIndex:indexPath.row] valueForKey: #"filename"]];
NSLog(#"%#", profilePicName);
[iv setImageWithURL:[NSURL URLWithString:profilePicName] placeholderImage:[UIImage imageNamed:#"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType){
if(error){
NSLog(#"Callback Error: %#", error);
}
[spinner stopAnimating];
cell.textLabel.hidden = NO;
cell.detailTextLabel.hidden = NO;
cell.imageView.hidden = NO;
NSLog(#"done");
}];
NSString *subtitle = [NSString stringWithFormat:#"Comments: %# \nPosted: %#", [[gallery objectAtIndex:indexPath.row] valueForKey:#"comments"], [[gallery objectAtIndex:indexPath.row] valueForKey:#"created_at"]];
cell.detailTextLabel.numberOfLines = 0;
cell.textLabel.text = [NSString stringWithFormat:#"Votes: %#",[[gallery objectAtIndex:indexPath.row] valueForKey:#"votes"]];
cell.detailTextLabel.text = subtitle;
return cell;
}
Very new to AFNetworking, but after many SO questions... I've concluded that this is the solution to my issue.
I've got a hierarchy of JSON data loading my TableViewController cells dynamically. All of my text strings are loading appropriately but the image from my URL is not making it to my imageview.
Before utilizing the AFNetworking library, I had the images loaded, but I was experiencing some issues with the photos not staying loaded when I scrolled away and returned (they had to load again.)
What am I missing to get my images in there?
TableViewController.m
-(void)viewDidLoad {
[super viewDidLoad];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
siderbarButton.target = self.revealViewController;
siderbarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
self.tableView.backgroundColor = [UIColor whiteColor];
self.parentViewController.view.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1];
self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"logo_app_white.png"]];
NSURL *myURL = [[NSURL alloc]initWithString:#"http://domain.com/json2.php"];
NSData *myData = [[NSData alloc]initWithContentsOfURL:myURL];
NSError *error;
jsonArray = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:&error];
[tableView reloadData]; // if tableView is unidentified make the tableView IBOutlet
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return jsonArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NeedCardTableViewCell *cell = (NeedCardTableViewCell *) [tableView dequeueReusableCellWithIdentifier:#"needCard"];
if (cell == nil)
{
cell = [[NeedCardTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"needCard"];
}
NSDictionary *needs = jsonArray[indexPath.row]; // get the data dict for the row
cell.textNeedTitle.text = [needs objectForKey: #"needTitle"];
cell.textNeedPoster.text = [needs objectForKey: #"needPoster"];
cell.textNeedDescrip.text = [needs objectForKey: #"needDescrip"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"userImage" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
_imageProfPic.image = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
return cell;
}
Have you tried using the AFNetworking+UIImageView category? You can then call:
[_imageProfPic setImage:[NSURL URLWithString:#"http://myimageurl.com/imagename.jpg"]];
This will make a request and then set the returned image to your UIImageView's UIImage without you having to do anything else. You should also consider initializing NSURLCache in your AppDelegate:
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:10 * 1024 * 1024
diskPath:nil];
[NSURLCache setSharedURLCache:cache];
Take a look at NSHipster's run down on NSURLCache. This will help reload images, and all your requests, much faster the second time around. This is increasingly important when dealing with images and tables.
Manage to figure this one out with the use of this tutorial:
Networking Made Easy with AFNetworking
I used the final snippet of code to get my desired result:
NSURL *url = [[NSURL alloc] initWithString:[movie objectForKey:#"artworkUrl100"]];
[cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:#"placeholder"]];
I cut the second line of his code because I already have an if statement in my PHP/JSON
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NeedCardTableViewCell *cell = (NeedCardTableViewCell *) [tableView dequeueReusableCellWithIdentifier:#"needCard"];
if (cell == nil)
{
cell = [[NeedCardTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"needCard"];
}
NSDictionary *needs = jsonArray[indexPath.row]; // get the data dict for the row
cell.textNeedTitle.text = [needs objectForKey: #"needTitle"];
cell.textNeedPoster.text = [needs objectForKey: #"needPoster"];
cell.textNeedDescrip.text = [needs objectForKey: #"needDescrip"];
NSURL *url = [[NSURL alloc] initWithString:[needs objectForKey:#"userImage"]];
[cell.imageProfPic setImageWithURL:url];
return cell;
}
It worked like a charm, and the tutorial was pretty helpful since I'm a rookie with AFNetworking.
I have a UITableView which contains a UIImage and a title per cell. I'm getting the image from my db which contains the path of the picture generate via the ALAssetsLibrary. Problem is whenever I include the photo in the table, I can't select the cell. Any help would be appreciated
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIndentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIndentifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIndentifier];
}
Person *aPerson = [arrayOfPerson objectAtIndex:indexPath.row];
UIImage *background = [self cellBackgroundForRowAtIndexPath:indexPath];
UIImageView *cellBackgroundView = [[UIImageView alloc] initWithImage:background];
cellBackgroundView.image = background;
cell.backgroundView = cellBackgroundView;
UILabel *myLabel = (UILabel *) [cell viewWithTag:101];
myLabel.text = aPerson.title;
NSString *stPath = [NSString stringWithFormat:#"%#", aPerson.photo];
NSURL *urlNow = [NSURL URLWithString:stPath];
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
[assetslibrary assetForURL:urlNow resultBlock:^(ALAsset *imageAsset) {
ALAssetRepresentation *r = [imageAsset defaultRepresentation];
UIImageView *myImageView = (UIImageView *)[cell viewWithTag:100];
myImageView.image = [UIImage imageWithCGImage: r.fullResolutionImage];
//[cell.contentView addSubview:myImageView];
[self.tableView reloadData];
} failureBlock:nil];
return cell;
New image view objects are configured to disregard user events by default. If you want to handle events in a custom subclass of UIImageView, you must explicitly change the value of the userInteractionEnabled property to YES after initializing the object.
UIImageView *cellBackgroundView = [[UIImageView alloc] initWithImage:background];
cellBackgroundView.userInteractionEnabled = YES;
Note:
When you are dealing with Asset Library images, Please look at my this answer that may help you for better performance.
I have this very serious problem of scrolling the table.
Initially i used GCD for loading the image in Background and setting on table cell.
but the table was not scrolling smoothly.
So i used SDWebImage for that but then the same thing is happening.
Could anyone let me know the reason for this. Why the table Scrolling is not smooth as expected.
Please let me know your views as my app is waiting its release for the only same purpose.
Code :
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = #"Cell";
customCellForExhibitor *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *xibPath = [[NSBundle mainBundle]loadNibNamed:#"customCellForExhibitor" owner:self options:nil];
for (id fileObject in xibPath)
{
cell = (customCellForExhibitor*)fileObject;
}
}
objDataModel = [parserDataContentArray objectAtIndex:indexPath.section];
cell.exhibitorNameLabel.text = [objDataModel exhibitorNameObjectClass];
cell.exhibitorText.text = [objDataModel exhibitorOfferObjectClass];
cell.exhibitorSponsorType.text = [objDataModel exhibitorSponsorTypeObjectClass];
[cell.exhibitorSponsorType setTextAlignment:NSTextAlignmentRight];
// #pragma mark GCD;
//
// NSString *ImageURL = [[parserDataContentArray objectAtIndex:indexPath.section] exhibitorImageObjectClass];
//// NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
//// cell.exhibitorImage.image = [UIImage imageWithData:imageData];
//
// dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// //this will start the image loading in bg
// dispatch_async(concurrentQueue, ^{
// NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
//
// //this will set the image when loading is finished
// dispatch_async(dispatch_get_main_queue(), ^{
//
// cell.exhibitorImage.image = [UIImage imageWithData:imageData];
// [cell setNeedsDisplay];
//
// });
// });
NSString *ImageURL = [[parserDataContentArray objectAtIndex:indexPath.section] exhibitorImageObjectClass];
[cell.exhibitorImage setImageWithURL:[NSURL URLWithString:ImageURL]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
if ([cell.exhibitorSponsorType.text isEqualToString:#"Gold"]) {
cell.exhibitorSponsorType.textColor = [UIColor colorWithRed:255/255.0 green:215/255.0 blue:0 alpha:1];
}
else if ([cell.exhibitorSponsorType.text isEqualToString:#"Silver"]){
cell.exhibitorSponsorType.textColor = [UIColor colorWithRed:192/255.0 green:192/255.0 blue:192/255.0 alpha:1];
}
else cell.exhibitorSponsorType.textColor = [UIColor colorWithRed:229/255.0 green:228/255.0 blue:226/255.0 alpha:1];
return cell;
}
Thank You
Best Regards.
Use lazy loading file instead here is the reference u can find it here along with demo how it is implemented.
https://stackoverflow.com/a/18032907/1305001
[cell addSubview:[self addViewWithURL:ImageURL NFrame:CGRectMake(0, 0, 50, 50)]];
add this method below cellForRow
-(UIView*)addViewWithURL:(NSString*)urlStr NFrame:(CGRect)rect
{
LazyLoad *lazyLoading;
lazyLoading = [[LazyLoad alloc] init];
[lazyLoading setBackgroundColor:[UIColor grayColor]];
[lazyLoading setFrame:rect];
[lazyLoading loadImageFromURL:[NSURL URLWithString:urlStr]];
return lazyLoading;
}
Set placeholder in LazyLoad.m file's init method as
-(id)init{
if (self==[super init]) {
[self setImage:[UIImage imageNamed:#"placeholder.png"]];
}
return self;
}
And change superClass of LazyLoad.h file to UIImageView from UIView as
#interface LazyLoad : UIImageView