I have a working UICollectionViewCell in UITableViewCell. I'm using HWViewPager, so the collectionview cell moves from left to right. Unfortunately, the data is not updated until the user scrolls to the left or to the right. The content that fills up the cell is fetched from json, so I figure that has something to do but I'm not sure what. I load everything in awakeFromNib.
- (void)awakeFromNib {
] videoArray = [[NSMutableArray alloc] init];
[self getDisco];
}
with getDisco being a void function.
- (void)getDisco
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
videoArray = [NSMutableArray arrayWithArray:[responseObject valueForKey:#"releases"]];
// NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Now, where the problem is.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.item < [videoArray count]){
DiscoCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CollectionCell2" forIndexPath:indexPath];
NSDictionary *shot = [videoArray objectAtIndex:[indexPath row]];
cell.label2.text = [shot objectForKey:#"title"];
return cell;
return nil;
}else{
DiscoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CollectionCell2" forIndexPath:indexPath];
cell.label2.text = [NSString stringWithFormat:#"Cell %d", indexPath.row];
return cell;
}
}
Without the if/else statements, the viewcontroller crashed completely. With it, nothing updates till the user scrolls. My question is how do I get it all to pre-load, without crashing, for the user? Please keep UICollectionViewCell is in a tableviewcell.
You should reload collectionView after finished the request:
- (void)getDisco
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://musicbrainz.org/ws/2/release/?query=arid:e0140a67-e4d1-4f13-8a01-364355bee46e%20AND%20primarytype:single&fmt=json&limit=100" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
videoArray = [NSMutableArray arrayWithArray:[responseObject valueForKey:#"releases"]];
// NSLog(#"JSON: %#", responseObject);
[collectionView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Related
I'm having a problem which is similar to others on SE, in that my UITableView controller loads the text label immediately, but only loads my thumbnail image when I scroll the view and move the item offscreen.
I tried adding [self.tableView reloadData] to the AFHTTPRequestOperation setCompletionBlockWithSuccess, which works with one drawback. It obviously runs too often.
Here is the method in which the problem occurs:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *fullPath;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TableViewCell" forIndexPath:indexPath];
Child *child = _children[indexPath.row];
if([child.data.thumbnail length] == 0) {
fullPath = #"reddit.png";
} else {
// Get the thumbnail
NSURL *url = [NSURL URLWithString:child.data.thumbnail];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
fullPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[url lastPathComponent]];
[operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:fullPath append:NO]];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"bytesRead: %lu, totalBytesRead: %lld, totalBytesExpectedToRead: %lld", (unsigned long)bytesRead, totalBytesRead, totalBytesExpectedToRead);
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// [self.tableView reloadData];
NSLog(#"RES: %#", [[[operation response] allHeaderFields] description]);
NSError *error;
if(error) {
NSLog(#"ERR: %#", [error description]);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"ERR1: %#", [error description]);
}];
[operation start];
}
cell.textLabel.text = child.data.title;
cell.imageView.image = [UIImage imageNamed:fullPath ];
return cell;
}
Instead of reloading the entire table view every time an image is loaded, you could just set that image directly on the cell inside you completion block.
HOWEVER, if you do that you need to check that the cell is still visible and that it is still on the same index path it was on when you started loading the view, otherwise you might be setting the image on a cell that has been reused and is now in a different position in the table view.
I am fetching data from the website and loading on the tableViewController. Tableviewcontroller is inside the tabbarcontroller. Whenever I clickked on tabbar, tableview data does not populated. However once I click other viewcontrollers and then click again on tableviewcontroller, then data populated.
#import "GetBookViewController.h"
#import "AFNetworking.h"
#interface GetBookViewController ()
#end
#implementation GetBookViewController
#synthesize booksArray;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated
{
[self loadData];
}
-(void)viewDidAppear:(BOOL)animated
{
[self.tableView reloadData];
}
-(void) loadData
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:#"http://XXXXXX.com/coursera/books.php" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
if ([[responseObject valueForKey:#"status"] isEqualToString:#"success"]) {
int count = [[responseObject valueForKey:#"total"] integerValue];
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count];
for (int i = 1; i <= count; i++) {
NSString *obj = [NSString stringWithFormat:#"%i", i];
[array addObject:[responseObject objectForKey:obj]];
}
booksArray = array;
for (id obj in booksArray) {
NSLog(#"%#", [obj valueForKey:#"title"]);
}
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [booksArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel* label = (UILabel*)[cell viewWithTag:100];
NSString *title = [[booksArray objectAtIndex:indexPath.item] valueForKey:#"title"];
label.text = title;
return cell;
}
You aren't doing anything once you receive a response from the network and populate your array?
What you need to do is notify the table view that it needs to query its data source again to refresh its values. Simply calling reloadData on your table view once you have your array would to the trick:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:#"http://ilyasuyanik.com/coursera/books.php" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
if ([[responseObject valueForKey:#"status"] isEqualToString:#"success"]) {
int count = [[responseObject valueForKey:#"total"] integerValue];
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count];
for (int i = 1; i <= count; i++) {
NSString *obj = [NSString stringWithFormat:#"%i", i];
[array addObject:[responseObject objectForKey:obj]];
}
dispatch_async(dispatch_get_main_queue,^{
booksArray = array;
for (id obj in booksArray) {
NSLog(#"%#", [obj valueForKey:#"title"]);
}
//now you can update your table view
[self.tableView reloadData];
});
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
I have a UITableView in a ViewController which contains a custom cell.
When the view first loads, the indexPathForCell in the following code returns the indexPath without problems:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PostCell *postCell = (PostCell *)[tableView dequeueReusableCellWithIdentifier:#"PostCell"];
if (postCell == nil) {
NSLog(#"EmptyCell Found");
}
NSDictionary *object = [postArray objectAtIndex:indexPath.row];
NSString *imageURL = [object objectForKey:#"imageURL"];
NSIndexPath *originalIndexPath = indexPath;
NSLog(#"Original IndexPath %#", originalIndexPath);
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:[NSURL URLWithString:imageURL]
options:indexPath.row == 0 ? SDWebImageRefreshCached : 0
progress:^(NSInteger receivedSize, NSInteger expectedSize){}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished){
if (image) {
// This returns correctly on first load
NSIndexPath *currentIndexPath = [imageTableView indexPathForCell:postCell];
NSLog(#"Current IndexPath %#", currentIndexPath);
}
}
];
}
After refreshing the tableView, currentIndexPath is always (null).
The following is my refresh code:
- (void)refreshMainView {
AFHTTPRequestOperation *downloadPostOperation = [[AFHTTPRequestOperation alloc] initWithRequest:serviceRequest];
[downloadPostOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//[tableView beginUpdates];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:urlData options:kNilOptions error:&error];
NSMutableArray *newPostArray = [json objectForKey:#"posts"];
// Replacing the old array with new array
postArray = newPostArray;
[self stopRefresh];
//[tableView endUpdates]
[imageTableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self stopRefresh];
}];
If I just perform [tableView reloadData] without performing refreshMainView, there will not be any problem with getting the currentIndexPath.
There must be something I am overlooking, could someone please help me? Thank you!
Edit:
I have tried [postCell.postImageView setImageWithURL:[NSURL URLWithString:imageURL] placeholderImage:nil]; instead and the refreshing works, so I am suspecting that something is wrong with me getting the indexPath in the completed block, can anyone help out please? I need the completed block as I am doing some image processing.
Hi I have finally fixed it.
For people who are needing answers, just add
dispatch_async(dispatch_get_main_queue(), ^{
});
around the portion that is retrieving the indexPathForCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PostCell *postCell = (PostCell *)[tableView dequeueReusableCellWithIdentifier:#"PostCell"];
if (cell == nil)
{
nib = [[NSBundle mainBundle] loadNibNamed:#"PostCell" owner:self options:nil];
}
NSIndexPath *originalIndexPath = indexPath;
NSLog(#"Original IndexPath %#", originalIndexPath);
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:[NSURL URLWithString:imageURL]
options:indexPath.row == 0 ? SDWebImageRefreshCached : 0
progress:^(NSInteger receivedSize, NSInteger expectedSize){}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished){
if (image) {
// This returns correctly on first load
NSIndexPath *currentIndexPath = [imageTableView indexPathForCell:postCell];
NSLog(#"Current IndexPath %#", currentIndexPath);
}
}
];
use this it may help you
I am using AFNetworking 1.2 to create an App that displays the tweets from the user. The app already successfully authenticates the user but doesn't display the tweets. Here is what I am doing to receive the Tweets.
- (void)fetchTweets
{
self.twitterClient = [[AFOAuth1Client alloc] initWithBaseURL:[NSURL URLWithString:#"https://api.twitter.com/1.1/"] key:#"4oFCF0AjP4PQDUaCh5RQ" secret:#"NxAihESVsdUXSUxtHrml2VBHA0xKofYKmmGS01KaSs"];
[self.twitterClient authorizeUsingOAuthWithRequestTokenPath:#"/oauth/request_token" userAuthorizationPath:#"/oauth/authorize" callbackURL:[NSURL URLWithString:#"floadt://success"] accessTokenPath:#"/oauth/access_token" accessMethod:#"POST" scope:nil success:^(AFOAuth1Token *accessToken, id responseObject) {
[self.twitterClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self.twitterClient getPath:#"statuses/user_timeline.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *responseArray = (NSArray *)responseObject;
tweets = responseArray;
[responseArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Success: %#", obj);
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
} failure:^(NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Here is how I am attempting to load the received Tweets into to the UITableView:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *text = [tweet objectForKey:#"text"];
NSString *name = [[tweet objectForKey:#"user"] objectForKey:#"name"];
cell.textLabel.text = text;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", name];
return cell;
}
I have added the Cell Identifier in Storyboard already, so that is not the issue.
[tableView reloadData];
Reload table after fetching all tweets and assigning it to array
means
- (void)fetchTweets
{
self.twitterClient = [[AFOAuth1Client alloc] initWithBaseURL:[NSURL URLWithString:#"https://api.twitter.com/1.1/"] key:#"4oFCF0AjP4PQDUaCh5RQ" secret:#"NxAihESVsdUXSUxtHrml2VBHA0xKofYKmmGS01KaSs"];
[self.twitterClient authorizeUsingOAuthWithRequestTokenPath:#"/oauth/request_token" userAuthorizationPath:#"/oauth/authorize" callbackURL:[NSURL URLWithString:#"floadt://success"] accessTokenPath:#"/oauth/access_token" accessMethod:#"POST" scope:nil success:^(AFOAuth1Token *accessToken, id responseObject) {
[self.twitterClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self.twitterClient getPath:#"statuses/user_timeline.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *responseArray = (NSArray *)responseObject;
tweets = responseArray;
[tableView reloadData];
//^ Add this line
[responseArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Success: %#", obj);
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
} failure:^(NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Note : tableView is your tableview name
I am trying to populate a UITableView with a remote JSON file. I am able to grab the JSON in the repsonseObject but am having trouble with the TableView. I am storing the JSON in an array.
My request looks like this:
- (void)makeJSONRequest
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://www.tylacock.com/cheats.json" parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.jsonFromAFNetworking = [responseObject objectForKey:#"ps3"];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
And my cellForRowAtIndexPath method looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *tempDict = [self.jsonFromAFNetworking objectAtIndex:indexPath.row];
cell.textLabel.text = [tempDict objectForKey:#"name"];
return cell;
}
I have checked to make sure the data source is connected to the ViewController. I was actually able to accomplish this with AFNetworking 1.X but since the upgrade and method changes I am at a loss.
You're loading the data asynchrously, so you've got to call [self.tableView reloadData] after setting jsonFromAFNetworking.