I am creating an Obj-C application, and am working on a single view. However, within this viewful, there is enough logic that I want to separate that from the view controller itself. I decided to create a delegate, but my current problem is how these two should communicate. Two potential solutions I have been considering:
1) An instance variable of the view controller within the delegate. Then when any view updates need to happen I simply call the appropriate method on that instance variable.
2) Notifications being fired off by the delegate and add the view controller as an observer.
Is there one method that is obviously superior or does it depend on the situation? I don't know the proper way to go about this and am trying to approach this from the correct angle.
If it's non-UI related responsibilities you want to separate from the view controller, it's very natural and recommended to have another object responsible for those tasks. In this case, you can either have a singleton for those responsibilities, or simply a NSObject subclass instance strongly referenced in your view controller.
If it's pure UI related tasks you want to separate from the view controller, just to organize the source code clearer, you should instead create categories for the view controller and name the categories according to their responsibilities, for example, MyViewController(Localization), MyViewController(UserInteration), etc.
This is a broad question. However, if what you are trying to do is simply refactor existing code to make maintenance easier without changing any functionality, use instance variables. Your code execution sequence will be unchanged and your method can return status information on the execution results. Your original controller and your new refactored class are tightly coupled - know a lot about each other.
Notification logic is event-based (something interesting happens and an event is sent to registered observers). The logic is executed when the observer receives the event so there is no guarantee you can control the exact execution sequence, and the caller does not know if the observer received or successfully processed the message - the are loosely coupled.
When in doubt look at what Apple does in its framework classes like UITableView. Delegates give you fine control over when things happen.
Related
I'm having multiple viewcontrollers (in a navigation stack or maybe not) and each controllers collects some data based on users input. In the end I need to use those data in the last controller.
So what would be the best approach/design-pattern to implement this scenario?
If you have (a navigation stack ) and you need to collect data from all this view controllers
the best way Not to use User-defaults , or Singleton
for your case you have to do container of view controllers to handle particular Process . Note (UINavigationController, UITabBarController, and UISplitViewController * is just containers)
For example create account that require 4 steps that collect users inputs , each step is represented by ViewController and at end you need to push all this data to API server ,
So create Parent ContainerViewController of child viewControllers and use Delegation to pass data after every step to ParentViewController , ParentViewController will be leader to allow next step and provide Data for this step . Here is how to begin create Your own Container managing-view-controllers-with-container
Do not use a Singleton
Singletons can be accessed directly from anywhere in the app. You have no control. a-lot coupling in your code and make your objects hard to test in the future
Do not use UserDefaults
UserDefaults is to store user preferences that persist between app executions.Anything stored there will stay until you remove, so it is not a mechanism to pass data between objects.
So you have to use architecture pattern in the future
Architecture
Each ViewController should only take care of their own screen . also viewController shouldn't know about each other. if we do this we will remove a-lot of coupling between our view controller classes.
So You can use Coordniator to be The leader that handle all navigation
Coordniator
and check how to Integrate with MVVM at MVVM-C
also Viper use this technique to handle navigation check Viper
Well, the best approach, in my opinion, is to use MVVM (Model-View-ViewModel) architecture pattern.
1) For each of your UIViewControllers, create a separate class (derive from NSObject if you wish) that's you consider to be the "view model" belonging to that UIViewController. Your view controllers are not allowed to access model classes... that's now a job of your "view model" classes.
2) Create a singleton named, say, DependencyManager. Your view models access it to obtain your models (or at least top-level models if they're hierarchial) and anything else they may need like networking services, etc... The DependencyManager acts as a way your unit tests can inject replacement "mock" versions of your models, network services, etc... when it's time to test each viewModel.
3) Create your model classe(s) that contain the data. Your view controllers had collected various data within the UI controls, and given that raw data to your viewModels. The viewModels may mutate that data (or not) and stick it into the appropriate models they acquire from the DependencyManager.
4) A ViewController is also allowed to ask their viewModel for data. So your last ViewController would obtain whatever data it needs from its viewModel.
Remember: ViewControllers should not directly manipulate your model classes.
Also, your ViewModels should never reference any UI objects, nor even have a reference to its ViewController.
Side Note: I recommend having each ViewModel conform to a protocol which derives from an empty protocol named something like "MockableViewModelProtocol". You can add a single property to your DependencyManager of type MockableViewModelProtocol that each of your ViewControllers can check before they create their ViewModel, in case a unit test has assigned a mock ViewModel for the ViewController to substitute. Another benefit of such a protocol is for quick & clear understanding of the relationship between a ViewModel and its ViewController. Often you'll have not just properties and methods but also callback properties (closure properties).
So there ya go. That, in my opinion, is the best way to not only design a way to manage and access data among a bunch of viewControllers, but to also test all your classes and their use of that data.
And unlike all the current claims that Storyboards block dependency injection and thus prevent testing of your ViewControllers, that's just bunk. By using a DependencyManager, such that your view controller tests inject mocks there, the tests get the same benefit as if they injected a mock directly into the ViewController, and yet the ViewController is still instantiated by the Storyboard. I've shipped a large app quite successfully with this approach.
There can be multiple ways to achieve that,
Pass the data along the controllers until the last one where you want to use it.
Use a Singleton to store the data from each controller. The only issue with Singleton is that it will persist in your app.
You can also store the data in UserDefaults. After using the data, you can clear it out from UserDefaults.
Let me know if you still face any issues.
In my opinion the best way to handle this would be to use a Flux design pattern. There is a framework called ReSwift on github that allows for unidirectional data flow similar to Redux.
Even if you do not use this framework specifically, the concept of unidirectional data flow is perfect for this situation. The state gathered from each view controller will exist outside of any view controllers, the view controllers will stay agnostic of each other, and there will be no need for any parent view controllers to act has higher order coordinators. Then on your last view controller, you access the state and use it however you need.
Another benefit is if you need to break out your view controllers into multiple view controllers through containers, i.e. one screen has 2+ view controllers, you will not need to create more infrastructure to pass data between those, which in my experience gets really messy.
I am creating a login app for iOS and have stumbled upon a design issue. In my app some data (e.g. current user id) has to be shared across view controllers so my initial thought was to hold that data in the AppDelegate and just call it from there whenever it was needed. This would work but it would mean that the AppDelegate would be doing work that it wasn't intended to do and hence it would be bad architecture, so I thought of creating a singleton class to hold all the shared data instead. This seems to be more focused and I have used this strategy in some of my previous apps, but googling the best practices for singleton classes, I found many results against using them, as they:
Hide dependencies
Violate the single responsibility principle
Make unit testing difficult
(taken from the top answer to this question: What is so bad about singletons?)
The alternative to the two other design patterns would then be to pass data back an forth between view controllers, but this again seems inappropriate. Take for example the current user id I would have to pass it from the login view controller to the main view controller (which is the same for all users), then from the main view controller to a more specified view controller which is customized for the user. In this case the main view controller is holding data only for the purpose of passing it to the more specific view controller and to me this also seems to violate the single responsibility principle. Would it be bad design to let the main view controller hold data it doesn't need or is there a better alternative?
There is no "magic" way of storing the model state of your model-view-controller application: you build a class, and you "anchor" it somewhere for easy access.
One common practice is using the app delegate. It is convenient, because it is a system-supplied singleton globally available to your app, but it is logically inferior, because, as you noted, app delegate was not intended for that.
Another common strategy is using a singleton. This is commonplace in app development, and it works fine in practice. You can mitigate the common grievances by limiting the access to your singleton to initializers of your view controller - this addresses the hidden dependencies and the testability issues.
Finally, you can pass the data around, in which case it is the same as "anchoring" it in one of the view controllers. Arguably, this leads to even bigger problems than singletons, because the dependencies become even harder to trace.
I would recommend storing the state in a singleton, and use it in the initialization code of your view controllers. This way the dependency on the singleton remains localized, and you could test your logic with minimal effort.
I am creating an app and using Parse.com for Data Storage.
I would like to use a Model for all the different aspects of Parse that I use. For example, if I store some Game data I would like a model to handle doing any finds/updates/entries into a Game model held on Parse.
So I would like a Model to handle all these methods, instead of adding these into the View Controllers.
What is the best/correct way to set these up? I have heard of singletons but not sure if they would be correct here.
At present, I set these up using a subclass of NSObject. I then create all the methods as class methods (no instance methods as there is no instance to create). I then call any class method as usual.
[GameModel classMethodName];
Would this be correct? Is there a better approach or any issues with this approach?
At present, I set these up using a subclass of NSObject. I then create
all the methods as class methods (no instance methods as there is no
instance to create). I then call any class method as usual.
This doesn't sound like a very good plan. The job of a model is to manage the data that your application operates on. That means that your model should have data to store, which means that you should be instantiating your model.
Building support for your back end infrastructure (Parse, in your case) is a good idea. It's much better to put it there than to put it in your view controllers. But where does that supporting code store the game state, for example, or the player's history? It should store it in the model object(s).
Without getting into the whole singletons good vs. singletons bad can of worms (you should Google that), it sounds like you're using class methods for much the same reason that people often use singletons: easy access. Instantiating your class and using instance methods instead of class methods would mean that you have to find a way to share the model with those objects that need it, and that's more work than just using the globally accessible class methods. Doing that work will make for a better application, though.
For example, you could restrict each view controller's access to just those parts of the model that it needs. The game play view controller might only get to see the current game board, and the high scores view controller would only see the player's history. That eliminates many possible bugs -- you'll never have to wonder if the game board view controller is causing a problem with the player history, because it never sees that part of the model.
I've not looked at the AutoMapper source code yet but was just about to make some changes to an API controller in my solution and had a thought.
The way I like to code is to keep my controller methods as concise as possible, for for instances I make use of a generic Exception attribute to handle try{}catch{} scenarios.
So only the code that is absolutely relevant to the controller action is actually in the action method.
So I just arrived at a situation where I need to create an AutoMapper map for a method. I was initially thinking that I would add this (as I have done previously) to the controller constructor so its available immediately.
However, as the controller grows following this pattern may introduce a lot unnecessary AutoMapper work depending on the controller action method which is invoked.
Considering controllers are created and destroyed per request this could get expensive.
What are some recommendations around this? Considering AutoMapper is accessed statically I was wondering if it's internals live beyond the request lifetime and it internally checks for an existing map before creating a new one each time CreateMap() is invoked?
You should create your maps (CreateMap) once per AppDomain, ideally when this domain starts (Application_Start).
Say I have a core data model with a few entities and, throughout the application's lifecycle, I'll be getting and setting properties of these entities from different views.
At least to me, it seems like passing the managed object context around from view controller to view controller and having the controller's code know about the different entities or derived objects goes against decoupling. As a matter of fact, there is a similar question where the only answer suggests passing around the managed object context.
So, in the spirit of MVC, I thought it might make more sense for view controllers to stick to controlling views, and have a singleton model controller through which these view controllers can query the model to feed their views and notify back when the model needs to be updated based on user interaction with the view.
But I'm not sure how to go about implementing the single model controller interface. For instance, here's a few ideas:
make this controller both a delegate and data source to all view controllers?
have the controller be only a data source and use notifications for updates?
kvc/o?
is the whole idea of a centralized bridge from/to the model just overengineering the MVC pattern? That is, is there some reasonable argument in favor of instead passing the managed context around and this not being considered crappy object-oriented design?
Another thing I'm thinking is, if the singleton controller is a delegate and data source, the methods to get model data and update the model should implement some sort of visitor pattern, right? Meaning, for example, if view controller A allows the user to interact with model entity / object A and some view controller B allows for the same for a model object B, and both view controllers rely on the same delegate, the delegate will have to have some way to know which model entity it should target depending on what concrete controller is calling on it.
I'd appreciate any thoughts / ideas
Your idea of a "model controller" makes sense, the problem is I think you may be thinking of it wrong.
It's not really a "model controller," it is the model. In MVC (traditionally), the views communicate with their controller for advice on what to do with interactions, and the controller decides what to tell them based on its logic and information it gathers from the model.
So really, you're simply abstracting the model further, which is a good thing. The idea of a "centralized bridge" is what you want in MVC. Your controller should see a high-level abstraction of the underlying model's implementation, as with all interfaces and layers of abstraction.
As far as implementing the model goes, I'm not sure which is the "best" way to do it, but I can't imagine using the delegate/data source strategy (or sending notifications to the controller) would be detrimental, I'd guess it depends on what you're comfortable with. If you love KVC/KVO, I doubt it'll hurt you. As far as the visitor pattern goes, the logic concerning keeping track of which controller gets which object should be within the model.
It seems to me that your biggest concern is with passing the model around from controllers. It is perfectly alright for the controllers to reference and use the model, but trying to manage their creation and penetration, you're right, is a bit much.
I'd recommend using a Dependency Injection container that can generate the access layer to your model. This way the controllers will get the model passed to them via DI, w/o having to pass around how to create the model classes.
The idea of a single centralized bridge isn't a bad one either, but it would make things a little tricky to unit test.
In the end, I ended up dropping the delegate / datasource approach for a singleton pattern:
I figured the following:
all controllers are collaborating with a single shared
managedObjectContext
the Core Data model itself revolves around a single "configuration"
entity (not the configurations that the Core Data literature refers
to).
This "default configuration" is also what all controllers interact
with, since all other entities exist in the context of this
configuration entity.
So essentially, I have a shared resource which should be accessible in a way similar to a global variable.
So I encapsulated the shared resource in a Singleton through whose interface all other controllers can query and modify the model without knowing much about the internals.
The general interface allows for things like:
[ModelControllerBridge sharedBridge] defaultConfiguration] which
returns the default shared NSManagedObject
[[ModelControllerBridge sharedBridge] newDataSample] which returns a
new NSManagedObject and internally allocates and inserts it in the
appropriate entity within the model.
[[ModelControllerBridge] shouldCommitChangesToModel] which signals
the context should be committed to the permanent store
etc.