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;
}
Related
Good morning,
I'm using UICollectionView for the first time to show images from a user (like a Facebook profile) and at the moment I can show the images fine but I have some problems:
1- When I visit my profile the app freezes for like 2-3 minutes due to the load of 5 images.
2- When I'm moving through the UICollectionView it freezes when the app load again the images outside the screen.
What I have to do in order to not to freeze the app when loading the user pictures? And what I have to do to navigate through the CollectionView without freezing? Maybe a cache system is what I need?
That's my code:
ProfileViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor: [self colorWithHexString:#"FFFFFF"]];
self.profileimage.layer.cornerRadius = self.profileimage.frame.size.width / 2;
self.profileimage.clipsToBounds = YES;
self.profileimage.layer.borderWidth = 1.0f;
self.profileimage.layer.borderColor = [UIColor whiteColor].CGColor;
[self fetchJson];
[self fetchImages];
self.oneCollectionView.dataSource = self;
self.oneCollectionView.delegate = self;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 1;
}
-(NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _carImages.count;
}
// COLLECTION VIEW
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * images = [UIImage imageWithData:imageData];
myCell.imageview.image = images;
return myCell;
}
-(void)fetchImages {
self.carImages = [[NSMutableArray alloc] init];
NSString *usersPassword = [SSKeychain passwordForService:#"login" account:#"account"];
NSString * urlString = [NSString stringWithFormat:#"http://mywebsite.com/posts.php?usersPassword=%#",usersPassword];
NSURL * url = [NSURL URLWithString:urlString];
NSData * data = [NSData dataWithContentsOfURL:url];
NSError *error;
[_jsonArray removeAllObjects];
_jsonArray = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
for(int i=0;i<_jsonArray.count;i++)
{
NSDictionary * jsonObject = [_jsonArray objectAtIndex:i];
NSString* imagen = [jsonObject objectForKey:#"imagen"];
[_carImages addObject:imagen];
}
}
Thanks in advance.
Import UIImageView+AFNetworking.h
and load your image via this method in cellForItemAtIndexPath method
[imageView setImageWithURL:[NSURL URLWithString:#"https://lh6.googleusercontent.com/-B8kSXtoaQDo/VGTVlXyIXpI/AAAAAAAAJ_M/USh6SgvMemw/w1024-h1024/IMG_20141112_103152.jpg"] placeholderImage:[UIImage imageNamed:#"placeholder-avatar"]];
it will surely speed up to load and scrolling collectionView
Download the images asynchronously, dataWithContentsOfURL is synchronous method and it will block your current thread until the download completes. You can use libraries like SDWebImage to automatically handle downloading for you or You can use NSURLSessionDownloadTask to download Images.
- (void)fetchImages {
self.carImages = [[NSMutableArray alloc] init];
NSString *usersPassword = [SSKeychain passwordForService:#"login" account:#"account"];
NSString * urlString = [NSString stringWithFormat:#"http://mywebsite.com/posts.php?usersPassword=%#",usersPassword];
NSURL * url = [NSURL URLWithString:urlString];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
[self.jsonArray removeAllObjects];
self.jsonArray = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
for(int i=0;i<_jsonArray.count;i++)
{
NSDictionary * jsonObject = self.jsonArray[i];
NSString* imagen = jsonObject[#"imagen"];
[self.carImages addObject:imagen];
}
}
}];
[dataTask resume];
}
// COLLECTION VIEW
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[self.jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSURLSessionDownloadTask *imageDownloadTask = [[NSURLSession sharedSession]
downloadTaskWithURL:imageURL completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
UIImage *image = [UIImage imageWithData:
[NSData dataWithContentsOfURL:location]];
myCell.imageview.image = image;
}];
[imageDownloadTask resume];
return myCell;
}
You can use the dispatcher to create an async operation for the download of the images. This will resolve the 2 problems you have:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [NSData dataWithContentsOfURL:YOUR_IMAGE_URL];
UIImage *img = [UIImage imageWithData:imgData];
[YOUR_IMAGE_VIEW_OUTLET performSelectorOnMainThread:#selector(setImage:) withObject:img waitUntilDone:YES];
});
These are the snippet you have to change:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL: imageURL];
UIImage *img = [UIImage imageWithData:imageData];
[myCell.imageview performSelectorOnMainThread:#selector(setImage:) withObject:img waitUntilDone:YES];
});
return myCell;
}
Try to Register Nib For Collection View
Write following code in your viewController's viewDidLoad()method :
UINib *nib = [UINib nibWithNibName:#"MyCollectionCell" bundle: nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:#"Cell"];
And I think you have to use https://github.com/nicklockwood/AsyncImageView for the image loading in collection view.
For Storyboards you have to see this tutorial : http://www.appcoda.com/ios-programming-uicollectionview-tutorial/ This will help you more.
Thanks!
For the first question the answer is in this line of code:
NSData * data = [NSData dataWithContentsOfURL:url];
From Apple Reference:
Do not use this synchronous method to request network-based URLs. For
network-based URLs, this method can block the current thread for tens
of seconds on a slow network, resulting in a poor user experience, and
in iOS, may cause your app to be terminated.
As alternative you can use NSURLSessionDataTask to download data (see Apple Reference)
-Edit
In ProfileViewController.h add these two properties:
#property (nonatomic, strong) NSURLSessionConfiguration *sessionConfig;
#property (nonatomic, strong) NSURLSession *session;
then, in - viewDidLoad initialise them:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view
self.sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfig];
//Other stuff...
}
Finally, in ProfileViewController.m
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSURLSessionDownloadTask *imageDownloadTask = [self.session dataTaskWithURL:imageURL
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"ERROR: %#", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200) {
UIImage *image = [UIImage imageWithData:data];
myCell.imageview.alpha = 0.0f;
myCell.imageview.image = image;
[UIView animateWithDuration:0.45 animations:^{
myCell.imageview.alpha = 1.0f;
});
} else {
NSLog(#"Couldn't load image at URL: %#", imageURL);
NSLog(#"HTTP %d", (int)httpResponse.statusCode);
}
}
}];
[imageDownloadTask resume];
return myCell;
}
I hope this can help you.
- Edit 2
For future readers, I slightly refactored my code based on #suhit's answer (+1 for him)
I'm calling this API and it's jsonobject in a segue, and trying to push it into a view controller, but it's not carrying the data. In my Below code it prints just fine in the call, but the other two prints come up with null.
Is there something I'm missing to make the data persistent?
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showChangeDetail"]) {
NSIndexPath *indexPath = nil;
BNRItem *item = nil;
//BDItemChangeDetailAPI *itemAPI = nil;
NSArray *items = [[BNRItemStore sharedStore] allItems];
if (self.searchDisplayController.active) {
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
item = [searchResults objectAtIndex:indexPath.row];
} else {
indexPath = [self.tableView indexPathForSelectedRow];
//item = items[indexPath.row];
item = [items objectAtIndex:indexPath.row];
}
NSLog(#"111111%#", self.APIItem);
[self fetchFeedAPIChangeDetail];
NSLog(#"222222%#", self.APIItem);
BDChangeApproveController *destViewController = segue.destinationViewController;
destViewController.itemAPI = self.APIItem;
}
}
- (void)fetchFeedAPIChangeDetail
{
//NSString *changeorder = changeOrder;
// NSString *requestString = [#"http://URL.com];
NSString *requestString = #"http://URL.com";
NSURL *url = [NSURL URLWithString:requestString];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask =
[self.session dataTaskWithRequest:req
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error){
NSDictionary *jsonObject1 = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
//NSLog(#"%#", jsonObject1);
self.APIItem = jsonObject1[#"CoDetail"];
NSLog(#"%#", self.APIItem);
}];
[dataTask resume];
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// show loading indicator
__weak typeof(self) weakSelf = self;
[[BNRItemStore sharedStore] fetchFeedAPIChangeDetail:^(NSArray *array, NSError *err)
{
[weakSelf performSegueWithIdentifier:#"showChangeDetail" sender:weakSelf];
// hide loading indicator
}];
}
As you can see I have two methods tuula and wendyslookbook. Then I call them both in my mostPopular method. I have requested the photos from the Instagram API but now I want to put these two user photos together. How can I do that?
//
// PhotosViewController.m
// Photo Bombers
//
// Created by Alex Macleod on 20/8/14.
// Copyright (c) 2014 Alex Macleod. All rights reserved.
//
#import "PhotosViewController.h"
#import "PhotoCell.h"
#import "DetailViewController.h"
#import "PresentDetailTransition.h"
#import "DismissDetailTransition.h"
#import <SimpleAuth/SimpleAuth.h>
#interface PhotosViewController () <UIViewControllerTransitioningDelegate>
#property (nonatomic) NSString *accessToken;
#property (nonatomic) NSArray *photos;
#end
#implementation PhotosViewController
- (instancetype) init {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
layout.itemSize = CGSizeMake(106.0, 106.0);
layout.minimumInteritemSpacing = 1.0;
layout.minimumLineSpacing = 1.0;
return (self = [super initWithCollectionViewLayout:layout]);
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Fashun";
[self.collectionView registerClass:[PhotoCell class] forCellWithReuseIdentifier:#"photo"];
self.collectionView.backgroundColor = [UIColor whiteColor];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
self.accessToken = [userDefaults objectForKey:#"accessToken"];
if (self.accessToken == nil) {
[SimpleAuth authorize:#"instagram" options:#{#"scope": #[#"likes"]} completion:^(NSDictionary *responseObject, NSError *error) {
self.accessToken = responseObject[#"credentials"][#"token"];
[userDefaults setObject:self.accessToken forKey:#"accessToken"];
[userDefaults synchronize];
[self mostPopular];
}];
} else {
[self mostPopular];
}
}
- (void)tuula {
NSURLSession *session = [NSURLSession sharedSession];
NSString *urlString = [[NSString alloc]initWithFormat:#"https://api.instagram.com/v1/users/7522782/media/recent/?access_token=%#", self.accessToken];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(#"links: %#", location);
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)wendyslookbook {
NSURLSession *session = [NSURLSession sharedSession];
NSString *urlString = [[NSString alloc]initWithFormat:#"https://api.instagram.com/v1/users/14454619/media/recent/?access_token=%#", self.accessToken];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(#"links: %#", location);
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)mostPopular {
[self tuula];
[self wendyslookbook];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.photos count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"photo" forIndexPath:indexPath];
cell.backgroundColor = [UIColor lightGrayColor];
cell.photo = self.photos[indexPath.row];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *photo = self.photos[indexPath.row];
DetailViewController *viewController = [[DetailViewController alloc]init];
viewController.modalPresentationStyle = UIModalPresentationCustom;
viewController.transitioningDelegate = self;
viewController.photo = photo;
[self presentViewController:viewController animated:YES completion:nil];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source {
return [[PresentDetailTransition alloc]init];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
return [[DismissDetailTransition alloc]init];
}
#end
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 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];
}