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
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 ??
AFAIK view controller classes should be used for managing their views, IBActions, IBOutlets and other view-screen related stuff only. This means that view controller class should be as lightweight as possible, only concerning about managing its root and inner views. However, sometimes we are tempted to leave the code inside view controller class and not to move to other custom class.
Currently, I always create custom classes for models(database tables or custom objects), parser wrappers, heavy computations and for other logic that is more or less big and might be considered as a separate class. However, very frequently, I'm leaving some relative small computations, simple checking, simple download and other small code stuff inside view controller classes, because I'm lazy (and who is not?) and I'm not comfortable with having a bunch of tiny classes just because, theoretically, some several code statements does not belong to some view controller class. I understand that those tiny classes might evolve to bigger and real classes later, during other versions of an app, but however, might not.
IMHO, if you will be very concerned about the 100% pureness and cleanness you will spend more time (well, at least during initial versions of the app), but you will never know if the product will evolve or if it will be abandoned. There's always some trade-offs the developers are facing with.
It would be interesting to hear, what in-house rules do you use for designing your classes.
Two questions really that when/where you should do something which is whether you've stuck to the pattern or not.
And how
How is much less clear cut, particularly when practicality and pragmatism start getting in your face.
We tend to go for a static class for simple stuff e.g. a DateUtility class for parsing and formating dates in different formats.
And Aggregation for larger stuff, i.e. a downloader.
If you want reuse, decouple is the basic rule, so just because something was big wouldn't necessarily mean a different class.
Personally i like to have a strict class separation also if that means have a huge amount of files :(
Every object has its purpose and if i found some really generic operations i prefer create an "helper" class where encapsulate methods that cannot be specific of a context.
The really difficult step is to be strict on your decision and don't be lazy :) because by your question it's clear that you understand how it's important be rigorous on your code!
i am very new to ios development, rather i have just started work on my first app. Now my app has a home button on almost every page and behind that button the same code snippet is called to move to the home screen. This is a lot of duplicate code in every controller that has a home button. And it is just an example. There are many other scenarios like this and programmer still learning to code, i think its bad practice as any change will have to be made separately on every controller.
So my question, what are the best practices in scenarios like this when coding for ios??
One easy thing to do in this situation is to make a UIViewController subclass (MyAppMasterVC, for instance) and define your button as so:
- (IBAction)myCommonButtonAction { // code and such }
In all of your view controllers, inherit from this one instead of UIViewController (a la #interface MyNewViewController : MyAppMasterVC).
The first thing to do is to learn more about OO programming and class hierarchy, and understand how you can make a common base class for all of your similar controllers.
Software development for iOS in this sense is no different from any other software development. Simply merge your logic into some common class or function, and use that as it deems appropriate. It often turns out that you don't know what part could be common and reusable until you write multiple pieces of code, and only then you realize that it all could be one function. The process of organising existing code, cleaning it up, making it more readable and reusable is called code refactoring. There are a lot of books on refactoring that explain different design patterns, techniques and processes of making your code better. I recommend you read some of them to get a better picture.
This problem is language/platform agnostic. The term many use is 'DRY', an acronym for 'Do not Repeat Yourself'.
Here is a SO search. This should help you with the typical problems and uses, so you can better determine whether you can, when you should, and how to approach this type of problem.
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.
I have been programming with the iPhone SDK for some time now.
I have not been using Interface Builder. This scares me a little. I know that in effect I may be 'fighting the framework' but I do not see it that way.
I find it very easy to just instantiate my UITabBarController in my app delegate, instantiate a UINavigationController, then push and pop view controllers as I go.
Naturally I do not have an extensive knowledge of how to architect an app with XIB files because I have never done so, however I do know the general gist of it, having built some Mac apps in Cocoa using NIBs. So I am not completely ignorant.
My question is whether there is an increase in development time when choosing to lay out UITableViewControllers and UIViewControllers using XIBs rather than programmatically instantiating them and then setting up the ivars.
As I see it, both methods still require you to subclass the view controller for customization which will probably occur for the majority of your views. As well, there are still manual classes required for delegates, and the process of connecting outlets from within the XIB seems comparable to me from setting an ivar.
Or am I missing some other major point?
Thanks!
Code takes much longer to write to configure UIs than IB does.
Plus, you can hand off design to designers and let them tweak the UI.
In the end they both accomplish the same thing. You should use either one depending on the circumstances. Most of the time writing the code to create and position views, and especially maintaining it down the road, will take much longer than using IB. In a simple app for the iPhone though, this might not be true and you'd be just as well off creating everything in code. Basically, you should know how to do both, and pick the path that involves the clearest code and quickest development.
IB shines when you're using it to actually lay out views; even two or three views can be a real hassle to lay out and configure in code. I do tend to use it for tab bar and navigation controllers, and sometimes for subcontrollers (usually only if I think the user is very likely to use it), but that's more just because I'm already there so I find it convenient.
With this new version 3 OS they're announcing next week, I'm hoping Interface Builder gains some of the flexibility it has in Cocoa, where you can add palettes for your own classes and even build up complex non-view data structures (by using custom palettes). We'll have to see, though.
Don't worry too much, IMO Interface Builder is a little over-rated too.
It's definitely useful for getting things up and running quickly, or if you have an app with a lot of screens that are tedious to setup, but you're not missing much.
For the uses you outline just doing things in code is fine, and possibly even a little easier to understand.
Laying out views, or custom cells though... then you get into a ton of font/color/position setting that quickly explodes into a lot of code, hard to maintain and tweak. Much easier to adjust what you want in IB in those cases.