Notification when UITableView changes - ios

I often have a UITableViewController with an edit button, which I like to disable when there are no rows in the table. To keep this in sync, I enable/disable the button every time something happens that might update its dataSource - adding the first row, deleting the last row, in viewDidLoad, etc. Whenever I add some new functionality that can affect the contents of the table, I have to remember to incorporate this logic.
Is there some delegate of the UITableView that I can use to simplify this? A way to know whenever the table (or it's dataSource) is modified, where I can check the number of items in the dataSource and enable/disable accordingly.
Alternatively, any other approaches would be welcomed.

You are the data source. So you do know whenever the data source changes, if you care to know. In other words, the reason you're having this problem is that you're treating the model (in the model-view-controller architecture) as an alien being. Instead, treat the model as something of your own. Take charge of your model. For example, is the model an array? Then wrap it in a class of your own, to which all commands to change the array must be given. That way, it can emit a notification whenever it is told to change the array.
It is also possible under certain circumstances to use Key-Value Observing to get notified when something changes, and you could look into it, but with primitives like arrays and dictionaries it is possible that this will be more trouble than it's worth. Again, you're likely to be happier wrapping your model storage in your own class, whose observability via KVO you can manage yourself.

Related

Does Swift have a way to observe changes not just to an object, but to a reference?

I'm working on caching for an app using a subclass of NSCache. It's working well, though I'm having a hard time wrapping my mind around how to update items in the cache when necessary and propagate those changes throughout the app. Say there is a model class, Article. An instance of Article is cached, and a few view controllers in the app are observing relevant properties on this instance with KVO, so when any changes are made to the properties of this Article, the changes automatically propagate.
But say another request for that Article is made, and the cached version is now stale. A request is made to the network and a new, updated instance is serialized, so the cache and the view controllers displaying the old instance need to be updated. How can I propagate this change to the view controllers? Is there a way to observe not just a property, but observe the reference itself to get notified when it changes? In other words, do something like oldArticle = newArticle and have an observer on the oldArticle fire?
I have a few ideas of how to handle it, but none I particularly like. I could individually transfer the property values of the new Article to the old one so the relevant observers are fired - yuck. I could use an object proxy, and set up an observer on the proxy when the object that it references changes. I could use NotificationCenter or set up some delegates or something to notify the view controllers of the update. But is there a simpler way to do something as described above?
One approach to observing the whole article is to make the cache a mutable dictionary (maybe yours is already) where the keys are something essential to the article (like an id) and the values are articles. Observing view controllers can then observe both the cache's dictionary (where the key path is article id) -- to observe whole-article updates -- and any specific values they wish on the article itself.
Sticking with KVO, another approach is to give article and updateWith: (or copyFrom:) method that takes another article parameter, updating itself with the props from that parameter. The VCs in this case will keep watching the same object, and their existing update logic will work.
I would create an ArticleUpdateDelegate, and make your ArticleViewController conform. The VC then sets itself the delegate of your Article, so that whenever the article is updated, you notify the VC, which can then update its view, and do whatever else it needs.

what's the best way to get notified when entity updates (when saved) in Core Data?

There's an article object that I am trying to keep monitoring in one ViewController. From my research there are couple of ways to achieve this but I am not sure which one is the most suitable one:
1, let the ViewController (or repository or viewModel if we are talking about clean architecture) be an observer to listen to the notification when core data saves.
2, in my Core Data abstract layer, add a completion block callback for when save() is called.
3, Use NSFetchedResultsController. I know this is designed for UITableView and UICollectionView, but I have seen people use this just to do the monitoring.
Among these 3 paths I am incline towards the third one but I am not 100% sure if that's the best practice since most people use it 1 to 1 on UITableView or UICollectionView.
If you want to observe when the object is changed, 1 and 2 will not necessarily help you.
You could do 3 - NSFetchedResultsController is very powerful - but you could also do the same thing that NSFetchedResultsController does internally, and it might be simpler:
You could register as an observer of NSManagedObjectContextObjectsDidChange.
It's posted once per pass through the run loop, if changes have been made, after the side-effects of such changes have been worked out. So it's safe to use if many changes are expected -- you'll only be notified once -- and double-ended relationships will be consistent.
It has a rich userInfo dictionary. Your task could be as simple as: check the userInfo's NSUpdatedObjectsKey and NSRefreshedObjectsKey for your object, and if it's there, refresh the views. Then check NSDeletedObjectsKey and NSInvalidatedObjectsKey too, and if your object is there, dismiss the view controller or return it to an "empty" state.

In Xcode, is there a way to set up a table which is not for UI but like an 'engine' for processing data

I'm wondering if there is some sort of way to set up something similar to a spreadsheet in Xcode. I'm trying to create a 'tapping game' or a 'clicker game' and storing so many variables in regular coding would be really tough.
Having this 'table' would enable me to keep track of multipliers and upgrade levels instead of clogging my coding with it.
Preferably, I could then just tell my code what to pull and what to look for off of the table. The table would be an 'engine' of sorts and it would not be UI. The table would do all of the work behind scenes, then show it through UI based on labels and buttons.
As traxido is saying, without more details we can't point you to a concrete example/solution. Base on the title the answer is yes. It's not a ui component though. It doesn't even need to be one.
What you want is a data structure to hold your data in a way that's convenient to access (save and retrieve). You could create a class which is a composite of other data structures like arrays and dictionaries and possibly other data structures. You might end up having many questions before you're through.
So: the answer is yes. Try it yourself and ask new questions if you get stuck.
Provide the code and error messages and I bet you quickly get answers.
Yes, you can.
Create a shared or singleton instance and retain all the data in instances of it.
(or) create a custom data structure and overide set or get methods to autoprocess the exiting data everytime you add or delete data element
Ex: If you want to maintain an array thats is always sorted. MySortedArray is the custom structure that inherits NSMutableArray and maintain a protected NSMutableArray instance. Overide addObject method to ensure sorting it whenever a new object is added.

Propagate CoreData changes to related objects

Is there a way to have changes to an object's attribute also "alert" related objects?
The structure we have is as follows:
Image has an attribute called content
Category has a one-to-one relationship to Image
It would be ideal if changes to attributes within the Image object could be detected by the related Category, in a way that the Category would be included in the NSUpdatedObjectsKey of NSManagedObjectContextObjectsDidChangeNotification. I've seen some suggestions indicating that adding a sentinel attribute such as needsUpdate to Category would be a good way to do this, but that seems like a cumbersome way of handling this.
My reasoning for doing this is that I need to reload a tableview whenever a Category changes, or whenever it's associated Image changes, at the moment in my observation method for NSManagedObjectContextObjectsDidChangeNotification I check updated/deleted/inserted objects for Image instances or Category instances, however Image instances are used elsewhere in the app and may have no relationship to a Category instance, in which case it would be a waste to reload the tableview. I could manually loop through the updated/deleted/inserted objects to see if they are Image instances associated with a Category, but that doesn't seem like the best place to do it.
I found that this question is similar to what I am attempting, however it has no answer.
Please let me know if additional information is needed, or if my question is too convoluted.
Edit: Modified to hopefully make it more apparent that I'm interested in Category being aware of changes within the Image object's attributes, rather than a change in the relationship itself.
I would suggest learning about KVO (Key Value Observing) as that framework is designed specifically for this purpose. With KVO you can listen to a specific object for changes on its attributes and then react to them.
However, I question why you are not using a NSFetchedResultsController for this. That is what the NSFetchedResultsController is designed for.

Multiple NSFetchedResultsController's with one UITableView?

Visually I have a UITableView with a UISegmentedControl to allow 'mode' selection which will change the table's sort order .
Using NSFetchedResultsController's I am thinking I should keep a separate controller for each different sort configuration then swap between which one is being displayed based on the currently selected 'mode'.
However I can see this will get tricky with 4 different NSFetchedResultsController all sending delegate messages to update the UITableView. To deal with this I am planning to use a switch() block in each of the relevant methods to ignore all but the currently 'active' NSFetchedResultsController.
Does this sound like the right approach or am I missing something obvious here?
-I can see potential for disaster if the user changes the 'mode' just as an update comes through (ie between controllerWillChangeContent: and controllerDidChangeContent:)
I've used a segment control to change sorting/grouping in several Core Data apps. In all of them, I've always just used a single NSFetchedResultsController, and re-queried the database when the segment changes.
As you correctly realized, it is a far simpler implementation that way, fewer chances of unexpected errors, and is also more scalable. E.g. what if I decide to add a new sorting/grouping segment based on customer feedback? How many NSFetchedResultsController's are you going to keep adding? At some point (5 or 6) it just becomes ridiculous.
Also graver's comment above that you could set all of their delegates, except the "active one" to nil won't scale (you would have to modify many lines of code to make all the other delegates nil, which will make maintaining the code hard.
So my suggestion is to go with the simpler implementation, which is a single NSFetchedResultsController, and recreate it every time the segment changes. If you're interested in caching, you could use a separate cache name for each segment. A unique cache name can be generated for each segment by concatenating something like:
[NSString stringWithFormat:#"Cache_%d", segment_index]
Isn't it more logical when the segmented control's selected index is changed, to change the sort descriptors and performFetch?
self.fetchedResultsController.fetchRequest.sortDescriptors = [NSArray ... ];

Resources