My application consists of data downloaded from an XML file. data contains short text and images.
currently I'm downloading up all data and building up the view in a view controller, in the ViewDidLoad method, which causes the application not to show up the root view until all data is downloaded. I want it to show up in a more user friendly way, at least to preload some of the data during the splash screen.
By the way I've done the lazy image loading so images can load while the main view is displayed.
As long as the number of views depend on number of rows in XML, loading XML asynchronously while building up the the view does not suite my need (or maybe I'm wrong).
I understand that describing the solution in an answer is quite a challenge, so maybe you could point to an article or even a book that has a detailed explanation of asynchronous and multithread handling.
I don't see why you can't load it asynchronously o_O
You should show some "Loading" view anyway (preferably with an activity Indicator)
A progress bar would be nice, too.
And when it's done downloading you just reload and relayout your view.
If by "number of views" you mean the number of cells in a table row you can just tell the tableview to reload all data whereas your numberOfRowsInSection function (or whatever you want to use) should return appropriate values depending on whether it's loading or not.
EDIT: you shouldn't do that while the application is still loading because that's extremely user-unfriendly and slows down the loading of the application aswell
I think you should parse all data in didFinishLaunchingWithOptions: method of appDelegate and then use following methods to do parsing.
[self performSelectorInBackground:#selector(downloadData:) withObject:nil];
method downloadData: contain parsing procedure.
Related
I am loading data of NSArray into UITableView . Its going ok. I really confuse to show UIActivityindicator at time of loading uitableview.
So please, give guideline, sample code.
Thanks.
No matter how much data you have (how many elements your NSArray model contains), only the visible cells will be needed for the table view, that is small. So if you already have you model data loaded then you don't need an activity monitor.
If you are talking about acquiring the data prior to refreshing the table view (filling your array based data model), or downloading data from a remote URL then you will need to do this in a background thread so that the main thread is free to update your UI (specifically your activity indicator). Once your data is ready you reload your table view on the main thread.
NSObject has a number of convenience methods to achieve this including
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
Except if you have a LOT of data in your array, or if some data come from the internet, the loading of your UITableView (well, the cells that are displayed) should take less than a frame, so it is useless to try to display a UIActivityIndicator in this case.
I have a UITableView which loads its data from the web. It takes a while to load this data and therefore I would like an acitivity indicator to animate while the data is loading. I am doing the following in my attempt to make this work:
1) In viewDidLoad I add an observer to listen to when the data loading is done and after that I call loadDataFromWeb
2) loadDataFromWeb creates the activity indicator, adds it as a subview to self.view and then it loads the data. At last it posts a notification (the one that viewDidLoad observes) to indicate that the loading process is done.
3) Finally, when the observer catches the post from loadDataFromWeb, it calls removeLoadingScreen to remove the indicator.
Pretty obvious I am not seeing my indicator view. If I comment out the line that removes the indicator, it stays on the screen when everything is loaded. I am aware that I'm probably messing around with which methods are called when in the process, and this is where I need help.
I should mention that the whole purpose is that instead of the user's looking at a screen on which nothing is happening (while the data loads), I want a activity indicator to show up to indicate that there's something going on here.
Thanks
#Muncken have a look at this MBProgresHUD project, this will help you a lot to do a downloading progress in background (secondary thread not main thread) and shows a activity indicator over you view -
https://github.com/matej/MBProgressHUD
I am processing several large RSS feeds and displaying results in a TableView. The processing starts after the user clicks on the relevant tab. All works well, but as it takes a couple of seconds to process, the NIB and Table don't load until the processing finishes and it looks like the iPhone has seized up. I have added an Activity indicator to the NIB, but because it doesn't load until the table is ready to display, it appears too late to be of any use.
Does anyone have any ideas how to display a message to a user while the table builds/loads? I have tried loading a UIView first and adding the Table as a subview but, again, both seem to load only after the table is ready.
Guidance appreciated.
It's kind of hard to guess what's going on from your description but it looks like your calls aren't asynchronous. Here's what you should be doing in your code:
Make all calls asynchronous. You said your phone is seizing up. Makes it sound like your requests and responses are happening on the main thread. There are many libraries you could use to handle asynchronous calls. ASIHTTPRequest for one example....
Don't wait for the data to come in before displaying the tableView. It's a design principle that you load as much of the UI as possible so that the user has something to look at while your data loads up in the background. What you should be doing is initializing an NSMutableArray to hold the data. Initially this array will contain no objects. This is the array that you use in your data source methods: Use array size for numberOfRowsInSection and use the array objects in cellForRowAtIndexPath. Once your RSS feed XML comes in and is parsed, store that in your arrays and call [tableView reloadData]. This way you don't leave your users looking at a blank screen. (Another good practice is when the array size is zero, show one cell in your tableview that says "data is loading" or something).
When you first initialize and load up your table and then fire off those RSS feed requests, that's where you show an activity indicator view on the tableView. Stop animating the indicator when the RSS data comes in and your tableView reloads.
These are the standard steps you should follow while showing non local data in a tableview. Makes for a smooth user experience.
Like I said before, it seems from your question that your calls are not asynchronous. If I'm wrong, correct me and let's take it from there...
In my UIView I've got a UITableView (UITV) which is controlled by an NSFetchedResultsController (NSFRC). The UIView is inside a UINavigationController.
When the view is about to be loaded/displayed I start some background activities which fetch data from a remote server (JSON) and parse into Core Data.
The NSFRC is being called when the parsing is done and the threaded NSManagedObjectContext have been merged into the main context.
The problem is that sometimes many rows are being inserted to Core Data at once, a lot of table cells are being added and there is quite a delay from that the actual fetching and parsing is done, until the rows are being displayed.
Now I wonder if anyone knows of any solution to, for example:
hook up a spinner to some "fetched results controller inserted all its rows for this time" (or something) notification/delegate call to at least tell the user that "something is going to show up soon"?
Or might the best solution simply be to not initialize the NSFRC until the background fetching and processing is completed?
Thanks!
If I understand your question correctly, you may want to look into the NSFetchedResultsControllerDelegate methods, with documentation available here: http://developer.apple.com/library/ios/#documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html
There are delegate methods available for pre changes with controllerWillChangeContent:, post changes with controllerDidChangeContent and during changes with didChangeSection: and didChangeObject.
I hope it helps!
Rog
I'm using the three20 project for my iPhone app. I've narrowed my problem down and I'm now just trying to re-create the 'Web Images in Table' example that comes with the project. I've copied the code exactly as in the project, with the exception that I do not use the TTNavigator (which the example does) but I am adding my TTTableViewController manually to a tabBar.
The problem is as follows; the images in the table should load automatically from the web, like in the example. But they only load after I scroll the table up and down.
In the console it clearly says it is downloading the images, and you see the activity indicator spinning like forever.. And unless I scroll up and down once, the images will never appear.
Anyone? Thanks in advance.
P.S:
If I'm using this code in any random UIView, It also doesn't work (only shows a black square):
TTImageView* imageView = [[[TTImageView alloc] initWithFrame:CGRectMake(30, 30, 100, 100)] autorelease];
imageView.autoresizesToImage = YES;
imageView.URL = #"http://webpimp.nl/logo.png";
[self.view addSubview:imageView];
If I put this code in my AppDelegate (right onto the window), it does work .. strange?
POSSIBLE SOLUTION:
Although I stopped using TTImageView for this purpose, I do think I found out what the problem was; threading (hence accepting the answer of Deniz Mert Edincik). If I started the asynchronous download (because basically that is all the TTImageView is, an asynchronous download) from anywhere BUT the main thread, it would not start. If I started the download on the main thread, it would start immediately..
Sounds like a threading problem to me, are you creating TTImageView in the main runloop?
I find one interesting thing. When I use combination TTTableViewController, TTTableViewDataSource and TTModel I have same problem with loading TTImageView. My problem was, that my implementation of Model methods 'isLoading' and 'isLoaded' don't return proper values after initialization of model. That forces me to call reload on model manualy in 'viewDidAppear' method and that causes image loading problem. So I repair my 'isLoading' and 'isLoaded' methods to both return 'NO' after Model init, and everything is fine.
When an image finishes loading try sending a reloadData message to the table view. This forces the table to recalculate the size of the rows and redraw the table. Just be careful that you don't start downloading the image again in response to this message.
I've written something similar to this where an image view will load its own image from the web.
Im my experience, when the image had loaded successfully but was not shown in its view, it was a case that the cell needed to be told to redraw.
When you scroll the table view, the cells are set to redraw when the come onscreen, which is why they appear when you scroll.
When the image loads, tell the cell that it is sitting in to redraw by sending it the message setNeedsDisplay.
That way, when the image finishes downloading, the cell its sitting in (and only that cell) will redraw itself to show the new image.
It's possible that you might not need to redraw the entire cell and might be able to get away with simply redrawing the image view using the same method call. In my experience, my table cells view hierarchy was flattened, so I had to redraw the whole cell.
I don't have an answer for what you want to do, but I will say that this is considered a feature, and the expected behavior. You use TTImageView in UITableView when you want to do lazy loading of images. TTImageView will only load the images whose frames are visible on the screen. That way, the device uses its network resources to download images that the user has in front of them, rather than a bunch of images that the user isn't even trying to look at.
Consider having a long list that may contain a couple hundred thumbnail images (like a list of friends). I know from experience that if you kick off 100+ image requests on older devices, the memory usage will go through the roof, and your app will likely crash. TTImageView solves this problem.
This is a thread problem. You can load the images by including the line:
[TTURLRequestQueue mainQueue].suspended = NO;
in - (void)didLoadModel:(BOOL)firstTime.