Subviews has a delegates, bad design? - ios

Here's the setup of a basic poker game.
PokerViewController has a subview called PokerTableView. The latter has a bunch of subviews called CardViews.
I'm trying to be a good programmer and following the basic MVC pattern. PokerTableView has a delegate and a datasource that PokerViewController implements.
I add a bunch of CardViews to the PokerTableView, and I want to move them around, so I add gesture recognizers within CardView class, and then add a delegate so each card can tell its parent (PokerTableView) that its being moved, tapped, etc.
Is this bad design?
What if CardView has subviews with delegates? Is it bad design to setup protocols in a grandparent, parent, child relationship?

There's nothing - on the face of it - that breaks the general principles of MVC here. In fact, the delegate pattern is well-known in the UIKit framework.
I think that the important thing here is to be very clear - both in your mind and in documentation - what object is responsible for what behavior and make sure those responsibilities make sense vis-a-vis the object's concept. For example, CardView objects should be responsible for things that the visual representation of a card does. PokerTableView objects should be responsible for the things that a visual representation of a poker table does. Perhaps there are model classes behind the scenes, too.

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.

Massive Parent-Child and delegate pattern

I'm facing with a complex design problem. Due to a hard designed graphic I can't use Apple navigation pattern as UINavigationController or other ones.
This is the app diagram
Black arrow: protocols direction
Blue arrow: parent-child pattern direction
I created this flow because I want to maintain the code inside the single ViewController clear and isolated: I thought about them as modules that they can be used somewhere in other apps.
The RootViewController is the MainVCs position manager. It decides which is the current view-controller that it must be showed and it configures it based on its status (modified by delegate methods).
The single MainVC doesn't know that RootVC exists and it call Root using protocols. The single ChildViewController doesn't know that its MainVC exists and it call the Main using protocols and so on.
Code is clear and much easy to understand, my purpose, but when I have to apply a modify to the skeleton (RootVC) from the ChildViewControllerN, child of the umpteenth ChildViewController, child of the umpteenth MainViewController, I have to propagate the protocol until the RootViewController.
My first question is: is this pattern correct? What do you think about it?
My second question is: is there a limit point where I haven't to use delegate pattern but something like KVO?
ADDING
I read a university lecture about the composite pattern that it says:
A composite object knows its contained components, that is, its children. Should components maintain a reference to their parent component?
Depends on application, but having these references supports the Chain of Responsibility pattern
So, according to the Chain, I can maintain a reference of the parent but I have to declare a custom interface for this kind of reference. However, doing this I will decrease the number of protocols, but the second question still be unanswered
Opinion:
When I go beyond a single level of parent/child relationships, I tend to stop using delegates and move to NSNotification. Frequently, I go directly to NSNotification to reduce dependencies. I prefer that to KVO because it is explicit, whereas KVO is harder to debug as the project progresses.
(Example: what looks like a simple variable assignment on a background thread results in a hard-to-diagnose crash if a listener is deallocated on the main thread between the moment of assignment and the KVO delivery.)

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.

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

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."

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