KVO, properties changes and notifications - ios

I have a shared singleton that contains all relevant information on the current user and its session, through the object [IWSession session] and [IWSession session].currentUser.
The current user (which actually refers to the one logged in the application) might have some of its properties updated frequently through webservice calls (triggered by iBeacon, triggered by a change in its location, etc).
This implies to update the GUI accordingly at different places in the app, let's say 5 or 6 class instances.
What's the proper way to update information displayed in the app as soon as any property is updated ?
I thought about
1) Adding a KVO on the [IWSession session].currentUser on himself and for all properties regarding the following link
Key Value Observing - how to observe all the properties of an object?
2) The KVO would then trigger a
[[NSNotificationCenter defaultCenter] postNotificationName:#"userUpdated" object:nil];
and all classes which need their layout to be updated would listen to that notification.
Is it a good approach ?
Any other suggestion ?

If you use Notifications then memory will not be released for all the objects in which notification is posted. Because if you use notifications then reference to the object is stored in the heap. So I don't this it would be a good idea to use Notifications.

I recently have been using a weak-observer list using hashtables
mObservers = [NSHashTable weakObjectsHashTable];
with semi-delegation messages, for example:
#protocol UserSessionObserver <NSObject>
- (void) userSession:(id)session didUpdateUser:(id)userProfile;
#end
So, any object that would be interested in changes to userProfile or userSession can simply add itself as an ad-hoc observer to the shared userSession. Because it is a weak entry, the object will be removed automatically from the observer table on dealloc.
Trick is to create the correct addObserver message:
- (void) addObserver:(__weak id<UserSessionObserver>)observer;
While this requires you to write your own observer logic, it also means:
1. No memory management issues with strong retain cycles,
2. Simplified and to the point observer messaging (the system notifications and KVO implementation is so generic, it is bordering on incomprehensible imo, but also adds several layers of logic that merely slows down processing).
An example implementation: Weak Observer example

Related

Passing NSNotifications. Good? Bad? NBD?

I'm trying to think through the ramifications of passing an NSNotification object as a var to a method.
It seems like it's difficult to trace what happens to a the flow of logic with a notification anyway (without some great commenting and method/object naming) so passing the notification to another method/class/lib/project would just make it even less fun to debug or respond intelligently to an error.
But it just feels like it's the sort of thing that has a lot of hidden gotchas potentially.
And I know there are still a lot of people out there who love notifications.
So does anyone have some pros/cons/better-practices about passing the actual NSNotification object as a var between methods?
Just for clarity's sake here's some pseudo code:
[[NSNotificationCenter defaultCenter] postNotificationName:kSuperImportantNotification object:self userInfo:soMetaDict];
... Later in the code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(importantThingHappened:) name:kSuperImportantNotification object:nil];
... Later in the code:
- (void) importantThingHappened:(NSNotification *)notification {
[respondingInterestedClass executeSomethingWith:notification];
}
... In "respondingInterestedClass":
- (void)executeServicesDiscoveredBlock:(NSNotification *)notification {
// ... do something with the NSNotificaiton object.
}
Thanks
It depends in what you are doing, usually this is when to use what:
One-to-One relationship and loose coupling: Delegate
One-to-One relationship and tight coupling: Direct method calls
One-to-Many relationship and loose coupling: Notifications
One-to-Many relationship and tight coupling: KVO
So you should not use Notifications for all kind of communication, lot of developers use them heavily even when its not needed.
Saying this, it is totally fine to pass the notification object to the method handler, but don't pass it anywhere else.
Putting aside how and when notifications should be used and focusing purely on the ephemeral set of uses that are totally the right choice....
Once received, the notification object is a state container that contains some set of state in a format that is convenient to the system. You can shoehorn whatever you want into it by shoving key/value pairs into a dictionary and passing it as the userInfo, if you want, but it is still the system state.
In a well designed body of code, there are hard fought barriers through which the format of the data and the encapsulated messaging are well defined. In a Model-View-Controller system, for example, a Model class won't be a subclass of UIView or handle user events directly.
And Notifications should be treated the same. When the notification is received, unwrap it into whatever internal-and-specific-to-your-architecture representation you want and pass that around.
Or, consider:
- (void) somethingChangedNotification:(NSNotification *)changed
{
[myModelGoop applyChange:...];
}
#implementation MyModelLayer
- (void)applyChange:(....)change
{
}
In the above, you could certainly pass the notification object into the model layer. But that's just pushing a system specific implementation detail into your model.
What happens the moment you have changes that aren't triggered via an NSNotification? Your either left to encapsulate your change into a fake NSNotification instance (because posting a notification may have side effects depending on who is observing) or you have to refactor the above to no longer take a notification in the model layer.
Better to get rid of the dependencies on system encapsulation early.
To that end, the NSNotification instance should never be passed out of the method that handles the notification.

iOS: Pattern for mapping view inputs to NSManagedObject

I am building an app with a view controller that represents a form for creating and editing a Task object. It has the following behaviour:
On initialization of the controller, a Task object (NSManagedObject subclass) is initialized in the MOC
NSNotificationCenter observers are set up for each input in the view.
When an input's value is changed, the corresponding property of the Task object is updated via the observers' assigned method. (eg. - (void)taskNameChanged;)
When the user taps Save, the Task object is committed to the data store. If the user taps cancel, the Task object is discarded from the MOC.
I have a feeling that there is a better way to do this. What is the most common pattern for this type of transaction?
It's uncommon to use notifications in cases like this. The question you need to ask is: Do you need to update it all the time? Most of the times you won't. I usually just the values when the Save button is tapped.
In case you would have to check the values earlier, you still don't want to use notifications. I usually go for hooking up a IBAction to one of the events in Interface Builder. Another option is using the delegate, in that case your UIViewController instance would implement the UITextFieldDelegate protocol.
Unfortunately, iOS lacks Cocoa Bindings, so you end up having to implement a light version yourself.
I did this for our app, and it ended up working well. I used KVO instead of notifications, for two-way binding. I created a dictionary mapping between the object properties and UI elements, and using KVC set up the binding when the view is loaded. In my implementation, I added an option to hint which value should take precedence (this is less valuable for data<->UI, but I wanted something more generic). Eventually, I added support for block-based data transformation between binded objects, so that UI could present text, while the data backing object could hold different types of data.
Please note that UIKit is not KVO compliant. I created KVO-compliant versions of UITextField and UITextView, by listening to notifications and sending the appropriate KVO messages.
While, I cannot post code of this, I hope this gives you ideas regarding your further adventures.

How do I make sure to removeObserver without subclassing and overrideing dealloc?

When using the NSNotificationCenter object, if you add an observer for a notification, You must invoke removeObserver: or removeObserver:name:object: before any object specified by addObserverForName:object:queue:usingBlock: is deallocated.
Is there a way to do this without subclassing the object and overriding "dealloc"? I don't want to have to subclass a bunch of objects just to use notifications with them if I can avoid it. Is there some other way to learn about the dealloc before it happens?
Thanks for your help.
Generally speaking you should think about what object is observing changes and make it appropriate. This usually means a controller class, and in this case you usually already have a custom subclass. It should usually be receiving the observation callbacks and forwarding them as required. It should add and remove itself as an observer when it is created / destroyed / put on display / removed from display.
That said, if you persist with making arbitrary classes observers, here's an idea (I think it should be safe, though I wouldn't want to rely on it):
You can use a single custom class to handle the removal of the observer. This should be a class which is configured with a reference to the class to be removed. During the configuration method this class adds itself to the class to be removed using objc_setassociatedobject and OBJC_ASSOCIATION_RETAIN, and stores the pointer to the class to be removed in an NSValue. Then, when it is deallocated, it removes the other class from the notification center, using the NSValue.

Multiple Delegates in iOS

I am making an object that goes to download stuff for all of my view controllers. The object is singleton instance and has a callback method with received data once the download is completed. It also has a delegate property so that it knows which object to call back to after the download is done.
There are multiple controllers that use this shared instance, and my question is how to call back to the correct view controller that requested the download.
My approach is to use delegation, but the problem is that since other view controllers are also its delegate, the download object could call back to every object and this will be hard to track.
I've worked on projects where people have attempted to use multiple delegates and it's basically a bad idea. The delegate pattern is about a 1 to 1 relationship between a class and it's delegate. Whilst it is possible to achieve some level of multiple delegation through switching the delegates in and out, it's more likely to lead to unpredictable behaviour and bugs.
My recommendation would be to change how you are thinking about this. You have two options as I see it:
Switch to an Observer pattern where you can register multiple observers which your main class can interact with. This is useful where your observers all implement the same protocol and where your main class wants to be aware of the observers and interaction with them.
Broadcast NSNotifications to indicate state changes and events. Here is a more decoupled approach because the main class does not need to know who is listening and does not directly interact with them. Other can start and stop being notified at their leisure. It also has the advantage that you do not need to create or implement a separate protocol. Instead you register the classes that need to know about changes with the NSNotificationCenter which in turns handles all the routing of notifications for you.
It actually sounds like the delegate pattern might not be the best approach here.
I would look into NSNotificationCenter instead.
The basic idea is that your singleton doing the net connection posts a notification (with something like postNotificationName:object:userInfo:) , saying that new data is available. Within this notification, you can pass a dictionary object (userInfo) that holds the data you've fetched, or info on what parts of your Model contain updated data.
Then, your other view controllers can register themselves to 'observe' these notifications by calling addObserver:selector:name:object:. Generally speaking, when a vc becomes visible I call addObserver, and removeObserver when it's being hidden or transitioned out.
Good luck!
Delegation doesn't seem like the right solution to this problem. How about requiring the requesting view controller to provide an object (its self) and a selector for you to call as a completion notification? Of course, you'll need a place to store that object and selector until the download completes. Hopefully you have (or could create) an object for this.
i recommend to use one of these ways
observer:
when use data that you want to inform other object are near to primitive ones.for example when you are using 'NSMutableArray' you can not inform the change in one of object by the standard implemented pattern at least you need to implement one for your self that is not reusable that much
Notification
when your interaction with destination object (those need to be inform) is in one-way.it means you don't need any acknowledge or other data back from them.
delegate
when there is one object to inform at each time step.
note:block use for success and fail is not a pattern to broadcast data its about to queue task when you don't know when they are finishing or failing like network operations
EDIT:
how to create notification | multi delegate issues and implementation
While I agree with most of the answers here, if you did actually want to achieve multiple delegates you could potentially declare an array of delegates and send messages to all delegates within that array. If your protocol has optional delegate methods you safely check using responds(to aSelector: Selector!) -> Bool before invoking (being mindful of memory management, as those delegates would be strongly referenced in the array). Again I do agree that multiple delegates is likely a bad architectural idea and using blocks or notification center would suit your needs better.
One approach, which works for me if you only have one other object to forward messages to is to create a forwardingDelegate This does not end up with issues of hard to debug ordering of delegates and it does not unnecessarily create a dependency on the other object. Keep in mind, if you have many objects then this might not be the best approach, it is mainly for one additional object but this could be extended to support an array of objects so long as there is one that receives the SDK and forwards it to the other objects [1]. Note that every method that is needed for the forwarded object needs to pass it along, even if it is not used by the forwarding object.
For example, if I need to forward the messages coming from the mapView delegate:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// handle this object here.
if ([self.forwardingDelegate respondsToSelector:#selector(mapView:regionDidChangeAnimated:)])
{
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
}
// or handle this object here.
}
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
The forwarding property would be declared like this.
#property (nonatomic) id<MKMapViewDelegate> forwardingDelegate;
And the other object would adopt the protocol as if it were receiving the original message.
[1] The array approach for multiple delegates may get tricky because then you don't have as much control over what order the delegates get called, as was mentioned in other posts.

Removing all notification observer from a single place

I want to remove a notification observer and I am using the method:
[[NSNotificationCenter defaultCenter] removeObserver: name:#"myNotification" object:nil];
for this. Now there are many observers who are listening to this notification and I want to remove all of them in one shot from a centralised place. Can I pass 'nil' in first parameter and it will remove all observers who are listening to myNotification?
You can remove an object from the notification center all together which means no notifications will get triggered. For example, when I have a view controller that has registered for notifications, I include this line in my dealloc.
[[NSNotificationCenter defaultCenter] removeObserver:self];
This is at the object level...so it will unregister for many notifications. It won't unregister for one notification in many objects.
Hope I understood your question correctly.
In case of Swift, you doing it like this:
NSNotificationCenter.defaultCenter().removeObserver(self)
And in Swift 3:
NotificationCenter.default.removeObserver(self)
Unfortunately, there is no way to remove all observers of a specific notification in one place. While there are certainly cases where this would be nice, it would be a dangerous thing to do as generally, the object doing the observing should be responsible for adding and removing itself as an observer of a particular notification. This ensures no unpredictable behavior b/c observers can come and go so they configure and clean up after themselves.
If an object that generates notifications goes away, it won't matter to the observer as the observer doesn't know about that object anyway. It just means that object won't be generating any more notifications.
[EDIT: RESPONSE TO YOUR COMMENT RE CLASS B STOPPING CLASS A FROM OBSERVING]
I just saw your comment. There are different ways to accomplish this, particularly if class B knows about class A. As you reference classes it sounds like you want to affect all instances of a class vs a particular instance. If you have some condition you can check when handling the notification, that's how I would approach this. In the notification handler something like:
if ([self shouldRespondToNotificationNamed:notification.name]) {
[self performNotificationAction];
}
If you don't have a condition you can check, then create one either in the class in question as an iVar or in a place where you can access it globally for all class instances. I generally use a singleton to store global app state that doesn't persist. If it persists, then use whatever method you're using for other state.

Resources