I have got several types of a logic controller class that handle the communication with a remote resource. To do so each class uses an instance of a network controller class that deals with the connection details: connects to a resource, sends data, receives data. The logic controller classes are notified of data changes from the network controller class using notifications. So in my current solution each logic controller class registers for the notifications and implements specific functions to deal with them differently.
However, if I want to do proper code engineering, I wonder whether it would be more robust to use protocols and delegation.
I wonder if I could define which methods the logical controller classes need to implement in order to receive the notification. However I am not sure if this makes sense and is correct because I do not want inheritance here.
Any suggestion?
Typically you have 1 or 2 (explained later) methods per notification. So it is a quite simple mapping. The reason for that is that you have one notification per "event" and there is little reason to chance that for delegation.
But your design is good. What is the difference between delegation and notifications? (Robustness is not.)
A delegate is a single instance that customizes the behavior of the delegating instance. Therefore beside the usual "inform" methods (will…, did…) it can have the ability to change the behavior of the delegating, i. e. returning NO as an "invalid marker" (should…) or change the data set, a operation is executed on. (Sometimes this is the 2nd method for an event.) It is obvious that in such cases you cannot have multiple instances at a time. Delegation is in competition with subclassing and often the better choice (white boxing vs. black boxing).
You can have as many notification receivers as you want to. Obviously they cannot change the behavior of the notification sender. Therefore it is the better choice, if you have several instances that only needs an information that an event happened.
If understood your use case correctly, notifications are perfectly fitting your requirements.
Related
I have some complex networking in my app( I don't use any third party dependencies, because of project requirements). For instance, I send three network requests in parallel after first two requests provide results. All my networking is done in separate models, known as networkClients(following MVC-S pattern) and are called directly from repository, not from ViewControllers. However, I need the last request to notify my viewController after I get response from network. How should I do that? I don't think notification center would be right solution because it can cause memory leaks and I have not found correct approach to complex problem like this. Please provide some prominent solutions. It should conform to good design pattern like MVVM or MVC and should not be some workaround or hack. Maybe delegates would work? I know that rxSwift would solve my issue, because I could start observing for results after initializing viewController and after data would be updated from repository my viewController would also be notified...
The right design doesn't have VCs observing the network clients directly. Those network operations should be assembling parts of a model, which is what the VC really cares about. Have the VC observe that singular model.
It can do this observing using one of the well known patterns for loosely coupled communication between objects. The OP correctly mentions delegates. Notification center and KVO are others. There's plenty of discussion on SO about which to use and how to implement. (I'd go with NSNotificationCenter as an easy and rational start).
So the order of operation is like this:
allocate the model
launch the network requests and setup those request completions (completion blocks, probably) to update that model with their responses. (the model can launch the requests, which is a reasonable practice).
create the view controller(s) that setup model observation when they initialize (probably, in viewWillAppear or later)
What about the fact that >1 requests are in flight simultaneously? A commenter above points out correctly that GCD offers a way to group those async operations into a single one. But you can do this yourself straight-forwardly: the model decides when it's completely built. The completion code for each request will change some condition in the model to the "ready" state. Each request completion can check to see whether all of the ready conditions are met, and only then post a "ready" notification for observers to see.
Another niggling issue: what if those requests all run very, very fast? Maybe there's some cached response that's ready early, making the model "ready" before the VC has had a chance to setup observation? Handle this straight-forwardly in the VC: before observing the model, check to see if it's ready already and run the same update code that runs on the notification.
I'll like to know why Apple allow to create more than one instance of HMHomeManager and what is the purpose of it?
I would expect the instance of HMHomeManager to be a singleton.
I can't speak for Apple but I see no cases where HMHomeManager would benefit from being a singleton and several clear disadvantages.
HMHomeManager has a delegate property. The delegate pattern works well when you want a delegator to send messages to a single delegate or when many delegators might share a delegate. It is however not useful when one delegator might produce messages of interest to many delegates which would be the case if HMHomeManager were a singleton.
Singletons are not easily deallocated. Any app using a HMHomeManager as a singleton would keep that object in memory monitoring for changes to the home database even if it was no longer needed.
The assumption that there should only ever be one HMHomeManager may not hold true forever. While one HMHomeManager can contain many homes they all share a common user. Designing this class as a singleton would preclude an app from acting on behalf of multiple users at once. Even if there's never a need for such behavior developers might be wise to avoid selecting an interface which cannot support it early in the design process.
Don't create multiple instances of HMHomeManager.May be below code will be helpful. If you want to made any changes to the existing home try to execute the code after made the changes like add room,zone...
for(HMHome *home in appDelegate.homeManager.homes)
{
if([home.name isEqualToString:appDel.selectedHome.name])
{
appDel.selectedHome = home;
}
}
I would expect internally there is a singleton client that communicates with the home daemon, the same way CLLocationManager has a singleton CLLocationInternalClient.sharedServiceClient which allows us to scatter location managers throughout our app without having to worry about forwarding notifications or multicasting delegate methods around ourselves. I haven't examined HMHomeManager as closely and it does seem quite a rushed API so maybe not as well designed. It's concerning the documentation mentions "the manager for your app" as if we are only supposed to have one. Furthermore when you receive the home changed delegate call it tells us to "invalidate your own app's objects that cache the home's data". One thing I have noticed is when you init a HMHomeManager it inits all the rooms, services and accessory objects which in my case is about 400KB (calculated by initing 10 home managers and comparing the RAM difference) for my 301 characteristics, 68 services, 19 accessories home (I used Allocations in Instruments searching for 'HM' to learn this). So we probably should stick to one manager per app but there is a serious design problem with the API that when we toggle a characteristic the delegate method isn't called so we need to reach out to our app's object and invalidate it rather than it happening automatically for us like any other API would.
I am building a remote app which is receiving different states of its accessory. It is receiving things like: power state on/off, volume state 5, equalizer setting jazz, etc. and has nothing more to do than map theses states into the UI with selected or unselected states and send changes done back to the accessory.
About the app architecture:
The app is connected with it's accessory as illustrated in Apples EADemo project using the external accessory framework.
The UI is build within non-repeating customized UITableViewCell full of UIButtons. When starting the app a data model class will receive all current states from the examples EADSessionController and has to communicate theses states to the UI (the cells directly rather than the UITableViewController) with one of the mentioned patterns. This will be a stand alone, one-page app looking like a real remote.
Thinking of NSNotification, delegates and KVO (key-value-observing) I am trying to figure out which of these patterns I should use for this special approach?
Any answer on why choosing one of them and a brief description on how to implement would be appreciated. If your answer will be KVO please give some more insights since I never used this pattern so far.
It really depends.
The most loosely coupled one is to use NSNotification and NSNotificationCenter, as the instance which post the notification does not necessarily have knowledge about the observer, and there can be more than one observer.
The delegate pattern is a little more rigid, and there could usually be only one delegate object that receives a message. If the UITableViewController in your project is the only instance that handles a message(, or it would properly propagate the message to other components), it is still OK.
The KVO pattern requires more precisely designed observation relationship. You will have and have to look after exactly how the KVO is implemented. And KVO also allows one-to-many observation. The down side of KVO is if the observing relationship is dynamic and transient, you must take much more care about how these objects were torn down, or you could get a lot of crashes like sending updates to a dealloc'ed instance, etc.
If you are working on a library which would be delivered to a 3rd party to use, perhaps NSNotification would be the first choice.
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
At the above link, I see the following in regards to how the model layer should communicate with the ViewController.
"When a model object changes (for example, new data is received over a network connection), it notifies a controller object, which updates the appropriate view objects."
My question is, how does the model object notify the Controller object? What are various ways this can be done? My model layer gets the user's location and then calls a web service. How should I notify the controller object when that data is downloaded?
There are several ways to do this, depending on your specific case. Generally you would use a protocol/delegate implementation, key value observing, or notifications. There is a pretty good overview here.
Edit:
Thought I should add, as the comment to this answer mentioned: using callback blocks is also a very solid option, depending on your needs. There are a lot of possible deciding factors on what solutions are best for what cases but here is a general outline I follow.
If you are guaranteed to only need one observer at a time: I generally use blocks or delegates. My personal preference is that I use blocks if there are only one or two callbacks because this is where they shine, but I use delegate protocols if there more than a few possible methods.
If you may need multiple observers, I use notifications via NSNotificationCenter.
I use Key-Value-Observing when I only need to observe specific properties on an instance, instead of events.
I'm just beginning to work on iPhone apps. How do I know when I should be putting stuff in AppDelegate versus a custom class? Is there a rule or any type of analogy with another programming language like Python or PHP that uses an AppDelegate like pattern?
I normally avoid the design approach implied by Andrew's use of the term "heart of your application". What I mean by this is that I think you should avoid lumping too many things in a central location -- good program design normally involves separating functionality by "area of concern".
A delegate object is an object that gets notified when the object to which it is connected reaches certain events or states. In this case, the Application Delegate is an object which receives notifications when the UIApplication object reaches certain states. In many respects, it is a specialized one-to-one Observer pattern.
This means that the "area of concern" for the AppDelegate is handling special UIApplication states. The most important of these are:
applicationDidFinishLaunching: - good for handling on-startup configuration and construction
applicationWillTerminate: - good for cleaning up at the end
You should avoid putting other functionality in the AppDelegate since they don't really belong there. Such other functionality includes:
Document data -- you should have a document manager singleton (for multiple document applications) or a document singleton (for single document applications)
Button/table/view controllers, view delegate methods or other view handling (except for construction of the top-level view in applicationDidFinishLaunching:) -- this work should be in respective view controller classes.
Many people lump these things into their AppDelegate because they are lazy or they think the AppDelegate controls the whole program. You should avoid centralizing in your AppDelegate since it muddies the areas of concern in the app and doesn't scale.
Your application delegate is the heart of your application. It's effectively your "Program Controller".
The Application Delegate is the class that receives application-level messages, including the applicationDidFinishLaunching message most commonly used to initiate the creation of other views.
While not exactly similar you could think of it as the "main()" routine of your Cocoa program.
#Shivam, thanks.
From what I understand of appDelegate, is close to what an Application is in Android. The viewDidLoad, viewDidDisappear is comparable to what Android's Lifecycle. Every application has a life cycle, from launching to interruptions from calls coming in, to notifications showing up. If you need your code to do something special when these system events occur then you need to write code the methods.
In Android we use onPause, onDestroy, onCreate kinda callback methods to handle such system events.
Hope this will help a little more ...
Programmers new to this language always have the same question - does the program start from a main method? Yes, you are right in this case; IOS apps also start from a main method. Your main class calls the below function:
UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
UIApplicationMain kicks off the Cocoa Touch run loop and app infrastructure which creates a UIApplication object. Our application needs content so objective-c uses a delegate to handle this. That's why we call it AppDelegate (act as delegate of UIApplication). We implement some of the optional methods of that delegate and it behaves accordingly.