Trying to figure out how data storage from UITableViews is ment to work. What is good practices when saving a UITableView data on e.g. viewDidDisappear.
Do I have to update an array with every changes made while working in the view, or can I collect all current values form the table on exit view?
Can someone point me in the right direction?
Thanks!
First, on when to save the data, I would suggest you save your data in this method instead of viewDidDisappear:.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Second, there are a bunch of ways to store data in iPhone applications, such as plist or sqlite3 database.
You are thinking about the problem the wrong way around. The UITableView only displays the data currently on screen. Its not a place to ever collect data from (other than user interaction which you should collect when they interact - didSelectRowAtIndexPath). Spend some time reading up on Model View Controller. The UITableView data should have COME from a model - the view should simply display it - so there is nothing to collect.
Related
I am working on iPad app. And I am using 2 tables in one view and images urls are coming from
web services. I am using Apple provided lazy loading for both tables, and there are 2 web-service called for showing the two tables data, one is calling in ViewDidLoad() and second is calling in callback method of first web service. And I am facing problem in this method.
- (void)appImageDidLoad:(NSIndexPath *)indexPath withDataReceived:(NSData*)receivedData
The values for indexpath.row values are changing every time , some time it gives correct value and some time not.
Can anybody please help me for that.
Thanks in advance.
you might have to pass in which tableview also.. you kno how it is passing indexPath to that method.. modify it to pass tableview.. and inside the method.. check which tableView and then get the right data source array for appropriate tableview..
So I implement UITableViewDataSource protocol using an NSFetchedResultsController.
I then modify the contents of the Core Data base and the NSFetchedResultsController then update the tableView..
Is there anyway to know when the tableView has done reloading the data?
We have a complex data model that is caching against a REST implementation, and it's difficult to determine if we need to get more data to fill up the screen (because the screen might be using complex filters against the raw data loaded). Also, the UITableViewCell objects are NOT guaranteed to be the same height.
The easy answer was to simply dump the data to core data, and use an NSFetchedResultsController to serve the data to the UITableView.
Here is how it works:
We added a tableview.tableFooterView that displays our "data loading" message.
Loading up a batch of data from the REST API and then using it update our Core Data objects.
This triggers the controllerDidChangeContent method to trigger, which then triggers a tableView reloadData (eg:)
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView reloadData];
}
We then basically then "Check" to see if the Footer is still visible 250ms later by calling a method like:
[self performSelector:#selector(checkIfFooterViewIsVisible) withObject:nil afterDelay:0.25];
- (void)checkIfFooterViewIsVisible
{
BOOL viewVisible = CGRectIntersectsRect(self.tableView.bounds,self.tableView.tableFooterView.frame);
if (viewVisible)
{
[self getMoreData];
}
We also check to see if the Footer is in view everytime we scroll.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self checkIfFooterViewIsVisible];
}
If we load the "last batch" of data, we actually just remove the tableViewFooter view object from the table (so it can't ever be visible).
So the answer is cool, because we can figure out if we need to pull more data, only if the user "needs" it. Either because there wasn't much visible data in the first batch, or because they have scrolled down and want more data. Checking the current placement of the tableFooterView lets us know if we have "painted" enough data on the screen.
The PROBLEM is - can I get rid of the:
[self performSelector:#selector(checkIfFooterViewIsVisible) withObject:nil afterDelay:0.25];
If we set the delay too fast, then UITableView doesn't have time to update the screen (and change the footer's position). If we update too slowly, then it feels like the app "stutters" as it loads data, and can load data slower than it could. But different iOS devices (and different network coverage) are going to mean slightly different timings, so the "let the UITableView update and check a bit later" works most of the time, but I feel like this could work smoother.
Is there anyway (maybe by overloading UITableView) that we can determine that the UITableView is "done" loading UITableViewCell objects? (at least until the next time the scroll moves?). Adding in this weird delay works well, but it would work cleaner if we knew definitively that the [tableview reloadDate] operation has completed.
I'm making a simple To-Do list app for the iPhone with a rails backend.
So far, I can pull all the tasks in a To-Do list from the web app, parse the JSON, and insert it into the UITableView.
The json response from rails:
[
{"id":1,"name":"Buy bread"},
{"id":8,"name":"Get gas"},
{"id":14,"name":"Call John"}
]
In the UITableView, a row for each task, the textLabel of the cell is the name of the task:
The problem I'm having now is how to associate the cell with the record id of the task.
Two tasks can have the same name, so I can't just get the id from the hash based only on the name.
I need the record id, so I can post back to the rails app, after the user edits the UItableView (deletes a task for example).
Is there a property I can set on the cell? I feel like I'm missing something obvious. This is my first iPhone app, so please be gentle, hehe.
How are you getting the JSON array to an Objective-C array for use in the table? You'll have to do that again for the ID of the task, and in your - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method use something like theID = [idArray objectAtIndex:indexPath.row];
The better solution would be to maintain a proper data model on the client. You could use the JSON as your model, but Core Data is a bit more robust. What you'd want is to have your controller associate what it knows about the view with what it knows about the model. For instance, if you use didSelectRowAtIndexPath: You'd want to use this index path to map to your model.
Your solution of setting a property on a cell which allows a client of your view to query your data model is in violation of the rules of the MVC paradigm. It couples your view to your model which isn't great.
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've been expanding my horizons recently and am trying to start utilizing KVO more in my programming.
I have a view controller in my iPhone application which acts as the datasource and delegate for a UITableView. I also have a singleton model controller which coordinates populating my model with data fetched from the web.
In my view controller, I request that the model's controller load new data from the web. Then I can observe the "dataset" property of the singleton and receive KVO notifications when items are added to or removed from the set.
Now, each cell in my table view has an indicator which specifies whether the content in that cell has been read or not (like the blue "unread" dot in mail). Like mail, when a row is selected, I'll display details about that row. In the viewDidLoad for the detail view, I set the object's "read" property to YES. I would like the original view controller to be able to observe this "read" property of each object in the dataset, so that [tableView reloadData] can automatically be called as necessary and redraw the cells without the blue dot.
In researching this, I found the following link: http://homepage.mac.com/mmalc/CocoaExamples/controllers.html#observingACollection
According to this, it looks like I will do the following:
1) Be an observer of the array
2) Whenever I get a notification of a change to the array, I add (or remove) myself as an observer for the individual properties I am interested in.
3) When I get a notification of a change to the property I'm interested in, I can call [tableView reloadData]
I'm currently in the process of attempting to implement this approach. Can anyone with experience doing this offer some advice on this approach? If this the best way to handle this type of situation?
If this is the correct approach, would anyone be willing to share their implementation of adding/removing the observers for objects in the collection when the collection changes?
Thanks!
I think you can accomplish this task by using Core Data and the Fetched Results Controller.
I'm sure this can save you a lot of work.
Here's a good guide: Ray Wenderlich Core Data Tutorial, getting started