Writing to coredata when device is put to sleep? - ios

I have abit of a problem, I have a coredata object that is used to populate a UITableView. Each UITableViewCell has a couple of buttons that I am using as check boxes, when the user presses one of these text boxes I would like to update coredata and reload the UITableView so all of the arrays I have are updated to reflect the new data.
Thinking about this I have come to the conclusion that its abit redundant or overkill to be reloading the UITableView every time a button is pressed because some of these UITableViews will contain hundreds of rows with two editable UIButtons each.
So I thought that maybe I should update the current array instead then when the view is either exited or the device is put to sleep I could update the coredata object then? the only thing being I don't really know if this is the right thing to do or possible.
The reason this is such a problem is that when I change a button from say a tick to a cross if I scroll away then come back the buttons tick or cross s reverted to its old value.
I would like to know the best way to handle this case as I have never done anything like this before.

You should use an NSFetchedResultsController and its delegate methods to populate the UITableView. Then when the user taps a button, you simply update the corresponding Core Data entity and not the cell. The NSFetchedResultsController will then call its delegate methods, and you can update just that one cell on which the user made a change.
Also, in cellForRowAtIndexPath, you simple fid the corresponding CoreData entity, and use its attributes/properties to adjust the display of the cell.
Remember, that you must always use some data (NSArray usually) from which to read what to do for the cell at the indexPath when the tableView calls cellForRowAtIndexPath:.
This way, when the fetchedResutsController call its delegate methods, you can simply call reloadCellAtIndexPath on the tableView and then the tableView will call cellForRowAtIndexPath again. As the Core Data entity has been updated, your logic for adjusting the display for that cell will cause the cell to look as it should. It's important that you only ever adjust the way a cell looks in cellForRowAtIndexPath, and base the look on a CoreData entity. Change the look of a cell in multiple places, and you will get problems.

Related

Using KVO to update table cells from model upon any change to model

I may have multiple table cells which are updated from the same model. I want to be able to update all of them when the model changes. So I assume I will use KVO to do that. My question is, how can I have each react to any change to the model, not just the part that each cell will display? i.e. if one item in the model changes, I want all of the cells to update themselves.
try to use tableView.reloadData() immediately after changing the model. On the other hand you may also try to use RxSwift and bind your model items to tableView - your tableview will then reload whenever the model changes. Refer to these articles as simple examples of RxSwift usage with tableView:
http://rx-marin.com/post/bind-multiple-cells/
https://daddycoding.com/2020/04/20/rxswift-uitableview-with-section/
So I assume I will use KVO to do that.
Table cells are very transient -- the cell for a given row in your table will get reused for a different row almost as soon as it scrolls off the screen. So long-term relationships really aren't something that cells are good at, and you probably don't want to go setting a cell up to observe part of your model directly. Instead, let the view controller worry about the model and reload any affected cells when the model changes. If you want to use key-value observing to let the view controller watch the model, that'll work fine.
My question is, how can I have each react to any change to the model, not just the part that each cell will display?
When the view controller learns that the model has changed, it should tell the table to reload its data. At that point, the table will go through the process of recreating the visible cells, and the effect will be that all the cells will appear to "update themselves."
Please try to reload table by using tableView.reloadData() after the data changed.

Reload data in table view without harming animation

I have a UITableView-based in-game shop.
Every cell has a "BUY" button which is mostly enabled and can be switched to "BOUGHT" if the item is a one-time purchase or can be disabled if there are not enough money.
Right now what I do is calling reloadData every time buy button is being pressed in order to update visible cells and the current cell itself. (I have to update all cells, because after purchase it is possible that there wont be enough money for visible item cells).
But it causes weird animation glitches, like when I click on one cell's buy button and animation finishes on another one.
I think this happens due to reusability of cells. So what I want to know is how to reload data in the whole table view without harming native animation.
The only thing I can think of is not to use reusable cells and cache them all, but I dont think this is a good programming practice.
First, make sure that your view layer and model layer are separate. There should be some non-view object that knows about each item; we'll call it Item.
Now, create an ItemCell (you probably have one already). That's your reusable cell. Hand it the Item. It should configure itself based on the data in there.
Use KVO, delegation, or notifications to let the cell observe its item. When the Item changes its status, the cell should update its own button.
When your cell is reused, you'll pass a new item to it. It should stop observing the previous one, and start observing the new one (and of course reconfigure itself to match the current status).
By separating the views (which are reusable and transitory) from the model (which is stable and long-lived), you get the performance benefits of cell reuse with correct animations and no need to call reloadData.
You could have a reloadCell method in the cell class and loop through the table's visibleCells and update their UI that way. That way they are not recreated (or re-used), they just have their relevant UI pieces that could have changed due to the new data updated.

TableView rows not updating after core data insert

I'm very new to swift programming. I have been playing around with this for a while, but I am not getting anywhere so asking here.
I have a tableview which I can load the data into the view from CoreData no problem. I have an ADD button at the top that segue's to a new tableview, with a long list of options they can pick from. This tableview also works fine, and includes a search bar.
When the user selects an item row from the second tableview, it inserts that item into CoreData and segue's back to the first tableview. This is where my problem is, the data does NOT update on the visible view.
I call tableview.reloaddata() and I can see my code calling the fetchedResultsController with the new query that would return with the new data. But the code never gets to the cellForRowAtIndexPath func so therefore the visible data view never changes. It remains the same display that was visible when the add button was pressed.
How does the visible data get updated? What am I missing?
When using an NSFetchedResultsController, if you want it to "automatically" update the contents of the tableview then there are a couple of things you need to make sure of...
You have to become the NSFetchedResultsControllerDelegate and implements the methods necessary for the updating of the table view. These are quite lengthy and can be found on the Ray Wenderlich website. The code on here is in Objective-C but it's fairly easy to convert to Swift.
The second thing you need is to make sure that the core data update is done on a background thread. Again the website linked above shows this.
Once you've done that then you don't actually need to run [tableview reloadData] because the fetched results controller methods will manage everything for you.

UITableview cell reinitializing every time in iOS 7

All,
I hope most of you know that with ios7 there is not need to do a null check for tableview reuse
if (cell == nil) {
But unfortunately, because of that the cells are always reinitialized, as we put the code in the same method for initializing values. The problem is only with text fields inside the tableview though.
Let me explain the scenario. I have a table view with multiple rows, and some rows contain multiple text boxes. I populate the textboxes with data from server when the page is loaded. Since the cells are always re-initialized as i explained above, whatever I enter in the field goes away and the server data is re populated once i scroll down and come back to the initial stage. This is because the populating the data code is also in the same place. After fetching a reusable cell it populates the data.
Previously till ios6, we used if(cell==nil) and hence we loaded server data inside the cell and when reusing the cell, this piece of code will never be called.
I have other dirty solutions, but would like to know if someone else has a graceful way of dealing this. Please help.
You just don't store any data in the table view cell but in the model that fills the table cell. This is always the way it should be done.
Looking from the MVC standpoint than the UITableViewCell is a view. Since it is reused by iOS you should use a model to the view.
Yes, this is the expected behavior of UITableView. For performance reasons, cells are reused. Thus, it is your responsibility to populate the views in a Table View Cell every time tableView:cellForRowAtIndexPath: is called.
The thing I don't understand from your question - are you making a network call every single time a cell comes into view? If so, cache the results somewhere. Or, if it's a small amount of data, consider just doing it all in one shot at the beginning (still need to be asynchronous though).
One thing I see a lot of developers do is move a lot of code into UITableViewCell subclasses, which sounds like a good idea because it's modular, but makes solutions for problems like this more difficult. Have the Table View Data Source manage the network calls.
If you need some inspiration, look at Apple's LazyTableImages sample.

iOS iterate UITableView

I have a UITableView that collects data from a database. What I would like to know is if there is some way I can iterate in the UITableView collection and check the values of the cell? The reason I ask is because I would like to update each cell based on the current value that it has (change font, size, color, etc.). I've seen in another SO post regarding this topic, but since the cells are already created and their values are changed it is a bit harder for me. I was thinking of iterating through the UITableView before I call reloadData, but any other suggestions are welcome.
You should not iterate over the cells of UITableView, because some of them (in fact, most of them) may not be present until you request them. UITableView aggressively recycles its cells, so if a cell is not visible, it is very likely that you would be creating it from scratch only to put it back into recycle queue moments later.
Changing your model and calling reloadData the way your post suggests would be the right solution. iOS will ensure that it runs the update in a smallest number of CPU cycles possible, so you do not need to worry about the cells that are already created. This is also the easiest approach in terms of your coding effort.
A table view is for displaying data. The properties of your table cells should only be written to, not read from. The appropriate way of handling this situation would be to update your underlying model objects -- the objects that you use to populate the table view -- as the data changes, and then reload the affected rows.
The issue you'll encounter is that UITableView reuses table cells. Once a table cell scrolls off the screen, it's quite likely that the table view will reuse the same cell to display a different row.
This means it's fundamentally not possible to iterate over the table cells. When you need to refresh a row because its data has changed, you should call reloadRowsAtIndexPaths:withRowAnimation: (or reloadData if all rows have changed) and if the row is visible on screen, UITableView will call your data source methods and give you an opportunity to configure the cell for display.

Resources