MVC Model - Should controller access view's controls directly? - ios

I'm learning iOS development stuff and what I have found in tutorials and books is that controller layer usually has access to the View's controls directly (textfields, labels etc.). Let's consider such an example:
Assume, that View has a label called lblResult and a textfield called txtDataToAnalyze. Than in controler interface we've got something like this:
#property (nonatomic, retain) IBOutlet UILabel* lblResult;
#property (nonatomic, retain) IBOutlet UITextField* txtDataToAnalyze;
and some #synthesize statements in the implementation file.
I have some experience with JavaSwing development, where most of thinks I'm writing manually without any GUI Builders, and what I usually do in MVC is to access the View's controls via getters/setter. For example: void setResult(String resString); or String getDataToAnalyze();. In that way, controller knows only what pieces of information are displayed in the view, and not how are they displayed. I think it is more flexible (it is easier to change the view layer later).
I know that iOS has some specific rules, has introduced XIB/NIB files etc so maybe my doubts are completely useless in case of iPhone/iPad development. But I am going to write some more serious application for iOS (actually "rewrite" it from Java Swing) and that's why I would like to ask you:
Do you think, I should change the way I am thinking and get accustomed to that new (for me) approach (xib files, creating GUI using drag&drop and providing controler with information about how data should be displayed in view) ?? Did you have similar doubts when starting with iOS?

Short answer:
Yes, I think you should definitely spend a little time getting accustomed to working with Interface Builder (IB) to make NIBs and storyboards and let IB create the IBOutlet and IBAction references for you for those controls with which you need to interact. Once you're proficient at it, you'll be impressed by your productivity in generating easily maintained code. Don't dismiss IB too quickly.
In terms of letting the controller interact directly with the IBOutlet and IBAction references, this is common practice for simple user interfaces. If you have some real world examples, post a new question with a screen snapshot and we can offer more practical guidance.
Long answer:
Part of your question seems to be driven by the apprehension in seeing view controllers that are doing detailed interaction with a view's controls. The thing is, if you want to isolate your controller from some of the implementation details of the view, then go ahead and subclass the view and put the view specific stuff in there. IB can interface with both view controller subclasses as well as view subclasses. So you can happily use IB and still isolate your view controller from some of these implementation details.
Personally, I only do this subclassing of UIView when the view hits some subjective complexity threshold (e.g. for me, that threshold is when I find myself doing some complicated animation, such as using CADisplayLink; complicated gesture recognizers, etc.). I also subclass those subviews that are logical entities of their own (e.g. UITableViewCell or UICollectionViewCell). But for simple views where I'm interacting with my model to setting a control's properties, interacting with text fields, etc., I think putting that in the view controller is fine. Having said that, if I have a lot of view-specific code in my controller which has nothing to do with the integration of my model with my view, then start subclassing the UIView and shifting the view-only code into that.
Implicit in your question is the notion of programmatically building view rather than using NIBs/storyboards. In my opinion, using Interface Builder (IB) to build your UI is much easier to develop and maintain. There might be some pedagogical value to doing a test project where you build your views programmatically, so you really understand what's going on, but after that, I think you'll find yourself quickly gravitating to storyboards. And you'll get plenty of chances to write your own non-IB code when you start doing things beyond the capabilities of the standard IB controls (e.g. complicated custom container views, etc.). There are definitely those who prefer to develop views programmatically, but I don't think you can beat the development speed and ease of maintenance of IB generated UIs.

I general, the controller does not know about the view, but the view knows about the controller.
The gang of four book says:
"MVC also lets you change the way a view responds to user input without changing its visual presentation. You might want to change the way it responds to the keyboard, for example, or have it use a pop-up menu instead of command keys. MVC encapsulates the response mechanism in a Controller object. There is a class hierarchy of controllers, making it easy to create a new controller as a variation on an existing one.
A view uses an instance of a Controller subclass to implement a particular response strategy; to implement a different strategy, simply replace the instance with a different kind of controller. It's even possible to change a view's controller at run-time to let the view change the way it responds to user input. For example, a view can be disabled so that it doesn't accept input simply by giving it a controller that ignores input events.
The View-Controller relationship is an example of the Strategy (315) design pattern. A Strategy is an object that represents an algorithm. It's useful when you want to replace the algorithm either statically or dynamically, when you have a lot of variants of the algorithm, or when the algorithm has complex data structures that you want to encapsulate."

Related

UIView class has too many delegate methods to parent View Controller?

I'm a bit of a newbie programmer, so I'm asking for people's opinions/advice on what they would do in the situation I'm in.
Background
Due to constraints of the library I'm using to achieve a "pop up" like window, I'm currently working on a UIView class (let's call it Menu) which creates UIImagePickers and various other View Controllers (VCs). However, since the UIView itself persists on top of any VCs it spawns itself, I'm forced to delegate any VC creation methods to the parentVC of Menu, so that I can dismiss the Menu view, create any VCs necessary, and then (sometimes) additionally restore the Menu view.
Issue
I'm currently copy and pasting hundreds of lines of delegate methods for any UIViewController that has a Menu view. These delegate methods are the same for every one of those view controllers, and exist there because the methods have UIViewController specific functions such as presentViewController. I'm tempted to pass the parentVC as a parameter to Menu in order to cut down on the amount of duplicate code, but this seems MVC-unkosher. What would be a good approach to this problem?
If I understood right, you can Just create an extension, like this
extension SomeClass: ClassesDelegates {
//some specific code that all Views will use
}
I'm tempted to pass the parentVC as a parameter to Menu in order to cut down on the amount of duplicate code, but this seems MVC-unkosher.
That's because MVC is a dated architectural choice, leading to exactly this kind of situation. That's where the "Massive View Controller" snark that you may have noticed here and there around the web comes from.
Your Menu depends on parentVC. Thus, we call parentVC a dependency. A fundamental precept of modern architectures is dependency injection, which allows you to eliminate the duplicate code you refer to and test Menu in isolation from its dependencies. Check out
Dependency Injection Demystified
Dependency Injection
Dependency Injection, iOS and You
Dependency Injection in Swift
So, fear not the use of parameters, your instincts are sound. Embrace the use of parameters, and preen that you are adopting the "25-dollar term for a 5-cent concept" (see first link), the Agile design pattern referred to as Dependency Injection. For bonus cool points, do not make that parameter a UIViewController. Define a protocol with just the access that Menu requires, and make that parameter anything that conforms to said protocol, and add an extension to UIViewController conforming to that protocol. That makes testing and reuse elsewhere easier; and more importantly, then you will be engaging in Protocol-Oriented Programming, which puts you right out on the cutting edge of trendy Swift design patterns. Nobody will call you a newbie then.

Singleton-Like UIView Access?

I have a UIView I need to access the properties of from all around my app. I know you can't create a Singleton around a UIView object, so what might be a good way of doing similar?
E.g. The view has a label. From any view controller in my app I want to be able to change the text of this view (sitting in a parent view controller).
Thanks.
EDIT:
Success! Using KVO to track changes in my Singleton object worked a charm, and a very simple solution.
I think what you’re trying to do violates the separation of concerns of the MVC pattern: The only thing that should interact with a view is its controller. In your case, you should probably be creating a model that is watched by your view controller (maybe through key–value observing), and then the controller can propagate the necessary changes to your view.
If you know (read: you really know for now and forever!) that there will be at most one instance of that view alive at one point in time, you can just use a global variable to store that. Or use a class property on that view - which is as close as being a singleton as possible.
Or you might just fix your design, which has proven to be the better choice in every case I can remember. :) Just add some forward and backward references in your classes (and stick to MVC principle). It takes much less time to implement that worrying about those awkward workaround, and it will pay of rather sooner than later.

Should views hold model references?

Let's say we have the following classes:
View
#interface ArticleView : UIView
#property IBOutlet UILabel *titleLabel;
#property IBOutlet UILabel *bodyLabel;
#end
Model
#interface Article : NSObject
#property NSString *title;
#property NSString *body;
#end
Controller
#interface ArticleViewController : UIViewController
#property Article *myArticle;
#property ArticleView *myArticleView;
- (void)displayArticle;
#end
#implementation
- (void)displayArticle {
// OPTION 1
myArticleView.titleLabel.text = myArticle.title;
myArticleView.bodyLabel.text = myArticle.body;
// ... or ...
// OPTION 2
myArticleView.article = myArticle;
}
#end
OPTION 1
PRO: Both the view and model aren't coupled to each other.
CON: The controller needs to know the details of both the model and view.
OPTION 2
PRO: The controller code is light and flexible (if the view or model change, the controller code stays the same.
CON: The view and model are coupled and therefore less reusable.
In OPTION 2, ArticleView will have to be changed to hold a reference to the model:
#interface ArticleView : UIView
#property IBOutlet UILabel *titleLabel;
#property IBOutlet UILabel *bodyLabel;
#property Article *article;
#end
The article setter can then be overwritten to update the view accordingly, like so:
- (void)setArticle:(Article *)newArticle {
_article = newArticle;
self.titleLabel.text = _article.title;
self.bodyLabel.text = _article.body;
}
So my question is, which one of these two options is best in terms of OO and iOS/MVC best practices?
I've certainly seen both being used. I've seen OPTION 2 used commonly in UITableViewCell subclasses.
I've also read that views and models should be designed to be reusable and not depend on anything whereas view controllers are meant to be the least reusable of the bunch.
My gut feeling is to use OPTION 1 simply because I'd rather the view controller do the dirty work of binding the model to the view and let the model and view stay independent and unaware of each other. But since some views are designed to do one thing only then perhaps it's not so bad to have them tied to a specific model directly.
I'd love to hear your opinions on this.
It's not always an either/or decision. Your first option is more typical of Apple's version of MVC; it's generally true in iOS that the model and view don't talk to each other directly, and the controller does most of the coordinating between them. However, it's not unreasonable to have a custom view that knows about specific classes within the larger model. You might well have an ArticleView that knows what to do with an Article, but the ArticleView should still receive any Article that it displays from the controller instead of getting it directly from the larger model.
One of the goals of MVC is to make model and view classes more reusable. If you keep your ArticleView very simple, so that the controller has to do all of the work of interpreting an Article, then you may actually be losing reusability -- every time you want to reuse ArticleView with a new view controller, you have to reproduce all the code that interprets the article for the ArticleView. Alternately, you always use the same view controller class to manage an ArticleView. Neither of these is really "reusable."
At the same time, you have to acknowledge that there's some natural coupling between Article and ArticleView simply by virtue of the fact that ArticleView is designed to display all the relevant details of an Article, whether it gets them directly from the Article or has them set by the view controller. If Article changes, there's a strong probability that ArticleView will have to change whether it knows about Article or not.
So, even though Article may be a model class, it can be okay to have a view that knows about it. What you don't want is an ArticleView that knows about the larger model and tries to fetch articles from the model itself. That limits the articles that you can display in ArticleView to just those that can be found where ArticleView looks -- it prevents you from displaying articles from other sources.
Yes, you have demonstrated understanding of the subject.
OPTION 1 is the classical structure of MVC, and I recommend it as your default route of the two presented.
Just because OPTION 1 is a purer definition, it doesn't mean that it need be applied everywhere possible.
The most frequent deviation I make is when an implementation is so specific and not reused that introducing a dedicated controller type just results in more code to write and maintain when the implementations are tiny, very specialized, not reusable, and will not grow substantially. If the program lends itself well to folding the V and the C into a single implementation and fits in something small (e.g. tens of lines of code), I don't worry about using OPTION 2.
Reality is more complicated than that, but the gist is: don't feel like you need to adhere to #1, although you probably won't understand how using #2 can introduce maintenance issues until you have written and maintained some moderate sized programs for a few years. Moving from one to the other can introduce many changes in a shipped program -- which could have been avoided.
Use of OPTION 2 should be the minority. If in doubt, use OPTION 1.
Either way, I believe the model should not know about the view or the controller.
To me, strict adherence is more important when writing reusable components.
Frankly, sometimes I do Option 2 myself. But Option 1 is 'out of the book'.
As others have said, Option 1 is the purer approach. The controller should be a "junction box" between the view and the model.
However a number of implementations of this type of approach (for example the framework that Microsoft call MVC) plump for Option 2. Certainly in Microsoft's case, the fact that the View and Model know about each other allows the IDE to create lots of boilerplate code, and save you the "trouble". The advantage of this is that you spend your time writing "function" code rather than "wiring" code. So, pure or not, you can appreciate where they're coming from.
As so often in software development, the choice between Option 1 and Option 2 boils down to purity versus pragmatism.
In terms of Apple's official guidance on this topic, the MVC as a Compound Design Pattern section of the Concepts in Objective-C Programming document discusses both approaches, but clearly articulates Apple's preference of your option 1 over your option 2. In fact the Cocoa Core Competencies only lists option 1.
I've never regretted implementing the option 1 approach, but when I've cut corners and tried to have models and views interact directly, I've often regretted it when I've had to go back and modify a system at later date.
Option 1 is MVC. Option 2 is not.
OO is at a different level really, you have objects for the Model, View and Controller so you can't do much more to be OO.
Both options will of course work, but MVC exists for a reason (I'm sure you've already done some general reading like this) and you'll find that your code is easier to read, understand and reuse if you follow the principles of MVC.

UIViewController's initWithNibName: a reason behind this design?

I tend to agree with Joe Conway’s and Aaron Hillegass’s analysis, as reported today by Ole Begemann in http://oleb.net/blog/2012/01/initWithNibName-bundle-breaks-encapsulation/
Basically, they state that the NIB's filename is an implementation detail of the corresponding UIViewController class, and that it is not the business of the calling class to pass in the NIB's filename in the init method.
I was wondering if there was any particular reason for this design choice from the creators of AppKit/UIKit, or if it is merely a mistake — and, in the latter case, why it wasn't corrected when UIKit came out, which would have been a good opportunity.
If any Objective-C old-timer could provide the historical background to this, that would be nice to get a better understanding of the framework we use every day.
I suspect it was done this way so that a UIViewController could have basic functionality as a controller without requiring any subclassing. For example, if you're just pushing a "Credits" view on a navigation controller, and the view has nothing but static text, you could get away with not creating a UIViewController subclass. You could simply create a UIViewController directly and pass it the nib that contains your static text.
Most of the time, of course, you're going to want some level of interaction with the presented content, in which case a custom controller is necessary. But in theory, it's not always required.
It has come to my mind today that maybe Storyboards are precisely a response to that issue. Because Storyboards are defined at application-level, there is no more violation of encapsulation, merely a change of level. UIViewController subclasses become the detail implementation of the Storyboard as a whole.
It still doesn't explain the historical reasons behind the original design, but at least they have done something to address the issue — and, as often with Apple, in a very elegant way.

iOS: handling of UIGestureRecognisers in UI(Sub)Views

I would like to know how to best possible address the following issue:
I have a single ViewController. Its view contains a great number of complex subviews (subclass of UIView). Due to the complexity some of these UIViews initialise their own UIGestureRecognisers and implement the according target actions. As I want to coordinate the gestures of various subviews I have to set the single once ViewController as the gesture's delegate.
There are various possibilities for that.
1) Initialize ALL gestures in the the viewController (this will lead to a massive viewController)
2) defining a protocol in the UIVIews (getViewController), implemented by the ViewController
#protocol CustomViewDelegate <NSObject>
#required
- (UIViewController *)getViewController;
#end
3) customise the init method of the UIViews and using the ViewController as an option.
- (id)initWithFrame:(CGRect)frame andViewController:(UIViewController *)vc;
What is the most elegant possibility to solve this issue? Is it OK to implement target actions inside a UIView object?
Thanks for your thoughts...
If you're defining custom UIView subclasses, you can invest them with as much logic as it makes sense to store local to them, give them delegate protocols to pass anything else up and, as long as you expose the delegate as an IBOutlet, you can wire up your view controller as the relevant delegate directly in Interface Builder or the UI designer part of Xcode 4. I personally think that would be the most natural way forward, since it consolidates any view-specific logic directly in the view and lets you do the wiring up where you would normally do the wiring up.
In terms of overall design, such a scheme conforms to model-view-controller provided your views are doing only view-related logic. So, for example, if you had a custom rectangular view that can take a swipe anywhere on it to reposition a pin, and the 2d position of the pin affects some other system setting, you'd be correct to catch the gesture in the view, reposition the pin and then send updates on its position down to the delegate, which would fulfil the role of controller and push the value to any other views that are affected and out to the model.
Commenting on your suggested solutions directly:
(1) this would focus all logic into the one controller; whether it's correct from a design point-of-view depends on the extent to which you're having to interrogate your custom views (in that you don't want to end up treating them as mostly data that external actors have to know how to manipulate) and the extent to which you want to reuse logic.
(2) I'm not sure I entirely understand the suggestion — what is getViewController defined on and how does it know how to respond? If it's the UIViews themselves and the view controller has to identify itself first then I'd suggest just adopting the delegate pattern wholesale rather than specialising to views and view controllers, e.g. as you may want to build compound views that tie together logic from several subviews.
(3) as a rule of thumb, the sort of things to pass to init are those that the class actually needs to know to be able to initialise; it would probably be better to use a normal property to set the controller after the fact. Or make it an IBOutlet and wire it up so that it happens automatically via the NIB.

Resources