Is it possible to observer a NSMutableArray from different class? - ios

I'll try to summarize this as succinctly as possible:
I have three classes: a ViewController, a ViewModel, and a DataSource.
The ViewController creates both the ViewModel and DataSource. It then proceeds to "configure" the DataSource with a NSMutableArray that was initially created by and is owned by the ViewModel.
I'm aware that by implementing the appropriate indexed accessor methods I can make the NSMutableArray property KVO compliant so that my ViewModel can observe its changes.
However, what I want to do is observe the changes from my DataSource.
When it is configured the DataSource, "sets" the NSMutableArray to its own "objects" property (weak, strong, copy???). Whenever the NSMutableArray is updated via the ViewModel (which does the fetching from the server), my ViewModel is made aware of the changes. But, I can't seem to be able to observe these changes from the DataSource.
Any suggestions?
(Also, not a priority, but does anyone know of a way to do this "reactively" with RAC?).

Yes, it's possible to observe changes to an array property of one class from another class. I've done it. It's been a long time, and I don't have the code at hand, so I can't give you specifics, but it is indeed possible.
It's fragile, since if the listening object gets deallocated without removing itself as a KVO observer, you crash.
This sort of KVO observation seems like bad mojo to me. It creates fairly tight coupling between your classes, and makes the observing class dependent on implementation details of the observed class.
If I were to do this again I would probably use KVO within the class that owns the array, and then broadcast a notification, use a callback, or use some other method to notify the interested external object about the change that does not have such tight coupling.

Related

Have multiple instances of a class point to one object #property

I will try to make this question as understandable as possible. I am implementing core data in my app, and I need to access the NSManagedObjectContext from around 10,000 different instances of a class (this class extends UIView). The Core Data stores what is displayed on these instances and the class builds it.
Everything that I have found so far uses View Controllers, of which you only have one instance, so you can just alloc init the VC in AppDelegate, set an #property for NSManagedObjectContext and be on your way. This does not work for my program.
What I want to do is have many instances of my CoreDataHelper class (which I will alloc init in the class that I have around 10,000 instances of, which all have a property pointing to the same NSManagedObjectContext. Is this a possible way to do it or will I have to make my program less flexible by moving all of the code to create the 10,000 different objects to the View Controller?
Sure, just put your NSManagedObjectContext in a singleton and all your instances can access the single class.
It does not matter if you get your managed object context from a singleton or from your app delegate (where presumably you the core data stack is set up by default).
To follow the pattern suggested by Apple with view controllers, do the exact same thing with your views: give them a #property of type NSManagedObjectContext and set it during initialization. Seems straight forward enough.
The advantage of the singleton is that you do not even need the property on your view but can call the singleton instead. But why go there? From your comments I understand that you do not really know how a singleton works. You don't need it. Go with the class property solution.
One more caveat: with your setup, you are seriously braking the MVC architecture by giving the views access to your data. Instead, you should indeed have a view controller do this and then populate your views with the retrieved data. I do not think that there is a compelling reason to deviate from this principle.

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.

iOS: Singleton class for storage in UITableView app

I got a app that uses navigation controller and tableViews and I want to create a class to do some simple storage of information that stays persistent while navigating through the different views without saving to disk.
I can either create an singleton with only class methods, but in this case I´d need to create
the collection class holding the data as an instance variable (as #properties don´t work with class methods). I only ever see objects declared in properties in iOS, so is this frowned upon?
The class would look something like this
header:
+ (BOOL) addObject: (id) object;
+ (BOOL) removeObject: (id) object;
+ (NSInteger) count;
and privately I´ll have an NSArray for storage
NSArray *cache;
But is this a good way of achieving the task? or would it be possible to have a non-singelton class with instance methods and use that same instance of the class in the different table views? if so, how would I do that?
First, ALL readwrite properties auto-synthesize instance variables (unless you implement BOTH setter AND getter).
Second, if that information is global to the entire (or most of the) App, a singleton is just what you need. You don't need to keep it as a property (or an ivar). It's a singleton, it keeps its own pointer.
If you still want to go with a property, you will have to pass it some how to every VC in your App (prepareForSegue:sender: probably if you're using storyboards).
First figure out what global information you need. Then figure out what objects you already have that have a lifetime consistent with that global information, and which are logically associated with the info. Eg, if you need an array of info to "back up" a UITableView, store the pointer to that array in the table view data source instance.
It is rarely necessary to create a "singleton", and having lots of singletons is usually a sign of poor programming.

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.

Why only one delegate?

I've read that an object can only have one delegate at once.
But is that really true?
Let's say I make an object with a protocol and from that object I want to gather a lot of data from several other objects. I add every object that conforms to my protocol to an array. Then I just loop through it and call my methods on every delegate.
NSMutableArray *collectFromDelegates = [NSMutableArray alloc]init];
//in delegateArray I keep pointers to every delegate.
for(id delegate in delegateArray){
[collectFromDelegates addObject:[delegate someProtocolMethod]];
}
Is this wrong?
That's not really delegation.
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled.
It doesn't make much sense to have more than one object handle an event for you, since it has already been handled. The only reason I could see to have multiple delegates is that if the first fails to handle an event, it can be passed to the next, continuing until some object handles it.
In your example, the objects are acting as data sources. This makes more sense than multiple delegates, but could easily be implemented by having a single data source combine data from multiple objects, which means the object asking for the data doesn't have to worry about how to combine it.
The other case where you would often want multiple objects is receiving notifications of an event. This is not delegation because the objects are not working for the object, just acting on something that happened to the object. This is better implemented using notifications or observing.
Apple's convention is to only have one "delegate" object. But you can set up your own class to have an array of delegates if that's what you need. You might want to call them something else for clarity.
In your example, calling them "dataSources" might be more appropriate.
A class only really needs one delegate, if you have more than one you are solving a different problem. The delegate pattern is used to modify the behaviour of a class. Say for instance we have a Dog class which can bark, but different types of dogs bark in different way. A delegate would be one way of changing the barking behaviour.
If you need more than one you are probably more interested in OBSERVING what your class is doing, it needs to NOTIFY others of current EVENTS. As several other classes might be interested in the behaviour of one you would need an array. In iOS SDK this is already done for you with notifications. This is called the Observer pattern.
Different use cases...
I've read that an object can only have one delegate at once. But it's that really true?
Where did you read that? No, it's not true. For instance, UITableView has two delegates, one to supply the data, the other to handle actions.
A delegate is just an abstract concept - you can have as many delegates as you want. However, this is rarely required and often a poor pattern.
Apple make good use of a source and delegate pattern. Source ivars (a form of delegate) provide data, while delegate ivars are invoked for logical responses. Perhaps this is a better solution?
Alternatively you can use NSNotification to inform many listeners of a single event.
Hope this helps!
Generally, when you want to message multiple classes that are interested in what you class does, you would use NSNotifications. That will however not allow them to return data unless you allow them to send a message to the object of the notification. I'm not sure if that would be a cleaner solution though.
One approach beside the mentioned Notifications could be, that your delegate implementation holds an array of objects conforming to the protocol and calls the protocols method on this as a wrapper.

Resources