I've been working on my iphone game recently and came across a forked road when deciding the design of my various classes. So far I've adhered to the MVC pattern but the following situation had me confused:
I have 4 buttons displayed visually. Each button though consists of a container UIView (which I've subclassed) and 2 UIButtons (also subclassed) as subviews. When you press a button, it does the flip effect plus other stuff. The user input is using target-action from my container UIView to my controller. This part is ok, the following part is the debatable part:
So I've subclassed the container view as well as the UIButtons and I need to add more data/methods (somewhere) to do more things. Putting data that needs to be serialized and non-rendering related code in the view classes seems to break the MVC design but at the moment, it makes the most sense to me to put it there. It's almost like my subclassed views are their own little MVC's and it seems neat. Separating out the data/methods from the view to my main controller in this case seems unnecessary and a more work. How should I be doing it?
Thanks heaps.
The MVC pattern is quite useful because it lets you reuse at least 2 parts of the MVC model (usually the model and the view) so usually, the best way to write clean code is avoid the use of inheritance and use instead delegation (based in protocols) and dependency injection (for the services) so you can generate unit tests for your systems and a better way to upgrade the develop of code
Here are some interesting articles:
when would I use the delegation pattern instead of inheritence to extend a class's behavior?
Inheritance is evil, and must be destroyed
Dependency Injection
Related
Having used storyboards for a while now I have found them extremely useful however, they do have some limitations or at least unnatural ways of doing things. While it seems like a single storyboard should be used for your app, when you get to even a moderately sized application this presents several problems.
Working within teams is made more difficult as conflicts in Storyboards can be problematic to resolve (any tips with this would also be welcome)
The storyboard itself can become quite cluttered and unmanageable.
So my question is what are the best practices of use?
I have considered using a hybrid approach having logical tasks being split into separate storyboards, however this results in the UX flow being split between the code and the storyboard. To me this feels like the best way to create reusable actions such as login actions etc.
Also should I still consider a place for Xibs? This article has quite a good overview of many of the issues and it proposes that for scenes that only have one screen, xibs should be used in this case. Again this feels unusual to me with Apples support for instantiating unconnected scenes from a storyboard it would suggest that xibs won't have a place in the future but I could be wrong.
You are correct, breaking up the storyboards is the best way to go. Decomposition does more than just make parts of the UI more reusable. It also makes using storyboards in a team more manageable.
Lately, many of my storyboards have contained four or less scenes. It is easy enough for one person to solely build and maintain one or more of such UI modules. This practice reduces or eliminates merge conflicts.
In the case I do need something changed in a storyboard owned by someone else, I ask the owner first if he or she has any local changes. If so, I sometimes have the owner add the changes for me. Decomposition still requires some coordination, but it is substantially less than a full-app storyboard. Ever since I started this practice, I haven't had any merge difficulties.
As for XIBs, I don't think I wrote enough about them in my article. They are still very useful. They can be nice for single view controllers. However, this is not where they truly shine. XIBs have one advantage that storyboards may never have. The most basic unit of a XIB is a UIView, whereas the basic unit of a storyboard is a UIViewController. Since XIBs can hold collections of UIViews, they are great for visually creating custom controls. In a XIB, I can visually build a rotary dial or a GPS widget. Then I can drop these controls and widgets into storyboards or other XIBs. Such XIBs are seen more often in iPad apps since they have larger screens capable of holding many controls and widgets. It would be unnatural to build a UISwitch within in a UIViewController in a storyboard.
Now for the best news. It is possible to connect storyboards within Interface Builder and without writing any code. I was planning on releasing this technique after WWDC, since Apple may release similar functionality in iOS 6. However, since you asked, I decided to release it now. Rather than duplicate my explanations on how RBStoryboardLink works, you can find more details on my blog and on GitHub. This will make your UIStoryboard experiences much more enjoyable.
I found this article mentioned a lot of issues when using StoryBoard, one thing the author raised is using a huge of nib files in one StoryBoard, which I agreed he shouldn't do that, but there was other issues such as:
My root view controller has become a source view controller for lot of
segues and therefore its prepareForSegue: has become a stupidly large
method filled with a lot of “if (segue.identifier
isEqualToString:#”…”)” statements in a row
and
It is possible to assign view controllers in a storyboard an
identifier. Unfortunately this identifier property is not exposed in
the UIViewController class. This makes it very hard to perform safe
introspection of the view controller hierarchy at runtime. It would be
really nice if identifier was exposed for view controllers as well as
for segues.
and ...more other issues, I thought it does make sense, and I'm worry whether should or shouldn't use StoryBoard for now ??
I'm still quite new to Cocoa and Objective-C (<1 year). My App now has some 50+ classes, but some of the ViewControllers get quite crowded with code, like 700 lines or more.
My question is: is it fine to have a "large" ViewController or are there patterns for splitting up code into fractions? A lots of the code is implementing delegate methods, thats why I don't have an idea how to move it away.
I know, I can structurize with pragma marks though.
Thanks for any input.
EDIT (Dec 2013): there is a great article from Chris Eidhof of objc.io regarding this subject. He also talked about that subject on Macoun 2013/Frankfurt. Separating out the UITableView protocols are a great pattern.
EDIT2 There are also 2 videos on NSScreencast explaining concepts of refactoring ViewController (episode #102 and #103).
One of the most common causes of large view controllers that I have seen, is lack of separation b/w Model and Controller in MVC architecture. In other words, are you handling your data in your view controllers?
If yes, rip out the model component from VC and put it into separate class. This will also force your thinking towards a better design.
For reference, In View Controller:
Handling of all changes in the UIView and the UI elements contained within.
All animation, transitions and CALayer operations.
In Model:
All processing of data, including sorting, conversion, storage, etc.
IMHO, 700 lines is not (yet) huge for iOS code, I've seen and handled much worse. Of course, if all your VCs are this big, you have a problem.
You should definitely use and abuse #pragma mark, it's very useful under Xcode at least.
Then if you find you got too much code in one file, you can extract functionality to classes or categories, as better fits.
Creating classes can be very rewarding in the long term to manage recurring tasks in projects (ie connecting to webservice, parsing XML/JSON, interacting with SQLlite, logging, etc...). If you are doing recurrent iOS programming, you can create a 'common' library of useful code that way.
Creating categories, especially on UIViewController can help reducing boilerplate code that takes a lot of place. You can (and probably should) also create a common base UIViewController for your app, that will handle stuff like rotation, maybe logging, navigation, etc... in a centralized part of the code.
You should try to identify what your ViewController is really doing.
If you can separate some concerns you can move them to classes of their own. Find out which properties and ivars are used by the viewControllers methods. If you can find a subset of functions, that use a common subset of ivars/properties, these together are very likely to become a class of their own. The controller would then own such a new class and delegate work to this.
If your ViewController is managing some sort of state, eg. you find the same switch statement or if-chain in 2 or more methods the STATE pattern could make your VC much more readable. But basically you could use any pattern that helps to reduce the VCs responsibilities.
IMHO the ViewController is the place were you would connect the model to the views. Propagating model changes into views and handling user interaction with the views are the only things, that should happen there. All other responsibilities, like calculation, network transfer, parsing, validation... should happen in different classes the VC uses.
You might like the book Clean Code by Robert C. Martin. He explores in depth how code could be structured to increase it's readability and reusability.
You can distribute the code using categories depending on the functionality. Refer http://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/Category.html
Prefer the use of NSObject class to manage part of your view controller functions. Main reasons code is more clear and easier to debug
Say I want to create my view controller class with 2 superclasses; UIViewController and UIView.
is this possible? or is there another way of getting round this?
Multiple inheritance is not supported by Objective-C (hopefully, because multiple inheritance is generally synonym of bad design and also lead to potential complex problems like the diamond problem).
Use protocols instead if you need the concept of "common programming interface" (common API for multiple classes)
Note anyway that making a ViewController inherit UIView is nonsense anyway as this is not the same objects at all and in separate parts of the MVC pattern. (UIViewController being in the "Controller" part, probably holding behavior stuff, whereas UIView is the "View" part and not the Controller part, and only have to manage the display/visible representation of your stuff).
There is obviously some misunderstanding of the MVC pattern (omnipresent in Cocoa framework) and I suggest you take some time to read more about MVC. This may not be straightforward at the beginning if you are new to OOP but this is worth understanding as it would be easier for you once you understand it fully.
No multiple inheritance in Obj C. However you can achieve your goals using Protocols, composition and message forwarding. And might I add, just searching for the above 3 keywords in Apple's dev documentation pages is an excellent way to learn and get started.
One of the tasks of a view controller is to carry enough state so that the view can be released and rebuilt to handle low memory situations. So it is a likely a bad idea.
In general, the iOS framework uses delegates as a neat way to combine the behavior of 2 superclasses: you subclass one (or both) and have an instance of the other class as member variable. Neat and simple and probably a better design anyway.
Thank you for reading this.
These are my first steps in the iPhone Ipad app programming.
In order to learn from scratch (and because I know my app would need dynamic views), I decided not to use Interface Builder.
My question is(regarding the fact that I don't use IB): how would one use Views and Controllers?
I think I understand the MVC concept as it is repeated over and over again in the tutorials I follow, but after the "MVC explanation" part, nothing is made to make it clear "on the field" and closer to the real world (Earth being Xcode here).
Worse, sometimes it seems that some tutorials mix these two concepts up and use one word to say the other.
I read around here a lot of questions (and answers of course) based on the matter but I still don't get it. Sometimes it's too generic, sometimes it's too specific (for me at least).
For what I think I understood, the UIView is the static View when the View Controller is the logic which links the View to the data and those 3 concepts must be separated.
This separation, while a bit clearer with the use of Interface Builder seems to get quite blurry when you code everything as it becomes a virtual soup.
Technically, should I create a specific ".h" and ".m" file for each View AND ALSO for each associated Controller?
If I understand the MVC pattern, it's seems that I should but when I follow tutorials (without IB) it is never the case, view and controllers are created and manipulated within the same implementation files.
Any high level (I'm a noob, don't forget) but still applicable explanation of the use and best practices?
Let's say I want to create a simple app with a green view I can swipe to get to a red view.
I know for sure that I would need at least an:
xxxappDelegate.h
xxxappDelegate.m
xxxView.h
xxxView.m
What else?
1)Where should I put the the second view (along with the first one in "xxxView" or should I create another class h and m file?)?
2) What would the controller(s) do, for that kind of application? In which files would they be created and in which files would they be invoked and how would they "control" the related view?
3) Mainly, regarding to MVC pattern and the fact that there would be no IB, how would you organize that app?
I know it's a lot if you go into the details and code but that's not the point here.
Thank you. This - as simple as it seems - would be of a great help and is not as easily found in tutorials as you might think.
I understand the tutorials I read but they are so particular. As soon as I try to create something on my own which is not a "Hello World" screen, I realize that something is missing, logic wise.
Thank you very much for your help.
Sorry, but I can't get past your first paragraph. If you don't use Interface Builder, you are not going to be a successful iOS programmer. It's that simple. The best advice I've ever read about this is in this Aaron Hillegass interview:
Experienced Cocoa programmers put a lot of the smarts of their application in the NIB file. As a result, their project has a lot less code. Programmers who have spent a few years working in Visual Studio get freaked out. They ask me stuff like, "Can I write Cocoa apps without using Interface Builder? I like to see the code. Maybe I can just explicitly create my windows and the views that go on it?"
It is difficult to explain how the NIB file (and a few other scary ideas) create leverage. It is that leverage that enables one guy in his basement to compete with a team of engineers at Microsoft or Adobe. It is like I showed a chain saw to a early American colonist, and he said, "Can I cut down the tree without starting the engine? I don't like the noise. Maybe I can just bang it against the tree?"
Yes, it's hard to generalize after reading specific tutorials, but you will learn. I thought the learning curve was insurmountable when I first started, but if I can become a programmer that gets paid to write Cocoa software, you can too. Just keep reading and practicing. Don't fight the tools--use them.
Early:
In order to learn from scratch (and because I know my app would need
dynamic views), I decided not to use Interface Builder.
Later:
As soon as I try to create something on my own which is not a "Hello
World" screen, I realize that something is missing, logic wise.
I think what is missing logic wise is that you have accepted your assumption that Interface Builder was a crutch and that to learn "from scratch" you had to avoid using it. You are trying to learn the MVC design pattern but you are not willing to use the tools that have been designed to support it.
In Apple's own documentation they discuss the fact that sometimes there is value in having combined roles—Model Controllers and View Controllers—and that is worth reading, as it may explain some of the code examples you're reviewing. But my primary advice would be: before assuming you know better than the people who built the tools, trying using them the way they recommend. It might be an eye-opener.
Additions later:
OK, so to try and actually answer your questions...
1)Where should I put the the second view (along with the first one in
"xxxView" or should I create another class h and m file?)?
If I am understanding correctly and the two views you are thinking of here are the red and the blue displays to the user, you wouldn't have a second view—what you would do, whether in IB or in code—is to have an element in your view on which you changed a colour property... This would be done programmatically whether you were setting up the parent view in IB or in code.
2) What would the controller(s) do, for that kind of application? In
which files would they be created and in which files would they be
invoked and how would they "control" the related view?
There would be a view controller that would implement the gesture support, and would provide a method for changing the colour of the item in the view between blue and red when that swipe gesture was successfully received. I would have a ViewController.h and and ViewController.m. I think if you were implementing the View entirely in code, it would be implemented in the ViewController.m rather than having a separate View.m. (If you were using IB, you would have a ViewController.h, ViewController.m and ViewController.xib, with the latter providing the basic setup of the view elements and layers.)
You would create a ViewController instance in your AppDelegate.
3) Mainly, regarding to MVC pattern and the fact that there would be
no IB, how would you organize that app?
As above.
If you really insist on going without IB (and I agree 100% with SSteve) then in addition to the files you list you will also want to use a UIViewController. Now, it is important to know that you only need to create header and implementation files when you are adding or changing default behavior.
In you case, the view can probably just be a generic UIView, so you wouldn't need the files. What you would do is subclass UIViewController, and put the swipe logic there. In the swipe logic code you would probably just change the background color of the view.
You would instantiate the view controller in the delegate (in this case anyway) and create the view in the view controller's loadView method. That is required since you won't be using IB.
Personally though, I think that IB does a great job of encouraging proper MVC patterns, and if you are just starting then you should go with IB.
In practice you mostly do not make classes for views, unless they need to do custom drawing or display.
For lightweight configuration of views, that is often done in the viewController's viewDidLoad (or I guess in your case loadView) method.
Yes it's a good idea to keep model and view separated, but that's also balanced with the equally good idea to reduce the amount of code that exists. The less code that is written, the fewer bugs you will have.
Since you are just starting out at this point I would absolutely start by using ARC, and using IB - even though I'm sure you're tired of hearing that from everyone, I'll give you an alternate take. Less code means fewer bugs. And the fact that so many experienced developers are telling you to use it should be a giant clue about what a productive path forward is. I mean, are you doing this to build applications or learn every corner of the UIView class?
To speak to your code example, you do not need the UIView custom class. Just create use a UIViewController's main view as a container view, place a UIView inside with the background set to red. On swipe (using a gesture recognizer attached to the container view) call the UIVew method to swap in a new green-background UIView for the existing red view, you can even define the transition style.
Or create a scroll view in the container view, set up the red and green view inside the scroll view, set the content size and enable paging on the scrollview.
Or create a custom UIView class as you had, listen for touch events and slowly adjust two subview positions to follow the drag action.
Or use an OpenGL backed view, and based on the gesture recognizer pan the scene you are observing with two triangles for a green rectangle and two triangles for a red rectangle.
Sticking to Apple's guidelines, I create one subclass of UIViewController per screen of my iPhone application. However I consistently find that these classes become very large, both in terms of sheer lines of code and number of member variables.
By definition they end up being responsible for quite a number of different concerns (e.g. view life cycle, mediating between views and models, sometimes touch handling, control logic, managing alerts and other UI state).
Not only does this violate the Single Responsibility Principle but it also results in large swathes of code which are near impossible to unit test.
What responsibilities/concerns do you tend to divide off into new classes? What kinds of responsibilities do you think make good candidates for clean separation in the case of UIViewController subclasses?
This is an interesting question and I also struggle on how to properly separate responsibility. It all depends on the context but since testing subclasses of UIVieController can be a pain I try to move as much as I can into model classes. In the spirit of Skinny Controller, Fat Model.
When it comes to tables I have created a base model class for handling all the table view stuff, basically encapsulating what you get when you create a new Navigation Based Core Data project. The in the controller I just forwards the calls to my table model.
I'm trying to keep the methods of the controller as small as possible. Depending on the context I may have several model classes, each responsible for a specific part.
I have also looked into the possibility of using controller factories for getting detail controllers for certain data models.
UIViewController *detailController = [self.controllerFactory controllerForItem:item];
[self presentModalViewController:detailController animated:YES];
This way I can unit test that I get the proper controller for a specific data item without having to involve the parent controller.
With mine, I'm creating categories, abstract parents and using a variety of patterns I've learned in the Java world to reduce complexity and code duplication. But when it comes down to it, I still have one view controller per screen because every screen has at least one thing on it thats unique in some way. There just might not be much code left in the controllers thanks to the infrastructure I've placed around them.