I have a table that is populated by an array of objects and whenever I call my refresh method that re-populates the array and reloads the table, when I try to read my array in cellForRowAtIndexPath I get a beyond bounds error. I have NSLogged my array to make sure it is populated correctly, and it is. It always is trying to read an index 1 larger than the array is actually. I have no idea why. Any help would be greatly appreciated!
cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"IndexPath = %d", indexPath.row);
// Returns the cell for the given indexPath
static NSString *cellidentifier1 = #"cell1";
static NSString *cellidentifier2 = #"cell2";
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"dark-background.jpg"]];
self.tableView.separatorColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"dark-background.jpg"]];
// Invisible Cell
if (indexPath.row % 2 == 0) {
UITableViewCell *cell2 = [theTableView dequeueReusableCellWithIdentifier:cellidentifier2];
if (cell2 == nil) {
cell2 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier2];
}
[cell2.contentView setAlpha:0];
[cell2 setUserInteractionEnabled:NO];
[cell2 setBackgroundColor:[UIColor clearColor]];
return cell2;
}
// Standard Cell
FCTableViewCell *cell = (FCTableViewCell *)[theTableView dequeueReusableCellWithIdentifier:cellidentifier1];
if (cell == nil) {
cell = [[FCTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier1];
}
FCCall *currentCall = [[dataController calls] objectAtIndex:((indexPath.row - 1 ) / 2)];
cell.callLabel.text = currentCall.call;
cell.locationLabel.text = currentCall.location;
cell.wcccaNumberLabel.text = currentCall.wcccaNumber;
cell.callNumberLabel.text = currentCall.callnumber;
// Remove leading white space from units string
NSString *units = [currentCall.units stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.unitsLabel.text = units;
cell.stationLabel.text = currentCall.station;
if ([currentCall.county isEqualToString:#"W"]) {
cell.countyImageView.image = [UIImage imageNamed:#"blue.png"];
}
else {
cell.countyImageView.image = [UIImage imageNamed:#"green.png"];
}
if ([currentCall.callType isEqualToString:#"F"]) {
cell.callTypeImageView.image = [UIImage imageNamed:#"red.png"];
}
else {
cell.callTypeImageView.image = [UIImage imageNamed:#"yellow.png"];
}
[cell.unitButton addTarget:self action:#selector(unitButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.unitButton.tag = ((indexPath.section & 0xFFFF) << 16) |
(indexPath.row & 0xFFFF);
[cell.directionsButton addTarget:self action:#selector(directionsButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.directionsButton.tag = ((indexPath.section & 0xFFFF) << 16) |
(indexPath.row & 0xFFFF);
return cell;
}
numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Returns the number of rows per section
return [dataController calls].count * 2;
}
refresh method:
[dataController refreshData:self success:^(NSURLRequest *request, NSURL *url, NSArray *calls) {
[self setWork:calls];
NSLog(#"Array = %#", work);
// Reset the pull controller and reload the table
[pull finishedLoading];
[tableView reloadData];
} failure:^(NSURLRequest *request, NSURL *url, NSError *error) {
// Reset pull indicator
[pull finishedLoading];
// Reload table
[tableView reloadData];
}];
refresh method:
- (void)refreshData:(id)object success:(void (^)(NSURLRequest *request, NSURL *url, NSArray *calls))success failure:(void (^)(NSURLRequest *request, NSURL *url, NSError *error))failure
{
NSLog(#"Refresh Started");
// Start the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// Check to make sure we can even make an HTTP request
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.wccca.com/PITS"]];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Reachable");
// Get the URL we are going to use to parse with
[FCDataController parserURL:[NSURL URLWithString:#"http://www.wccca.com/PITS"] completion:^(NSURL *url) {
NSURLRequest *parserRequest = [NSURLRequest requestWithURL:url];
AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:parserRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
// Initialize our calls array that will control our calls
calls = [[NSMutableArray alloc] init];
// Set the delegate for the XMLParser and start the parse operation
XMLParser.delegate = self;
BOOL successful = [XMLParser parse];
// Determine if the parse operation was a success or not
if (!successful) {
// Return the failure block because the parser failed
failure(request, url, [FCErrors parserError]);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
else {
// Return the success block
success(request, url, calls);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
NSLog(#"Refresh Finished");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser) {
NSLog(#"AFXMLOperation Error: %#", error.localizedDescription);
// Remove all data from our previous calls aray
[self setCalls:nil];
failure(parserRequest, url, [FCErrors badURLError]);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Refresh Finished");
}];
[operation start];
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Unreachable. AFHTTPRequestOperation Error: %#", error.localizedDescription);
// Remove all data from our previous calls aray
[self setCalls:nil];
failure(request, nil, [FCErrors networkError]);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Refresh Finished");
}];
[requestOperation start];
}
Related
I have a table view cell,having labels and images,on scrolling the images and labels get changed,this is due to the cell dequeue feature.I tried to resolve it by setting the imageview to nil,but it doesn't work.
The problem of repeatition is with PinImageView,that takes image from an array of images,its not with the one which takes images from URL.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier=#"cellIdentifier";
TripInfoListCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=(TripInfoListCell *)[[[NSBundle mainBundle] loadNibNamed:#"TripInfoListCell" owner:self options:nil] firstObject];
}
cell.PinImageView.image = nil;
NSString *direction=[dict123 valueForKey:#"direction" ] ;
NSString *drive_status=[dict123 valueForKey:#"driver_or_rider"];
if((indexPath.row==totalRow-1)&&[direction isEqual:#"From"])
{
__weak TripInfoListCell *weakCell = cell;
cell.PinImageView.image=[UIImage imageNamed:#"pin7#2x.png"];
cell.userNameLabel.text=loggedUser.profile_name;
cell.riderDriverSlNo.text=#"Driver";
if([drive_status isEqual:#"Ride"])
{
cell.riderDriverSlNo.text=#"Driver";
cell.userNameLabel.text=#"Driver"; //In case of "Rider" "From" name in the last row
}
else{
cell.availabiltyInfoLabel.text=#"You";
}
NSString *imagePic = [[NSUserDefaults standardUserDefaults] objectForKey:#"user_image"];
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:imagePic]];
[cell.userImageView setImageWithURLRequest:request placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.userImageView.image=image;
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"%#",error);
}];
}
else if((indexPath.row==totalRow-1)&&[direction isEqual:#"To"])
{
cell.PinImageView.image=[UIImage imageNamed:#"pin7#2x.png"];
cell.userNameLabel.text=[_tripDetails objectForKey:#"park_name"];
NSString *image=[NSString stringWithFormat:#"%#",[dict123 objectForKey:#"parkBannerImageUrl"]];
[[ImageHandler sharedInstance] getImageFromURL:image withCompletion:^(UIImage *image) {
if (image) {
[cell.userImageView setImage:image];
}
}];
}
else
if ([tableGoersList count] > indexPath.row)
{
NSDictionary *goersInfo=[tableGoersList objectAtIndex:indexPath.row];
[[NSUserDefaults standardUserDefaults]setObject:[goersInfo valueForKey:#"user_image_url"] forKey:#"user_image"];
[[NSUserDefaults standardUserDefaults]synchronize];
__weak TripInfoListCell *weakCell = cell;
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:goersInfo[#"user_image_url"]]];
[cell.userImageView setImageWithURLRequest:request placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.userImageView.image=image;
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"%#",error);
}];
if((indexPath.row==0)&&[direction isEqual:#"To"]) {
if([drive_status isEqual:#"Drive"]){
cell.riderDriverSlNo.text=#"Driver";
cell.PinImageView.image=[UIImage imageNamed:#"pin1#2x.png"];
cell.userNameLabel.text=loggedUser.profile_name;
cell.availabiltyInfoLabel.text=#"You";
}
else{
}
}
else if((indexPath.row==0)&&[direction isEqual:#"From"]) {
if([drive_status isEqual:#"Drive"])
{
cell.PinImageView.image=[UIImage imageNamed:#"pin1#2x.png"];
cell.userNameLabel.text=[_tripDetails objectForKey:#"park_name"];
cell.riderDriverSlNo.text=#"";
cell.availabiltyInfoLabel.text=#"";
NSString *image=[NSString stringWithFormat:#"%#",[dict123 objectForKey:#"parkBannerImageUrl"]];
[[ImageHandler sharedInstance] getImageFromURL:image withCompletion:^(UIImage *image) {
if (image) {
[cell.userImageView setImage:image];
}
}];
}
else{
NSLog(#"rider from");
cell.riderDriverSlNo.text=#"";
}
}
else{
imageNameArray = [[NSArray alloc] initWithObjects:#"pin2#2x.png", #"pin3#2x.png", #"pin4#2x.png", #"pin5#2x.png", #"pin6#2x.png",#"pin8#2x.png",#"pin9#2x.png", nil];
NSString* nameStr=[goersInfo valueForKey:#"name"];
NSArray * nameStrArray = [nameStr componentsSeparatedByString: #"'s"];
nameStr=[nameStrArray objectAtIndex:0];
cell.riderDriverSlNo.text=[NSString stringWithFormat:#"Rider %ld",(long)indexPath.row];
index = [TripInfoVC ifNameExists:_arrName Name:nameStr];
if(index == 0)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:0]];
[_arrName addObject:nameStr];
}
if(index == 1)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:1]];
}
if(index == 2)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:2]];
}
if(index == 3)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:3]];
}
if(index == 4)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:4]];
}
if(index == 5)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:5]];
}
if(index == 6)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:6]];
}
if(index == 7)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:0]];
}
if(index == 8)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:1]];
}
if(index == 9)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:2]];
}
if(index == 10)
{
cell.PinImageView.image=[UIImage imageNamed:[imageNameArray objectAtIndex:3]];
}
} // this pinImageView is the pin image which is repeated on scrolling
return cell;
}
Please help me solving this issue.
you may be faces the closure collision. when you declare completion block
[cell.userImageView setImageWithURLRequest:request placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.userImageView.image=image;
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"%#",error);
}];
weakCell is the pointer to cell object that was requested by UITableView delegate. it maybe reused later when you scroll the table and at that moment your completion block may actually be invoked, because downloading
process is not immediate.
How to handle it? I would use etc. UITableViewCell.tag property for identification of what exactly image I requested at the moment when cell was required and does it match the image I am trying to put to that cell when completion block is running. maybe some other downloading was fired later and overwritten tag property.
You have to implement load images in the fly or lazy loading by adding your code into delegate method of UICollection cellForRowAtIndexPath method on operation queue.
And, if you are doing something on UI that you have placed inside main thread, here is another example:
Lazy loading images in UICollectionView with SDWebImageManager
I making here simple application on XCODE 7.1. I just display 2 label and 1 image in tableview cell.I am parsing data from this URL. I am simply load data in TableviewHere i put the code of ViewController.m file
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.alpha = 1.0;
[self.view addSubview:activityIndicator];
activityIndicator.center = CGPointMake([[UIScreen mainScreen]bounds].size.width/2, [[UIScreen mainScreen]bounds].size.height/2);
[activityIndicator startAnimating];//to start animating
// Do any additional setup after loading the view, typically from a nib.
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://www.androidbegin.com/tutorial/jsonparsetutorial.txt"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
[activityIndicator stopAnimating];
_responsedic = (NSDictionary*) responseObject;
_Worldpopulation = [_responsedic valueForKey:#"worldpopulation"];
_imageURL = [_Worldpopulation valueForKey:#"flag"];
_country = [_Worldpopulation valueForKey:#"country"];
_population = [_Worldpopulation valueForKey:#"population"];
NSLog(#"Data:%#",_imageURL);
NSLog(#"Population",_population);
NSLog(#"Country",_country);
// NSLog(#"%#",_MovieList);
//NSLog(#"Array: %#",_imageURL);
//NSLog(#"%#",responseObject);
}
}];
[dataTask resume];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *Identifier = #"mycell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:Identifier];
// Set and load the images
[cell.imageView sd_setImageWithURL:[_imageURL objectAtIndex:indexPath.row] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
// Get rid of the activity indicator when the image has been loaded
}];
cell.textLabel.text = [_country objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [_population objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//NSString *rowValue = self.friends[indexPath.row+1];
NSString *message = [[NSString alloc] initWithFormat:#"You selected %#",[_country objectAtIndex:indexPath.row]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"YOU SELECT"
message:message
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
I am using AFNetworking 3.0 and SDWebImage for image loading.Data parse successfully and and displayed in tableview.I attached screenshot below
Problem is what the all data are not displayed in the tableview cell i also put the Alert dialog on each cell of tableview data successfully loaded but not displayed in cell. I search everywhere i can't find solution for this i am using 3G connection so net speed is not an issue Please someone help.
Try to reload table view with updated data in completion block.
NSURL *URL = [NSURL URLWithString:#"http://www.androidbegin.com/tutorial/jsonparsetutorial.txt"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
[activityIndicator stopAnimating];
_responsedic = (NSDictionary*) responseObject;
_Worldpopulation = [_responsedic valueForKey:#"worldpopulation"];
_imageURL = [_Worldpopulation valueForKey:#"flag"];
_country = [_Worldpopulation valueForKey:#"country"];
_population = [_Worldpopulation valueForKey:#"population"];
NSLog(#"Data:%#",_imageURL);
NSLog(#"Population",_population);
NSLog(#"Country",_country);
// NSLog(#"%#",_MovieList);
//NSLog(#"Array: %#",_imageURL);
//NSLog(#"%#",responseObject);
//Added Code -> Reloading data on Main queue for update
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableview reloadData];
});
}
}];
[dataTask resume];
Hope, it'll help you.
Thanks.
1) Parse Data and after getting data relaod table
-(void)ParseData
{
NSURLSession * session = [NSURLSession sharedSession];
NSURL * url = [NSURL URLWithString: #"http://www.androidbegin.com/tutorial/jsonparsetutorial.txt"];
//Create URLReques
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
// Set Method POST/GET
[request setHTTPMethod:#"GET"];
// Asynchronously Api is hit here
NSURLSessionDataTask* dataTask=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) //If error nil
{
//Serialization data
NSDictionary * json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"json %#",json);
array=[json valueForKey:#"worldpopulation"];
dispatch_async(dispatch_get_main_queue(), ^(void) {
if(array.count!=0)
{
//Reload table View
[_tblView reloadData];
}
});
}
else
{
//failure;
}
}];
[dataTask resume] ; // Executed task
}
2) Table View DataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(array.count!=0)
{
return [array count];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
//= [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.backgroundColor =[UIColor whiteColor];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel *lblCountry=(UILabel*)[cell viewWithTag:2];
lblCountry.text= [[array objectAtIndex:indexPath.row]valueForKey:#"country"];
UILabel *lblPopulation=(UILabel*)[cell viewWithTag:3];
lblPopulation.text= [[array objectAtIndex:indexPath.row]valueForKey:#"population"];
UIImageView *img = (UIImageView *)[cell viewWithTag:1];
[img setImageWithURL:[NSURL URLWithString:[[array objectAtIndex:indexPath.row]valueForKey:#"flag"]]];
return cell;
}
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'm trying to create a simple rss reader. The code works okay, except the UI hangs when the feeds are being updated. I thought I cobbled together the code to get the feed and parse it on a background queue while updating the UI on the mainQueue, but the table hangs pretty badly. Code below:
-(void)refreshFeed2
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for (NSString *feed in _feeds) {
// iterate over all feeds
NSLog(#"feed=%#", feed);
NSURL *url = [NSURL URLWithString:feed];
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
(void)[conn initWithRequest:request delegate:self];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ([data length] == 0 && error == nil) {
// handle empty response
} else if (error != nil) {
// handle error
NSLog(#"Error %#", [error localizedDescription]);
} else if ([httpResponse statusCode] == 200) {
// data present and no errors
[queue addOperationWithBlock:^{
// parse feed on queue
RXMLElement *rss = [RXMLElement elementFromXMLData:data];
RXMLElement *rssChild = [rss child:#"channel"];
RXMLElement* title = [rssChild child:#"title"];
NSArray* items = [[rss child:#"channel"] children:#"item"];
NSMutableArray* result=[NSMutableArray array];
for (RXMLElement *e in items) {
// iterate over the articles
RSSArticle* article = [[RSSArticle alloc] init];
article.sourceTitle = [title text];
article.articleTitle = [[e child:#"title"] text];
article.articleDescription = [[e child:#"description"] text];
article.articleUrl = [NSURL URLWithString: [[e child:#"link"] text]];
NSString *articleDateString = [[e child:#"pubDate"] text];
article.articleDate = [NSDate dateFromInternetDateTimeString:articleDateString formatHint:DateFormatHintRFC822];
if (article.articleUrl != NULL) {
[result addObject:article];
}
}
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// update table on mainQueue
for (RSSArticle *article in result) {
// iterate over articles
int insertIdx = [_allEntries indexForInsertingObject:article sortedUsingBlock:^(id a, id b) {
RSSArticle *entry1 = (RSSArticle *) a;
RSSArticle *entry2 = (RSSArticle *) b;
return [entry1.articleDate compare:entry2.articleDate];
}];
[_allEntries insertObject:article atIndex:insertIdx];
[self.LeftTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:insertIdx inSection:0]]
withRowAnimation:UITableViewRowAnimationFade];
}
}];
}];
}
}];
// Stop refresh control
[refreshControl endRefreshing];
}
}
Code that calls refreshFeed2:
- (void)viewDidLoad {
[super viewDidLoad];
self.allEntries = [NSMutableArray array];
self.feeds = [NSArray arrayWithObjects:
#"http://feeds.washingtonpost.com/rss/politics",
#"http://rss.cnn.com/rss/cnn_allpolitics.rss",
#"http://www.npr.org/rss/rss.php?id=1012",
#"http://www.slatedigital.com/support/feeds/rss_kb.php?s=fd5aa35e773dc3177b85a2126583f002",
nil];
}
//add refresh control to the table view
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:#selector(refreshInvoked:forState:)
forControlEvents:UIControlEventValueChanged];
NSString* fetchMessage = [NSString stringWithFormat:#"Fetching Articles"];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:fetchMessage
attributes:#{NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:11.0]}];
[self.LeftTableView addSubview: refreshControl];
[self refreshInvoked:self forState:UIControlStateNormal];
}
-(void) refreshInvoked:(id)sender forState:(UIControlState)state {
NSOperationQueue *refreshQueue = [[NSOperationQueue alloc] init];
[refreshQueue addOperationWithBlock:^{
[self refreshFeed2];
}];
}
Any help?
Thanks!
Can you try this? replace
[self refreshInvoked:self forState:UIControlStateNormal];
by
[self performSelectorOnBackground:#selector(refreshFeed2) withObject:nil];
and replace the same instead of
-(void) refreshInvoked:(id)sender forState:(UIControlState)state {
[self performSelectorOnBackground:#selector(refreshFeed2) withObject:nil ];
}
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.