I need to show a list of elements from an array in a UITableView (loaded from database).
The steps are:
When I open the view I fetch the data from the database and I store it in the array. If the array has less than 100 objects I perform a call to the backend to get 100 objects.
I show the first 10 objects in the table view while the backend call is performed. If there are less than 10 objects I show them and when the call to the backend is finished, then I show the needed n-objects in order to have 10 in the table.
Now, each time I scroll to the bottom of the table I need to add the next 10 objects from the array, and when the table has 100 objects - don't show more (this is the limit).
Please not that there are might be many possible solutions to this. Some might be better than this.
Create an extra cell with a reuseIdentifier like LoadMoreCell, which should appear at the end of your table.
Implement UITableViewDelegate method tableView:willDisplayCell:forRowAtIndexPath:.
In this check if the reuseIdentifier is LoadMoreCell.
If it is, call your method that requests data.
Related
I want to loop through a TableView and extract the text from all the selected rows. I suppose I "could" create and maintain a special array that is updated every time a row is selected/deselected using the didSelect/didDeselectRowAtIndexPath methods. But creating a separate array seems like an extra step. Is there no way to let the TableView itself serve as the array and then simply loop through it and get the selected rows? What would the code look like? I'm new to Swift, so this might be a silly question.
Part of the problem is that cells are supposed to be reused, and when used this way it is not possible to loop through them all. You could get around this by using a unique reuse identifier for each cell, such as the indexPath itself or some underlying unique id in your model. Then, you could indeed loop through all cells and retrieve whatever state you desired from each.
You would, however, find your application crushed under the weight of too many cells being instantiated and kept in memory. If you don't have many cells you won't be killed, but try it with a big data set and your app will enjoy a very quick death.
It is far more efficient to store one array with a bunch of id's than a large number of memory-intensive UITableViewCells.
As mentioned in comments, you should work with underlying datasource, not the table itself.
For example if your table shows rows from Array, it is way more faster to retrieve strings directly from that array than creating UITableViewCells and get strings from them.
Get indices of selected rows using UITableView's property indexPathsForSelectedRows.
Query datasource for each row.
As has been said the tableview only handles displaying, your datasource is what powers the data shown if you think about it.
Plus as said before the tableview dequeues cells as they scroll on and off the screen.
The best way to achieve what you want is to add a property to your datasource for each element that will allow you to filter out the select properties easily.
How are you storing the state for each selected cell currently? As this is the same functionally you would use to be able to generate your selected text array.
I have drawn my tableView in storyBoard with static cells and multiple sections. 6 sections each has proper number of static cells. In code, in MyTableViewController I do not implement any of the datasource or delegate methods, which logically means I do not have my model in code, the array or whatever that dataSource methods will use to populate number of sections or number of rows in a section. My question is: is it possible to insert a row to any of the sections?
I read a lot of stack questions. All of them is based on having a model array or dictionary that plays its role in dataSource methods to construct the table.
I have my table already constructed in storyBoard. I can get my number of sections with tableView.numberofSections() for example. Which means the model is stored somewhere for sure. I just need a proper method to get access to that model.
There is a reason the UITableView works the way it does with the datasource protocol. It allows iOS to use just what is needed to display on the screen at any given time as you scroll through the table, making it very efficient. Without implementing the required methods, iOS will not know how to rebuild the cell if you scroll it off the screen and then back on.
If you don't need that complexity (and really, it isn't complex and you can implement the required methods in less time than it is taking me to respond), you could use a UIStackView inside of a UIScrollView. It would allow you to simply add a set of UI components vertically down the screen, complete with scrolling.
Can you explain why you don't want to implement the UITableViewDataSource protocol?
I'm working on an a game app in swift that currently has a tableView displaying the scores, number of trys etc, downloaded in an array from parse.
However, this table can get pretty long if the user plays the game many times. So I'd like to improve the app by displaying the first, say, 20 objects of the array in a tableview, then, once the user scrolls down to the end of the table it automatically adds more rows and displays the next 20 objects in the array (along with the original 20, making the tableview now 40 rows)
If anybody's familiar with the twitter app, that's exactly what I'd like to go for. There's a set amount of tweets shown initially, then once you scroll down to the end of the table more tweets are loaded, in order to decrease loading times.
Problem is, I really have no clue how to implement this at all. I've never been in the situation where I only need to use part of an array. Any help would be greatly appreciated. Dan
UITableView is a virtual view where it calls you back for the data to create cells for a given row that's in view and destroy's cells that go out of view. You should also re-use cells that have been created.
So, I think the answer to your question about pre-loading portions of the list is ... you shouldn't have to. Just implement the data source and answer the data call backs.
More here in the apple docs on the datasource for a UITableView
This is addressed in How to know when UITableView did scroll to bottom in iPhone in Objective-C. If any help needed translating this to Swift, post as a comment and I'll update answer.
EDIT -- The real question:
The tableView delegate methods allow you to perform arbitrary logic / mapping between your data and the table's viewable data. So when you do detect a scroll to the bottom, increment an internal state variable, such as var rowsToReveal declared as a class-wide stored property. After incrementing, call tableView.reloadData(). Then re-write numberOfRowsInSection delegate method to use rowsToReveal rather than someDataArray.count or whatever hardcoded value you had. Make sure rowsToReveal never exceeds the count, of course, otherwise -- instant crash.
I have a view which shows a list of entries in a UITableView. The data for the list is an NSArray. When the user is on this view, there is an asynchronous call to a webservice to retrieve the latest entries. When I have downloaded the latest entries, I update the NSArray and then I send off a notification to the notification center. The UITableView is listening to this event and will try to reload the table.
But with this approach I get an error which is on the lines of "The object was mutated during reading".
After going through similar questions here on SO, I see the suggested approach is to remove objects and add objects at individual indexes and ask the table view to reload the data.
Is there a way to replace the array completely and ask the table view to reload the data ?
UITableView's reloadData method should do the trick.
From Apple's documentation:
Call this method to reload all the data that is used to construct the
table, including cells, section headers and footers, index arrays, and
so on. For efficiency, the table view redisplays only those rows that
are visible. It adjusts offsets if the table shrinks as a result of
the reload. The table view's delegate or data source calls this
method when it wants the table view to completely reload its data. It
should not be called in the methods that insert or delete rows,
especially within an animation block implemented with calls to
beginUpdates and endUpdates
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableView_Class/index.html#//apple_ref/occ/instm/UITableView/reloadData
if you have Updated NSArray Object
Then you can use directly following method of UITableView
[tableView reloadData]
I have to fill a TableView with lots of items (20.000 items frol sqlite) but I know that I will overload it.
Is there a way to load only the needed data when scolling ?
for example if I display 100 items when I scroll over 100 should I load 200 in the table or load only the items 101>200 ?
Also is it possible when returning the Cell content to fetch for EACH element in the embedded sqlite DB ?
Thanks
I have to fill a TableView with lots of items (20.000 items frol sqlite) but I know that I will overload it. Is there a way to load only the needed data when scrolling?
UITableView is designed specifically to load only the cells that are visible. You don't so much "fill" a table as you make the data available to the table via the table's data source. As the table scrolls, it asks its data source for additional cells, and it re-uses the cells that are no longer visible. This minimizes memory usage and maximizes speed. You don't need to do anything to achieve this other than implement the necessary table view data source and delegate methods in your view controller (or some other object).
Also is it possible when returning the Cell content to fetch for EACH element in the embedded sqlite DB ?
Sure, you can do that. Just implement your -tableView:cellForRowAtIndexPath: method to make the appropriate SQLite query for the requested cell.
This the default functionality of a UITableView, it only draws the necessary rows when they need to appear. This is why you have "reusable cells" because they keep getting reused. I think storing the 20,000 items should not be terrible memory overhead, so I would just try using the UITableView default functionality and you will be fine.