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];
}
Related
I have a table view on InquiryViewController that I want to be reloaded when I click the update status button. The update status button is a JSON that gets the status of a message.
Here's the code:
-(BOOL)getMessageStatus : (NSMutableArray *)emails : (UIAlertView *)alert : (UIProgressView *)progress : (InquiryLogViewController *)controller
{
_emailsInApi = [[NSArray alloc]init];
_emailsInApi = [[DBManager getSharedInstance]arrayOfEmails];
NSMutableArray *newArrayEmail = [[NSMutableArray alloc]init];
NSString *arrayEmail =#"";
for(int i = 0; i<[_emailsInApi count]; i++){
arrayEmail = [_emailsInApi objectAtIndex:i];
[newArrayEmail addObject:arrayEmail];
}
NSURL *url = [NSURL URLWithString:#"http://www.url.com/API/2.0/message.php"];
NSDictionary *params =#{#"api_key":#"APIKEYIOS",#"action":#"get-message-status",#"email":newArrayEmail};
NSLog(#"params: %#",params);
NSData *paramsData = [NSJSONSerialization dataWithJSONObject:params
options:NSJSONWritingPrettyPrinted
error:nil];
NSString *paramsString = [[NSString alloc]initWithData:paramsData encoding:NSUTF8StringEncoding];
paramsString = [paramsString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
paramsString = [paramsString stringByReplacingOccurrencesOfString:#"%5C" withString:#""];
NSString *post = [NSString stringWithFormat:#"params=%#", paramsString];
NSData *sendData = [post dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:sendData];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (!error)
{
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"response...... = %#", responseString );
//get data frm response
self.responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.responseArray = [self.responseData objectForKey:#"data"];
for(NSDictionary *items in self.responseArray)
{
Inquiry *inq = [[Inquiry alloc]init];
inq.email = [items objectForKey:#"to_email"];
inq.status = [items objectForKey:#"status_id"];
[emails addObject:inq];
}
float newProg = (float)1 - (float)[emails count] / (float)5;
dispatch_async(dispatch_get_main_queue(), ^{
[progress setProgress:newProg animated:YES];
});
dispatch_async(dispatch_get_main_queue(), ^{
[[DBManager getSharedInstance]updateInquirylog:emails];
});
dispatch_async(dispatch_get_main_queue(), ^{
controller.arrayOfEmails = [[DBManager getSharedInstance]loadInquiries];
[controller.tableViews reloadData];
});
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissWithClickedButtonIndex:0 animated:YES];
});
}
else
{
self.alert = [[UIAlertView alloc] initWithTitle:nil message:error.localizedDescription delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
self.responseData = nil;
[alert show];
}
}];
[task resume];
return YES;
}
My problem here is in: [controller.tableViews reloadData];
It doesn't reload my table. Why? Help me please. Thank you
EDIT: This json is in a class
Ok I'm sorry. I forgot to include my table view method.
Here it is:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID =#"Cell";
tableCellOfInquiryLog *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (tableView == self.searchDisplayController.searchResultsTableView){
if(cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle]loadNibNamed:#"searchCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
Inquiry *inquiry = [searchResult objectAtIndex:indexPath.row];
cell.sInquiry_id.text =[NSString stringWithFormat:#"%d",inquiry.ID];
cell.sName.text = inquiry.name;
cell.sItem.text = inquiry.item_name;
cell.sDate.text = inquiry.dDate;
cell.status.layer.cornerRadius = 10;
if ([inquiry.status isEqual: #"1"]) {
cell.status.backgroundColor = [UIColor greenColor];
}
else if ([inquiry.status isEqual: #"2"]) {
cell.status.backgroundColor = [UIColor orangeColor];
}
else if ([inquiry.status isEqual: #"3"]) {
cell.status.backgroundColor = [UIColor redColor];
}
return cell;
}
else
{
if(cell == nil)
{
cell = [[tableCellOfInquiryLog alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
Inquiry *inquiry = [arrayOfInquiries objectAtIndex:indexPath.row];
cell.inquiry_id.text =[NSString stringWithFormat:#"%d",inquiry.ID];
cell.name.text = inquiry.name;
cell.item.text = inquiry.item_name;
cell.date.text = inquiry.dDate;
cell.status.layer.cornerRadius = 10;
if ([inquiry.status isEqual: #"1"]) {
cell.status.backgroundColor = [UIColor greenColor];
}
else if ([inquiry.status isEqual: #"2"]) {
cell.status.backgroundColor = [UIColor orangeColor];
}
else if ([inquiry.status isEqual: #"3"]) {
cell.status.backgroundColor = [UIColor redColor];
}
return cell;
}
return nil;
}
create a instance of your tableview and the add the given code in which ever method u want to add to [self.nameoftableview reloaddata]
if (indexPath.section ==1) {
cell = [tableView dequeueReusableCellWithIdentifier:section1identifier];
cell = nil;//here i have made it nil
if (!cell)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:section1identifier];
data *newObj = [callingObj.itemslist objectAtIndex:indexPath.row];
UITextView *titlelabel = [[UITextView alloc]initWithFrame:CGRectMake(cell.frame.origin.x+5, cell.frame.origin.y-2, 320, 38)];
titlelabel.textColor = [UIColor redColor];
titlelabel.font= [UIFont fontWithName:#"Times New Roman" size:FONT_SIZE];
titlelabel.text = newObj.title;
titlelabel.scrollEnabled = NO;
titlelabel.editable = NO;
[cell.contentView addSubview:titlelabel];
desView = [[UITextView alloc]initWithFrame:CGRectMake(cell.frame.origin.x,cell.frame.origin.y+25 , 320, i + 160)];
desView.text = newObj.description;
desView.editable = NO;
desView.hidden = NO;
[cell.contentView addSubview:desView];
if (check == NO) {
desView.hidden = YES;
}
}
}
return cell;
I have a collectionView of Photos, when the photo is tapped it should show a detail view of that photo.
The problem is, the first photo I tap doesn't do anything, and then every tap after works except it shows the photo tapped two times ago.
For example:
Tap Photo 1... does nothing.
Tap Photo 2... shows Photo 1.
Tap Photo 6... shows Photo 2.
Thanks for the help!
ViewController.m
#property (nonatomic) NSArray *photos;
- (void)viewDidLoad
{
[super viewDidLoad];
[self.collectionView registerClass:[BlissPhotoCell class]
forCellWithReuseIdentifier:#"photo"];
NSURLSession *session = [NSURLSession sharedSession];
NSString *urlString = [[NSString alloc] initWithFormat:#"https://api.instagram.com/v1/;
NSURL *url = [[NSURL alloc]initWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSString *text = [[NSString alloc] initWithContentsOfURL:location encoding:NSUTF8StringEncoding error:nil];
NSData *data = [[NSData alloc] initWithContentsOfURL:location];
NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
self.photos = [responseDictionary valueForKeyPath:#"data"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
}];
[task resume];
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *photo = self.photos[indexPath.row];
BlissDetailViewController *viewController = [[BlissDetailViewController alloc] init];
viewController.modalPresentationStyle = UIModalPresentationCustom;
viewController.transitioningDelegate = self;
viewController.photo = photo;
[self presentViewController:viewController animated:YES completion:nil];
}
BlissPresentDetailTransition.h
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController *detail = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView = [transitionContext containerView];
detail.view.alpha = 0.0;
CGRect frame = containerView.bounds;
frame.origin.y += 20.0;
frame.size.height -= 20.0;
detail.view.frame = frame;
[containerView addSubview:detail.view];
[UIView animateWithDuration:0.3 animations:^{
detail.view.alpha = 1.0;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.3;
}
You inadvertently implemented didDeselect rather than didSelect. It's an easy mistake to make if you use auto completion when you type since didDeselect comes up first alphabetically.
I'm parsing some data from a JSON-file located on my server to my Table View.
When I launch the app the app successfully downloads the data to my table view, but when I begin to scroll, the app crashes.
Here's my code:
#import "FirstViewController.h"
#import "YoutubePost.h"
#import "AFNetworking.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize tableView = _tableView, activityIndicatorView = _activityIndicatorView, movies = _movies;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Videos", #"Videos");
self.tabBarItem.image = [UIImage imageNamed:#"newtab1"];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.navigationController setNavigationBarHidden:YES];
self.tableView.separatorColor = [UIColor clearColor];
// Setting Up Activity Indicator View
self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
self.activityIndicatorView.hidesWhenStopped = YES;
self.activityIndicatorView.center = self.view.center;
[self.view addSubview:self.activityIndicatorView];
[self.activityIndicatorView startAnimating];
self.tableView.separatorColor = [UIColor clearColor];
// Initializing Data Source
self.movies = [[NSArray alloc] init];
NSURL *url = [[NSURL alloc] initWithString:#"http://my-website.com/link-to-json.php?name=Name&orderby=published"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.movies = JSON;
[self.activityIndicatorView stopAnimating];
[self.tableView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
}
// Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.movies && self.movies.count) {
return self.movies.count;
} else {
return 0;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 378;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"YoutubePost";
YoutubePost *cell = (YoutubePost *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"YoutubePost" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
cell.title.text = [movie objectForKey:#"title"];
NSURL *url = [[NSURL alloc] initWithString:[movie objectForKey:#"link"]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
NSString * storyLink = [[_movies objectAtIndex: storyIndex] objectForKey:#"link"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:storyLink]];
NSString *formattedJSON = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:[self.tweets objectAtIndex:indexPath.row] options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding];
NSLog(#"tweet:\n%#", formattedJSON);
}
#end
What is wrong? I see that the data successfully downloads to my custom Table View Cell, but every time I try to scroll down the app crashes. Please help me fix this.
Thanks.
Correct this:
// Initializing Data Source
//self.movies = [[NSArray alloc] init];
NSURL *url = [[NSURL alloc] initWithString:#"http://my-website.com/link-to-json.php?name=Name&orderby=published"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.movies = [[NSArray alloc] initWithArray:JSON];
[self.activityIndicatorView stopAnimating];
[self.tableView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
And in your YouTubePost Nib add Identifier "YouTubePost":
And also in your YouTubePost Nib select your title UILabel and in the inspector change from:
To:
Or Change:
To:
This will do the job.
Change the lines below:
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"YoutubePost" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
Like this:
if (cell == nil)
{
UINib *nib = [UINib nibWithNibName:#"YoutubePost" bundle:nil];
[tableView registerNib:nib forCellReuseIdentifier:#"YoutubePost"];
tableViewCell = [tableView dequeueReusableCellWithIdentifier:#"YoutubePost"];
}
It looks like you're not doing any checking for [NSNull null] in your JSON. It is possible that the following code will give you [NSNull null] instead of an NSDictionary:
NSDictionary *movie = [self.movies objectAtIndex:indexPath.row];
You should filter these out before calling reloadData
Similarly, this line could also potentially return [NSNull null]:
cell.title.text = [movie objectForKey:#"title"];
You need to be prepared to handle that case. This may help you: Replace all NSNull objects in an NSDictionary
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.
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.