load image to tableView - ios

i am using table view to display image fron internet and its taking time to load the image..
i tried
dispatch_async(imageQueue_, ^{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[record imageURLString]];
dispatch_async(dispatch_get_main_queue(), ^{
[[cell imageView] setImage:[UIImage imageWithData:imageData]];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
});
but its loading image slowly and repeating the images till the other images will load in the same row..
is there any way to load all the images in tableview at same time (normally it will happen one by one..)?

Make 2 class with AsyncImageView.h and .m
In AsyncImageView.h
#interface AsyncImageView : UIView
{
NSURLConnection *connection;
NSMutableData *data;
NSString *urlString; // key for image cache dictionary
}
-(void)loadImageFromURL:(NSURL*)url;
- (void)StoreImage:(UIImage*)image String:(NSString *)str;
#end
and In .m
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame])
{
}
return self;
}
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
- (void)dealloc
{
[connection cancel];
[connection release];
[data release];
[super dealloc];
}
-(void)loadImageFromURL:(NSURL*)url
{
if (connection != nil)
{
[connection cancel];
[connection release];
connection = nil;
}
if (data != nil)
{
[data release];
data = nil;
}
if (imageCache == nil) // lazily create image cache
imageCache = [[ImageCache alloc] initWithMaxSize:2*1024*1024]; // 2 MB Image cache
[urlString release];
urlString = [[url absoluteString] copy];
UIImage *cachedImage = [imageCache imageForKey:urlString];
if (cachedImage != nil) {
if ([[self subviews] count] > 0)
{
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImageView *imageView = [[[UIImageView alloc] initWithImage:cachedImage] autorelease];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout]; // is this necessary if superview gets setNeedsLayout?
[self setNeedsLayout];
return;
}
#define SPINNY_TAG 5555
UIActivityIndicatorView *spinny = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinny.backgroundColor=[UIColor whiteColor];
// spinny.tag = SPINNY_TAG;
// spinny.center = self.center;
[spinny startAnimating];
[self addSubview:spinny];
[spinny release];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)incrementalData
{
if (data==nil)
{
data = [[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection
{
[connection release];
connection = nil;
UIView *spinny = [self viewWithTag:SPINNY_TAG];
[spinny removeFromSuperview];
if ([[self subviews] count] > 0)
{
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImage *image = [UIImage imageWithData:data];
[imageCache insertImage:image withSize:[data length] forKey:urlString];
UIImageView *imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout];
[self setNeedsLayout];
[data release];
data = nil;
}
And in your class where you are displaying tableview just import AsyncImageView.h and in tableView cellForRowAtIndexPath write
AsyncImageView *asyncImageView = nil;
UIImageView *cellImage = (UIImageView *)[cell viewWithTag:1];
asyncImageView = [[AsyncImageView alloc] initWithFrame:cellImage.frame] ;
[asyncImageView loadImageFromURL:YourImageURL];
asyncImageView.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:asyncImageView];
I have used it and works fine. Hope it'll work for you also.. :)

As Eugene mentioned, use SDWebImage. Makes this stuff so simple.

You load images lazily to the tableview.
Here is the Great Example by Apple.

Related

Data from JSON not updating in UICollectionView

I'm creating an app with a Newsfeed as a UICollectionView however it doesn't seem to update when I change the JSON file. I am using a UIRefreshControl to refresh it but I can't tell if my issue is to do with this or to do with how the JSON is read (or something else entirely).
viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.navigationItem.title = #"News";
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0,0,23,16);
[btn setBackgroundImage:[UIImage imageNamed:#"menuImage.png"] forState:UIControlStateNormal];
[btn addTarget:(NavigationViewController *)self.navigationController action:#selector(showMenu) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barBtn = [[UIBarButtonItem alloc] initWithCustomView:btn];
self.navigationItem.leftBarButtonItem = barBtn;
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config
delegate:self
delegateQueue:nil];
[self fetchFeed];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat frameWidth = screenRect.size.width - 20;
CGFloat frameHeight = screenRect.size.height - 20;
_collectionView=[[UICollectionView alloc] initWithFrame:CGRectMake(10, 10, frameWidth, frameHeight) collectionViewLayout:layout];
[_collectionView setDataSource: self];
[_collectionView setDelegate: self];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[_collectionView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:_collectionView];
UIRefreshControl * refreshControl = [[UIRefreshControl alloc] init];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:#"Refresh Images"];
[_collectionView addSubview:refreshControl];
[refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
[self.collectionView reloadItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];
[self.collectionView reloadData];
}
fetchFeed
- (void)fetchFeed
{
NSString *requestString = #"http://www.jameslester.xyz/example.json";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
self.articles = jsonObject[#"articles"];
NSLog(#"%#", self.articles);
NSLog(#"Feed Fetched!!!");
dispatch_async(dispatch_get_main_queue(), ^{[self.collectionView reloadData];
});
}];
[dataTask resume];
}
refresh
- (void)refresh:(id)sender
{
[self fetchFeed];
[(UIRefreshControl *)sender endRefreshing];
NSLog(#"Refreshed");
}
Any help will be really appreciated.
Collection View Data Source
#define LABEL_TAG 100001
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
UILabel *articleTitle = [cell.contentView viewWithTag:LABEL_TAG];
NSDictionary *article = self.articles[indexPath.row];
if (!articleTitle) {
articleTitle = [[UILabel alloc]initWithFrame:CGRectMake(5, cell.bounds.size.height - cell.bounds.size.height / 2.2, cell.bounds.size.width - 10, cell.bounds.size.height / 2)];
articleTitle.textColor = [UIColor whiteColor];
articleTitle.numberOfLines = 3;
articleTitle.adjustsFontSizeToFitWidth = YES;
articleTitle.tag = LABEL_TAG;
[cell.contentView addSubview:articleTitle];
}
articleTitle.text = article[#"title"];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: article[#"image"]]];
UIImageView *bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:imageData]];
[bgImageView setContentMode:UIViewContentModeScaleAspectFill];
[bgImageView setClipsToBounds:YES];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = CGRectMake(0, cell.bounds.size.height - cell.bounds.size.height / 2, cell.bounds.size.width, cell.bounds.size.height/2);
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor clearColor] CGColor], (id)[[UIColor blackColor] CGColor], nil];
//gradient.locations = [NSArray arrayWithObjects:[NSNumber numberWithInt:0.0],[NSNumber numberWithInt:0.5], nil];
[bgImageView.layer insertSublayer:gradient atIndex:0];
cell.backgroundView = bgImageView;
return cell;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionView *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 10; // This is the minimum inter item spacing, can be more
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 10;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
int x = screenWidth/2 - 15;
int y = x;
return CGSizeMake(x, y);
}
- (void)collectionView:(UICollectionView *)colView didSelectItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
NSDictionary *article = self.articles[indexPath.row];
NSURL *URL = [NSURL URLWithString:article[#"url"]];
self.webViewController.title = article[#"title"];
self.webViewController.URL = URL;
[self.navigationController pushViewController:self.webViewController
animated:YES];
}
If NSLog(#"%#", self.articles) works and shows data you have proven that you are getting network data back. Did you set up your UIView as the delegate and the datasource properly? This is usually done at the top of the UIViewController class and looks like this:
class MyClassName: UICollectionViewDataSource {
// Your code here.
}
One way to check if the datasource is set up correctly is to set a breakpoint here
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
print(“This shows that I’m getting called”)
// Your custom code
}
When you call
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
})
this will in turn call cellForItemAtIndexPath to display data. If cellForItemAtIndexPath isn’t called then you have not properly set your UICollectionViewDataSource
Try to this
- (void)fetchFeed {
NSString *requestString = #"http://www.jameslester.xyz/example.json";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest*req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask*dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.articles = jsonObject[#"articles"];
NSLog(#"%#", self.articles);
NSLog(#"Feed Fetched!!!");
dispatch_async(dispatch_get_main_queue(), ^{
[_collectionView reloadData];
});
}];
[dataTask resume];
}

How to load images from API/URL asynchronously?

I am fetching images synchronously from an array which stores URLs of images but it work very slowly. Now i want to load them asynchronously for fast working.
Heres the code and provide answer with coding.
#import "DetailViewController.h"
#import "FinalViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
#synthesize jsonData;
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Select a Photo";
// Do any additional setup after loading the view.
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = [NSURL URLWithString:#"http://json.code.com/albums/1/photos"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response
{
data1 = [[NSMutableData alloc] init];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)theData
{
[data1 appendData:theData];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
jsonArray1 = [NSJSONSerialization JSONObjectWithData:data1 options:nil error:nil];
[mainTableView reloadData];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(nonnull NSError *)error
{
UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Please make sure you are connected to either 3G or Wi-Fi." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil, nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (int)numberOfSectionInTableView:(UITableView *)tableView
{
return 1;
}
- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [jsonArray1 count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
cell.textLabel.text = [[jsonArray1 objectAtIndex:indexPath.row] objectForKey:#"title"];
cell.detailTextLabel.text = [NSString stringWithFormat:#"URL : %#", [[jsonArray1 objectAtIndex:indexPath.row] objectForKey:#"url"]];
NSURL *URL = [[NSURL alloc] initWithString:[[jsonArray1 objectAtIndex:indexPath.row] valueForKey:#"thumbnailUrl"]];
NSData *URLData = [[NSData alloc] initWithContentsOfURL:URL];
[[cell imageView]setImage:[UIImage imageWithData:URLData]];
return cell;
}
-(void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
FinalViewController *fvc = [[FinalViewController alloc] initWithNibName:#"FinalViewController" bundle:nil];
fvc.jsonData2 = [jsonArray1 objectAtIndex:indexPath.row];
[self.navigationController pushViewController:fvc animated:YES];
}
#end
We can use dispatch_async to run the operation asynchronously.
Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.poster.image = nil; // or cell.poster.image = [UIImage imageNamed:#"placeholder.png"];
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://myurl.com/%#.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:#"movieId"]]]];
if (imgData) {
UIImage *image = [UIImage imageWithData:imgData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
myCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.poster.image = image;
});
}
}
});
return cell;
}
You can do like this:
cell.tag = indexPath.row;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {
NSData *imageData = [NSData dataWithContentsOfURL: URL];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.tag == indexPath.row) {
cell.imageView.image = image;
[cell setNeedsLayout];
}
});
}
});
Ref: Asynchronous downloading of images for UITableView with GCD
Just by simply setting the following works fine for me .
cell.imageView.image =[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[imageArray objectAtIndex:i]]]]];
You can use the activity indicator as you have asked . Just drag and drop UIActivityIndicatorView onto the UIImageView of the UITableViewCell and set the needed constraints . Once the image gets loaded you can set it as hidden .
To do it programmatically , you can add a subview to the Image view in the UITableViewCell. Once the Image gets loaded you can remove the sub view .
UIActivityIndicatorView* actInd = [[UIActivityIndicatorView alloc]init];
[cell.imageView addSubview:actInd];

how to show no image UIWebImageView

I'm uisng UIWebImageView (custom class inherits UIImageView) its working fine, download image from url and show it webview, in some case there is no image in particular url then it show empty space, so need to show there No image, How to find its return image or not.
#implementation UIWebImageView
#define kAnimationDuration 0.5
#synthesize animate;
#pragma mark -
#pragma mark Public Methods
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
imageData = [[NSMutableData alloc] init];
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGFloat xCoord = (frame.size.width / 2.0f) - [activityIndicator frame].size.width;
CGFloat yCoord = (frame.size.height / 2.0f) - [activityIndicator frame].size.height;
[activityIndicator setFrame:CGRectMake(xCoord, yCoord, [activityIndicator frame].size.width, [activityIndicator frame].size.height)];
[activityIndicator setHidesWhenStopped:YES];
[self addSubview:activityIndicator];
}
return self;
}
- (id)initWithFrame:(CGRect)frame andUrl:(NSURL *)url animated:(BOOL)animated {
if (self = [self initWithFrame:frame]) {
[activityIndicator startAnimating];
animate = animated;
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (connection)
{
}
}
return self;
}
- (void)downloadImage:(NSURL *)url {
[activityIndicator startAnimating];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (connection)
{
}
}
#pragma mark -
#pragma mark NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[imageData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[activityIndicator stopAnimating];
UIImage *downloadedImage = [[UIImage alloc] initWithData:imageData];
if (animate)
{
[self setAlpha:0];
[UIView beginAnimations:#"Animations" context:nil];
[UIView setAnimationDuration:kAnimationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self setAlpha:100];
[UIView commitAnimations];
}
[self setImage:downloadedImage];
}
- (void)dealloc {
}
Try to check if downloadedImage is not nil, if it's nil show a label with "No Photo" title or show an image with "No Photo".
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[activityIndicator stopAnimating];
UIImage *downloadedImage = [[UIImage alloc] initWithData:imageData];
if (animate)
{
[self setAlpha:0];
[UIView beginAnimations:#"Animations" context:nil];
[UIView setAnimationDuration:kAnimationDuration];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self setAlpha:100];
[UIView commitAnimations];
}
if (downloadedImage) {
[self setImage:downloadedImage];
}
else {
// no image downloaded, show "No Image" message
}
}

Custom UITableViewCell with UIImageView not showing image

I have a custom cell with UIImageView, and it is not showing the image. I have tried setting image to default cell.imageView.image property, and it works just fine, but doesn't work with my custom ImageView.
I load my custom Cell from Xib, and I believe it has to do with lazy loading of UIImageView. How do I make it work?
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
DVGTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.tag = indexPath.row;
if (self.loader.parsedData[indexPath.row] != nil)
{
cell.imageCustom.image = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {
NSString *url = [self.loader.parsedData[indexPath.row] objectForKey:#"imageLR"];
NSData *imageData = nil;
if ([self.cache objectForKey:url] != nil)
{
imageData = [self.cache objectForKey:url];
}
else
{
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
[self.cache setObject:imageData forKey:[self.loader.parsedData[indexPath.row] objectForKey:#"imageLR"]];
}
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.tag == indexPath.row) {
UIImage *image = [[UIImage alloc] initWithData:imageData];
cell.imageCustom.image = image;
[cell setNeedsLayout];
}
});
});
}
return cell;
}
I usually do Lazy loading for ImageViews with this piece of code, hope it helps:
- (void) loadImageForImageView:(UIImageView *)theImageView WithURL:(NSURL *)url {
NSOperationQueue *queue = [NSOperationQueue new];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:3.0];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *reponse, NSData *data, NSError *error) {
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
theImageView.image = image;
for (UIActivityIndicatorView *spinner in theImageView.subviews) {
[spinner removeFromSuperview];
break;
}
});
}];
}
In your cellForRowAtIndexPath:
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[spinner setColor:[UIColor darkGrayColor]];
spinner.frame = CGRectMake(130 , 53, 20, 20);
[spinner startAnimating];
[imageCell addSubview:spinner];
[self loadImageForImageView:imageCell WithURL:imageURL];
Where imageCell is your UIImageView.

App Crashes when ReloadData done for the tableView

I am using the following code to reload my tableView when its done adding all the data to my Mutable Arrays, but the app always crashes
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//Spinner Add while waiting
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.frame = CGRectMake(147, 10, 25, 25);
[self.tableView addSubview:spinner];
[spinner startAnimating];
operationQueue = [[NSOperationQueue alloc] init];
usersFirstName = [[NSMutableArray alloc] init];
usersLastName = [[NSMutableArray alloc] init];
usersAvatar = [[NSMutableArray alloc] init];
NSString *urlstring = [NSString stringWithFormat:#"https://www.test.com/scribble/%#/",scribbleId];
NSURL *url = [NSURL URLWithString:urlstring];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON){
users = JSON[#"users_favored"];
if (users.count > 0) {
NSUInteger count = [users count];
for (NSUInteger i =0; i<count; i++) {
NSString *urlString = [NSString stringWithFormat:#"https://www.test.com%#",[users objectAtIndex:i]];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *requestUser = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:requestUser success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON){
if (i == 0) {
usersFirstName = [JSON[#"first_name"] mutableCopy];
usersLastName = [JSON[#"last_name"] mutableCopy];
usersAvatar = [JSON[#"user_avatar"] mutableCopy];
}else{
[usersFirstName addObjectsFromArray:JSON[#"first_name"]];
[usersLastName addObjectsFromArray:JSON[#"last_name"]];
[usersAvatar addObjectsFromArray:JSON[#"user_avatar"]];
}
if (i == count-1) {
[self.tableView reloadData];
[spinner stopAnimating];
[spinner removeFromSuperview];
}
}failure:nil];
[operationQueue addOperation:operation];
}
}else{
self.navigationItem.title = #"No Favors";
[spinner stopAnimating];
[spinner removeFromSuperview];
}
} failure:nil];
[operationQueue addOperation:operation];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return usersFirstName.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableFavorIdentifier = #"FavorCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableFavorIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableFavorIdentifier];
}
NSString *firstName = [usersFirstName objectAtIndex:indexPath.row];
NSString *lastName = [usersLastName objectAtIndex:indexPath.row];
NSString *avatar = [usersAvatar objectAtIndex:indexPath.row];
NSString *userFullName = [NSString stringWithFormat:#"%# %#",firstName,lastName];
UIImageView *userAvatar = (UIImageView *)[cell viewWithTag:100];
if ([avatar length ] > 0) {
NSString *img = [#"https://dtest_media_and_assets.s3.amazonaws.com/" stringByAppendingString:avatar];
[userAvatar setImageWithURL:[NSURL URLWithString:img] placeholderImage:[UIImage imageNamed:#"scribble.png"]];
}else{
userAvatar.image = [UIImage imageNamed:#"scribble.png"];
}
userAvatar.layer.cornerRadius = 4.0;
userAvatar.clipsToBounds = YES;
UILabel *userNameLabel = (UILabel *)[cell viewWithTag:101];
userNameLabel.text = userFullName;
return cell;
}
The error it gives is
2013-03-15 16:37:08.910 test[19547:c07] -[__NSCFString count]: unrecognized selector sent to instance 0x8679c80
2013-03-15 16:37:08.911 test[19547:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString count]: unrecognized selector sent to instance 0x8679c80'
*** First throw call stack:
(0x1cdf012 0x169fe7e 0x1d6a4bd 0x1ccebbc 0x1cce94e 0x143d7 0x7c8548 0x7cb224 0x68f952 0x68f2dc 0x140d7 0x281d2 0x29569 0x2f9553f 0x2fa7014 0x2f977d5 0x1c85af5 0x1c84f44 0x1c84e1b 0x21bb7e3 0x21bb668 0x5e3ffc 0x200d 0x1f35)
libc++abi.dylib: terminate called throwing an exception
Edit
everything works just fine when I use this instead
[usersFirstName addObject:JSON[#"first_name"]];
[usersLastName addObject:JSON[#"last_name"]];
[usersAvatar addObject:JSON[#"user_avatar"]];
[self.tableView reloadData];
if (i == count-1) {
[spinner stopAnimating];
[spinner removeFromSuperview];
}
try the same with that function:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"usersFirstName is of type %#", NSStringFromClass([usersFirstName class]));
return [usersFirstName count];
}
I guess you have to replace:
if (i == 0) {
usersFirstName = [JSON[#"first_name"] mutableCopy];
usersLastName = [JSON[#"last_name"] mutableCopy];
usersAvatar = [JSON[#"user_avatar"] mutableCopy];
}else{
[usersFirstName addObjectsFromArray:JSON[#"first_name"]];
[usersLastName addObjectsFromArray:JSON[#"last_name"]];
[usersAvatar addObjectsFromArray:JSON[#"user_avatar"]];
}
with just:
[usersFirstName addObject:JSON[#"first_name"]];
[usersLastName addObject:JSON[#"last_name"]];
[usersAvatar addObject:JSON[#"user_avatar"]];
The issue is that this:
users = JSON[#"users_favored"];
Returns an NSString, when it looks you are expecting an NSArray.
Verify this using:
users = JSON[#"users_favored"];
NSLog(#"users is of type %#", NSStringFromClass([users class]));
Something is either wrong with your assumption or the JSON is broken.

Resources