uitableview should load after retreving data from webservice with huge data - iphone

I have a requirement that my UITableview should load data after retrieving data from web service. When retrieving huge data, my uitableview is displaying empty. Instead of that, a UIActivityIndicator should appear until data is loaded into the UITableview.
I am trying as below, but not able to get the desired functionality. Please help.
Also let me suggest what is the best approach to load data into UITableview, when data returned from webservice is huge.
Thanks in advance.
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UILabel *lblName = (UILabel *)[cell viewWithTag:1];
[lblName setText:[myArray objectAtIndex:[indexPath row]]];
return cell;
}
- (void)dataLoading
{
myActivityIndicator=[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[myActivityIndicator setFrame:CGRectMake(140, 170, 40, 40)];
[self.view addSubview:myActivityIndicator];
[myActivityIndicator startAnimating];
NSString *playersDatalink = [NSString stringWithFormat:#"Webservice link"];
NSURL *JsonPlayersDataURL = [NSURL URLWithString:playersDatalink];
NSString *JsonPlayersData = [[NSString alloc] initWithContentsOfURL:JsonPlayersDataURL];
SBJSON *playersDataParser = [[SBJSON alloc] init];
NSDictionary *PlayersDicdata = (NSDictionary *) [playersDataParser objectWithString:JsonPlayersData error:nil];
NSDictionary *playersdata = (NSDictionary *) [PlayersDicdata objectForKey:#"players"];
NSLog(#"palyersdata is =%#",playersdata);
self.myArray = [NSMutableArray arrayWithCapacity:[playersdata count]];
for (NSDictionary *details in playersdata) {
[self.myArray addObject:[details objectForKey:#"teamid"]];
}
if ([playersdata count]==0) {
UIAlertView *myalert = [[UIAlertView alloc]initWithTitle:#"Webserive error " message:#"No data returned from webservice" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[myalert show];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:#selector(dataLoading) withObject:nil afterDelay:0.0];
[myActivityIndicator stopAnimating];
}

hi Download This zip http://www.sendspace.com/file/l48jxg Unzipe this file you getting two .h and .m for loading Indicatore view,. drag and drop this into Your Project.
Now you can use this like Bellow:-
if you wish to show Activity Indicator till you data not Load:-
import LoadingView.h into your Class,
create Object
loadingView =[LoadingView loadingViewInView:self.view:#"Please Wait.."];
at this time put this code of like olso yourTableView.userInterfaceEnable=FALSE;
and at the data Load finish method put this
[loadingView removeFromSuperview];
yourTableView.userInterfaceEnable=TRUE;
you getting loading View like:-
UPDATE
It doesn't metter your TableView delegate executing first.
1) If you Using NSURLConnection For Parsiong WebServices you can Reload Yout TableView Data after loading Finish at:-
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//your code
[yourTableView reloadData];
}
2) if you using NSXMLParser For Parsiong WebServices you can Reload Yout TableView Data after loading Finish at:-
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
//your code
[yourTableView reloadData];
}

Try this Activity Indicator which stops the user interaction until your data is loaded.
use MBProgressHud available on github
Have a Happy Coding..

Related

iPhone - Make UITableViewCells appear on view load before NSURLConnection completes

I am trying to create a loose version of LazyTabelImages using storyboard and JSON. in ViewDidLoad on my main TableViewController, I start an NSURLConnection to get the JSON data, but my cells do not load until after the connection is completed. I want the same behavior that LazyTableImages has, where the cells load as blanks, but then have the information filled in (reload the table data). I can duplicate this if I do not use storyboard, as LazyTables does not use storyboard, but that is not an option.
I have looked through LazyTableImages to try to find the solution, but storyboard make a big difference (to me anyway).
Is there a simple way to get the cells to load as blanks? For example, if the device has no internet, I still want my TableView to show up, and I will put a custom message in the cell.
Code:
The part of my viewDidLoad where I initialize the connection....
NSURLRequest *urlrequest = [NSURLRequest requestWithURL:[NSURL URLWithString:serverURL]];
self.dataConnection = [[NSURLConnection alloc] initWithRequest:urlrequest delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
connectionDidFinnishLoading...
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//ListData below is an array that my data received (JSON) is loaded into. It is then passed to getTableData.
self.dataConnection = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performSelectorOnMainThread:#selector(getTableData:) withObject:ListData waitUntilDone:YES];
});
}
getTableData...
-(void)getTableData:(NSData *)jsonData
{
NSError *error = nil;
arrayEntries = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&error];
for (int x = 0; x < arrayEntries.count; x++)
{
NSMutableDictionary *dic = [arrayEntries objectAtIndex:x];
//ARecord is a class just like in LazyTableImages that creates objects to keep the icons/data together. The ARecords are loaded into the TableView
ARecord *arecord = [[ARecord alloc] init];
NSString *title = [dic objectForKey:#"title"];
NSString *subt = [dic objectForKey:#"subtitle"];
NSString *url = [dic objectForKey:#"image_URL"];
arecord.Icon = nil;
arecord.URL = url;
arecord.Name = title;
arecord.title = subt;
//this is where I load an array full of the arecord objects.
[array addObject:arecord];
}
[self.tableView reloadData];
}
I've done something similar. In viewDidLoad: I set the array for table data to a few objects of [NSNull null] for however many blank rows I want to show while the data is downloading. In cellForRowAtIndexPath: I check if [self.arrayOfTableData objectAtIndex:indexPath.row] = [NSNull null]. If so return a "blank" cell, otherwise load the cell with ARRecrod data.
Then when the URL completes, replace the array of NSNulls with array of your ARRecords.
I do this with two objects. First, I have an image fetcher class that downloads data asynchronously and notifies a delegate when it's complete. Then I have an image view class that implements the fetcher's delegate methods. So something like:
#implementation AsyncImageFetcher
-(id)initWithURL:(NSURL *)aURL andDelegate:(id<SomeProtocol>)aDelegate{
//...
NSURLRequest *req = [NSURLRequest requestWithURL:aURL];
//Note that NSURLConnection retains its delegate until the connection
//terminates! See comments in MyImageView below.
[NSURLConnection connectionWithRequest:req delegate:self];
//...
}
//Implement standard connection delegates here. The important part is:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
// ...
UIImage *anImage = [self decodeDownloadedDataIntoAnImage];
if([[self delegate] respondsToSelector:#selector(imageFetcher:didFetchImage:)]){
[[self delegate] imageFetcher:self didFetchImage:anImage];
}
//...
}
#end
Then I subclass UIImageView or UIView or something (depending on how flexible you need to be) to implement the delegate protocol and fire off the fetcher:
#implementation MyImageView
-(id)initWithURL:(NSURL *)aURL andPlaceHolderImage:(UIImage *)aPlaceHolder{
//...
[self setImage:aPlaceHolder];
//Note we don't assign this to an ivar or retain it or anything.
//That's ok because the NSURLConnection inside the fetcher actually
//retains the fetcher itself. So it will live until the connection
//terminates -- which is exactly what we want. Thus we disable
//CLANG's noisy warnings.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
[[AsyncImageFetcher alloc] initWithURL:aURL andDelegate:self];
#pragma clang diagnostic pop
return self;
}
-(void)imageFetcher:(MCMAsyncImageFetcher *)anImageFetcher didFetchImage:(UIImage *)anImage{
[self setImage:anImage];
}
#end
In your specific case, you'd just set a MyImageView as your cell's imageView in -tableView:cellForRowAtIndexPath:, passing reasonable values for its placeholder and URL, of course.
Since I haven't see your code, I just give my suggestion here:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create(NULL, NULL);
dispatch_async(queue, ^{
//add your connection code here
//parse the json and store the data
//
dispatch_async(dispatch_get_main_queue(), ^{
//here to reload your table view again,
//since UI related method should run on main thread.
[YOUR_TABLEVIEW reloadData];
});
});
[YOUR_TABLEVIEW reloadData];
}
Note: Make sure your tableview in storyboard has connected to that in code! Hope it helps!

How to refresh after updating core data value in table view cell

I'm using core data in my app.I have an two view controller one viewcontroller show the list of book names after selecting anyone of the book move to second view controller for using the update button to update the value as 1 that will be show in core data table.Now back to main viewcontroller and after selecting same book doesnot show the value in secondviewcontroller but core data table having a value as 1. how to reload main viewcontroller in table view with core data table value .plz anyone known help me.
Here the source code below
- (void)viewDidLoad
{
[super viewDidLoad];
if(dictionary!=nil)//net is not connected fetch core data to display the booknames
{
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#" Warning Message" message:#"You are not connect to internet so becoz of loading default values" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alert show];
[self fetchValueFromDatabase];
}
}
-(void)fetchValueFromDatabase
{
NSFetchRequest *fech=[[NSFetchRequest alloc]init];
NSEntityDescription *entity=[NSEntityDescription entityForName:#"Bookname" inManagedObjectContext:self.managedObjectContext];
[fech setEntity:entity];
NSError *savingError=nil;
NSArray *allBook=[self.managedObjectContext executeFetchRequest:fech error:&savingError];
NSLog(#"Array count value:%i",allBook.count);
coreBookName=[allBook valueForKey:#"bookName"];
NSLog(#"all value:%#",coreBookName);
for(NSString *key in coreBookName)
{
NSLog(#"Key value:%#",key);
[insertBookname addObject:key];
}
coreVoteCount=[allBook valueForKey:#"vote"];
NSLog(#"All vote value:%#",coreVoteCount);
for(NSString *key in coreVoteCount)
{
[bookCount addObject:key];
NSLog(#"Key value:%#",key);
}
for(NSArray *key in allBook)
{
[addItems addObject:key];
NSLog(#"All items:%#",key);
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableview1 reloadData];
}
call your below method from (void)viewWillAppear:method
[self fetchValueFromDatabase];//call this from ViewWillAppear
Let me know it is working or not...
Happy Coding.!!!!
You are calling this in viewDidLoad [self fetchValueFromDatabase]; and [self.tableview1 reloadData]; this in viewWillAppear that is why you are not getting any updates in your table.
What you should do is call [self.tableview1 reloadData]; at the end of your function fetchValueFromDatabase
-(void)fetchValueFromDatabase
{
NSFetchRequest *fech=[[NSFetchRequest alloc]init];
NSEntityDescription *entity=[NSEntityDescription entityForName:#"Bookname" inManagedObjectContext:self.managedObjectContext];
[fech setEntity:entity];
NSError *savingError=nil;
........................
.......................
.......................
[self.tableview1 reloadData];
}

RootViewController - tableView:cellForRowAtIndexPath - Load image from assetsLibrary

StackOverflow friends and colleague programmers,
My RootViewController (a flowerTableView on a view) should display cell's with title, subtitle and an image thumbnail (loaded from the camera roll). A very basic table I guess.
All content is stored in 'Core Data' but the images are stored as imagePaths to the camera roll. Example: flower.imagePath = assets-library://asset/asset.JPG?id=1000000002&ext
Using the code at the bottom everything should run smoothly but it doesn't . When starting the App the title's and subtitle's are shown, but the images are not. When I press a cell, which display's the detail view, and pop back again to the main view the image for this specific cell is shown.
When I press 'Show All', a button on a toolbar which executes the following code
NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
[fetchRequest setPredicate:nil];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self.flowerTableView reloadData];
and reloads the table, all the beautiful flowers are now shown.
Why didn't the flowers be displayed the first time? Is this a caching problem?
When debugging this code the string: 'This debug string was logged after this function was done' was logged after loading the table on starting the app, not after pressing 'Show All'
This means that all images are loaded from the camera roll successfully but attached to the cell after the cell was displayed and therefore not shown.
The same line is printed as intended when pressing 'Show All'
Hope someone can tell me what's going on here and even better, what to change in my code to make this work. I'm stuck at the moment...
Thank for helping me out!
Edwin
:::THE CODE:::
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath
{
Flower *flower = [fetchedResultsController_ objectAtIndexPath:indexPath];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
// Display the image if one is defined
if (flower.imagePath && ![flower.imagePath isEqualToString:#""])
{
// Should hold image after executing the resultBlock
__block UIImage *image = nil;
ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset *asset)
{
NSLog(#"This debug string was logged after this function was done");
image = [[UIImage imageWithCGImage:[asset thumbnail]] retain];
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error)
{
NSLog(#"Unresolved error: %#, %#", error, [error localizedDescription]);
};
[assetsLibrary_ assetForURL:[NSURL URLWithString:flower.imagePath]
resultBlock:resultBlock
failureBlock:failureBlock];
[cell.imageView setImage:image];
}
return cell;
}
-[ALAssetsLibrary assetForURL:resultBlock:failureBlock] runs asynchronously. That means that the call returns immediately in your tableView:cellForRowAtIndexPath: method. The cell is displayed in the table view before the actual loading of the asset has taken place.
What you need to do is set the image for the cell in the result block. Something like this:
if (flower.imagePath && ![flower.imagePath isEqualToString:#""])
{
ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset *asset)
{
NSLog(#"This debug string was logged after this function was done");
[cell.imageView setImage:[UIImage imageWithCGImage:[asset thumbnail]]];
//this line is needed to display the image when it is loaded asynchronously, otherwise image will not be shown as stated in comments
[cell setNeedsLayout];
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error)
{
NSLog(#"Unresolved error: %#, %#", error, [error localizedDescription]);
};
[assetsLibrary_ assetForURL:[NSURL URLWithString:flower.imagePath]
resultBlock:resultBlock
failureBlock:failureBlock];
}
Fellow Overflowist let me propose the following solution:
rather than creating your cells in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath
create an NSMutableArray populated with UITableViewCells (the same ones you create in the cellForRowAtIndexPath method) that you want to display in the table
and simply return the relevant UITableViewCell (which will be an object in the NSMutableArray) in the cellForRowAtIndexPath method.
This way the cellForRowAtIndexPath method will show cells which have already been loaded and are ready to be shown.

iPhone Core Data problems

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
BlogRssParser *blogRss = [[BlogRssParser alloc] init];
[blogRss setSelectedObject:selectedObject];
RssFunViewController *rssFun = [[RssFunViewController alloc] initWithNibName:#"RssFunViewController" bundle:nil];
[self.navigationController pushViewController:rssFun animated:YES];
[rssFun release];
}
This is my code so when the user taps the row, its supposed to take the value from the row and insert it into here:
NSString *terms = [[[self selectedObject] valueForKey:#"data"]description];
NSLog(#"%#", terms);
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://news.search.yahoo.com/rss?ei=UTF-8&p=%#&fr=news-us-ss", terms]];
But "terms" is showing up as (null) in the log? Not the value of the clicked row
I see, that u used some codes, I posted here for you. But you shouldnt just copy and paste it.
In my code selectedObject is not a member, as it is absolutely not necessary.
This line
NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
points to a non-member variable
while
[self selectedObject]
points to a member — a totally different thing.
edit
Is the second part in the TableViewContoller or in the DetailedView?

object crashes Application

i got an NSArray which gets filled in the init Method of my UITableViewController.
i use this object in "didSelectRowAtIndexPath" for pushing another tableviewcontroller.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ablogSingleCatTableViewController *singleCatTableViewController = [[ablogSingleCatTableViewController alloc] initWithStyle:UITableViewStylePlain category:[categories objectAtIndex:indexPath.row]];
[[self navigationController] pushViewController:singleCatTableViewController animated:YES];
[singleCatTableViewController release];
}
this works a few times when i start my application. after selecting a row and getting back to the main uitableview controller at a rondom point my application crashes after selecting a row.
with some nslogs i found out, that it crashes if i try to use my "categories" object.
so
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"before");
NSLog(#"cats: %#", categories);
NSLog(#"after");
ablogSingleCatTableViewController *singleCatTableViewController = [[ablogSingleCatTableViewController alloc] initWithStyle:UITableViewStylePlain category:[categories objectAtIndex:indexPath.row]];
[[self navigationController] pushViewController:singleCatTableViewController animated:YES];
[singleCatTableViewController release];
}
with that code my application crashes after "before" ... "after" never shows up.
i dont know why my "categories" object is crashing my application ?!
my categories object is defined in my header file and has a #property (nonatomic, retain). i synthesize it and releasing it in my dealloc method.
anyone has an idea?
// edit:
some more details here, because of the comments:
Debugger Console says: "Program received signal: “EXC_BAD_ACCESS”.
i create the category array like this:
- (void)initCategories {
NSString *path = [[NSBundle mainBundle] pathForResource:#"Categories" ofType:#"plist"];
[self setCategories:[[NSArray alloc] initWithContentsOfFile:path]];
}
calling this method in my initwithstyle method
[self initCategories];
my other custom initializing method looks something like this:
- (id)initWithStyle:(UITableViewStyle)style category:(NSDictionary*)cat {
if (self = [super initWithStyle:style]) {
currentCategory = cat;
items = [[NSMutableArray alloc] init];
self.title = [currentCategory objectForKey:#"TITLE"];
//XLog("%#", currentCategory);
}
return self;
}
ok, first thing is ;
[self setCategories:[[NSArray alloc] initWithContentsOfFile:path]];
you have a leak here. just use
categories = [[NSArray alloc] initWithContentsOfFile:path];
Crash occurs in here;
currentCategory = cat;
you have to retain, use;
currentCategory = [cat retain];
These are the problems I see in posted code, if you have not any mistake in the rest of the program, it should be fine with these fixes.
If you are creating your array something like this:
NSArray *tmpArray = [[NSArray alloc] initWithBlah ...];
Make sure that you assign it using the synthesized getter by using this code:
self.categories = tmpArray;
[tmpArray release];
If you do:
categories = tmpArray;
[tmpArray release];
the instance variable will not be retained at all.