Hacker News new | past | comments | ask | show | jobs | submit login
iOS application architecture: MVVM, behaviors, singletons, subclassing (objc.io)
126 points by floriankugler on June 9, 2014 | hide | past | favorite | 35 comments



It is interesting that iOS apps suffer the same sort of runaway complexity that often plagues Rails apps, whereby the controller absorbs too much responsibility and becomes unmanageable. This is usually the collateral damage of an app growing within the overly tight conceptual confines of model/controller.

This points to a lack of developer education surrounding architecture and design. Most projects have too few abstractions, and/or a weak domain model. The Internet likes to complain about Java-style over-abstraction, but I've never seen that.

I think devs don't like to think about architecture because it implies they're not doing things well, it is highly subjective, and they don't see the benefits immediately. All of these are poor reasons.


The problem, as with rails, is that the frameworks, documentation etc. encourage this. That's how you make the cool "look ma, no code" demos work: thin model ("ideally" just a CoreData object drawn in the modeler), UI painted in IB, controller to hook it all together. But it's less than ideal, er, for non-trivial programs.

In fact, I've just recently had a junior dev. tell me that in MVC, the view was not allowed to talk to the model, instead it had to be fed pre-digested info by the controller. Hmm...


I think your junior dev shows some promise. Maybe too orthodox in his thinking or taking wrong conclusions from the right info, but at least a hopeful glimmer of understanding.

I think the upper limit of possibilities a View should have interacting with a Model for me is the point where your View and Model map 1:1 and the user is able to update the fields of the Model represented in your View. You might argue that in some cases it's better to just let the View not only read the Model and represent it but also let it change values in the Model or even create a new one.

But the decision to read / save / delete the Model should always be taken by the Controller and never be done directly by the View.

I also like to argue that there could be something between the Controller and the View that handles specific chores like input validation and creation of objects from input fields. You have the opportunity to add Objects to your Storyboards for just that reason.


Hmm..you are talking letting the view "change the values in the Model".

I thought "the view was not allowed to talk to the model, instead it had to be fed pre-digested info by the controller" made it clear that I was talking about updating the view from the model, not vice versa.

In MVC, the controller initiates changes in the model, not the view. However, the view updates itself from the model.

Whether that's good or bad is a different story, but that's how MVC is defined.


"But the decision to read / save / delete the Model should always be taken by the Controller and never be done directly by the View."

Definitely agree


You are thinking of the traditional conception of MVC, where the model notifies the views of updates and changes (i.e. they can talk to each other)

Cocoa does not use the traditional notion of MVC.

All documented here very clearly

MVC as a Compound Design Pattern: https://developer.apple.com/library/ios/documentation/genera...

"The controller object in this compound design pattern incorporates the Mediator pattern as well as the Strategy pattern; it mediates the flow of data between model and view objects in both directions. Changes in model state are communicated to view objects through the controller objects of an application."


There's something else to architecting a Cocoa app that I want to add, mainly because I had heard this a while ago but only just recently figured out how to incorporate it. There are Cocoa programmers (my understanding is that it is mainly the O.G.'s) that make good use of class extensions and categories to split the functionality of a class into different source files.

For example, if you have a view controller handling a table view that makes use of many delegate and datasource methods, it's easy to have code spilling all over the place. But you can use extensions and categories to separate out the delegate functionality into its own set of files, and do the same for the datasource as well. If you share the header files among the files, then to the computer it all works like one big class. But to the programmer -- and this is the whole point -- the functionality is broken out into conceptual units.

What you end up with is still a "god class," but instead of being monolithic, you wind up with a god of many faces. (I'm whimsically calling it the "Brahma" pattern.) Anyway, I suggest people give it a try if they've been having trouble organizing their code.

Does anyone on here have experience organizing their Cocoa apps this way? I'd be interested in hearing your input, since I've just gotten around to looking into this myself.


I call this "expert band-aid applying skills". I think UITableViewController is one of the worst designed parts of UIKit and it's always a way to gauge how good a developer's OO skills are if they can point out the problems with it or if they're just okay with it.

If you put the delegate and datasource in a separate file at least makes your controller look a lot cleaner but still there's still so much stuff going on in them that doesn't separate well. If you feel the need to add #pragma, categories and that kind of things to make your code more manageable the underlying code violates the single responsibility principle.

I tend to not use UITableView unless I need either the performance or I am using a lot of built in stuff and there's no fancy stuff going on. Having to know up front what the height will be of a yet to be rendered cell really leads to a lot of ugly code quickly. I will not use it if I simply want to repeat some items vertically.


So, when you do use a UITableViewController or a UITableView with a UIViewController, how do you partition the code?


I try to refactor out as much code as possible. Ofcourse the protocols should be implemented separate from the Controller, that's the first step but the implemented methods themselves can be made as thin as possible as well.

For instance the height could be calculated a static function on the UITableViewCell implementation as I think that's the object that should deal with layout.

The headers and footers should be separate UIView implementations not something you build there. Methods that are associated with them then can use methods on those classes instead of inline code.

I think if the delegate / datasource classes implement a lot of methods you want to reduce them to 1-3 lines of code between the braces each so you get a complete overview of what each does within 1-2 screens of information.

You can also often reduce some plumbing code with: https://developer.apple.com/library/ios/documentation/CoreDa...


If you want it to look prettier on-screen you can just an editor with code folding and hide all the irrelevant functions.

Really, this is just a weird halfway house reminiscent of Rails' ActiveSupport::Concern. Much like that implementation, it encourages developers to address SRP by chopping the class up and calling it done. Difficulties in testing and reasoning are still in place, and the class is likely still too coupled.

If the local units are truly independent concepts, then they should be split out into their own objects. Either make smaller objects that either model the domain closer, or abstract away needless technical details. For example, any sort of serialization (web service/DB) should be hidden behind a high-level class that obscures how it's done if only to firewall the dependency itself from leaking it's conceptual garbage over the rest of your code.

This can be applied gradually with good effect. It's not an all-or-nothing proposition.


I'm completely on board with you when it comes to things like the serialization ("web service/DB") that you brought up, but I wasn't talking about that. I was specifically talking about view controllers managing table views.

If we're talking about table views and controllers, I'm not sure how to factor out the delegate and datasource in a convenient way. The delegate, in many cases, will need to know information contained by the datasource (the number of objects in a table view or table view's section, for instance).

How do you suggest it gets this information? Should it have a direct channel to the datasource? Should the controller act as an intermediary? Should it have some indirect channel to the information -- blocks or notifications or wired up in some kind of delegate relationship with the datasource? I haven't been able to find a good answer.

I actually fancy myself a bit of a nut when it comes to partitioning out my code into different objects, because I can't stand the mental overhead when one class does too many things. But I have come up with no solution that satisfies me when it comes to view controllers, because it seems like a lot of plumbing needs to be put in place. What I do know is that Apple itself, as well as several good sources on coding for Cocoa and Cocoa-Touch make extensive use of categories. I still think they can be put to good use in the situation I describe, but I'm open to alternatives.


I have experience doing something similar in a project at work.

In this project I have one reusable ViewController (among others, but this example is about this one) that had nothing but a UITableView and a search box (a UITextField for searching by text, and a segmented control that sorts/filters the data by preset values like A-Z or distance).

About halfway through this project I found myself with a controller with several if/else blocks and other weird things to stop code re-use and make the controller abstract in the sense that I could init it with whatever data object I needed and it would figure everything else out from there. This accomplished my goal of limiting code re-use but it absolutely sucked when a change had to happen. Conceptually, it was terrible to go down and find the correct "else if {}" to make my amendments to and then make sure that didn't take anything else down with it.

Then I said to heck with code re-use. I'm going to make this sucker clean and easy to find/fix/edit/create a new one. I pulled all of my UITableViewDelegate and UITableViewDataSource code into separate files depending on the data model that was necessary for this controller. I still init the Controller the same way, but now all of the searching/sorting/table actions that were horribly done earlier are in their own separate classes - specific to the model for each.

This means that I have 12 files that have a slightly similar structure - all of the numerOfRows and cellForRowAtIndexPath type methods as well as my custom search view's delegates. And yes, an earlier self would of been a little weirded out by such blatant disregard for reuse. But yesterday, when a change request came in to add another similar type view with a different API and data model it literally took me 5 minutes to subclass my XXDataSource class and hook it up to a model, and the whole thing worked perfectly. 5 minutes. I can't tell you how good it felt to not have to look through the cruft and add another "else if" check and make sure my other stuff would still work.

I hate to call it beautiful since I'm still a noob, but damn is it beautiful. My controller has 40 lines. Each XXDataSource class has about 100-150ish. I highly recommend this approach, especially when it looks like you're going to reuse a tableview-esque controller.

Now my XXNavigationBrain solution - that's a whole other topic. ;)


I think 40 lines of code for a controller is overkill. The goal is to make them manageable without sacrificing readability. In my opinion the data source and the delegates should be in the controller because it makes the code easier to read.

My average controller is between 200 and 400 lines of code. This might be a lot of code in Rails of other frameworks but I find it acceptable in Objective-C (considering it's an extremely verbose language).

To reduce the lines of code in my controllers I usually use categories or subclasses for custom views (I don't use Interface Builder). You can also make manager objects to do most of the workload and reduce the lines of code per method. I think reducing the lines of code per method is more important than reducing the lines of code overall.

Things that I configure once and don't plan to touch again I put in separate files like subclasses or categories. Things that can change or are necessary for understanding the big picture stay in the controller. And guess what? Data Sources and Delegate Methods are necessary for understanding how a UITableView works. In my case 200 to 400 lines of code (on average) seems like a good compromise.


and you'll also notice that the linked article says the same thing (that the model and view never touch each other but instead communicate through the controller)... I've always learned MVC as strict separation of model and view, but I've recently heard more and more people saying that they think they should talk.


There's no silver bullet method.

If you do MVVM on an app that is sparse on input controls or text labels it's overkill. MVVM shines where you have a lot of data going back and forth in screens combined from different models and you want to be able to test everything you see.

If you are doing an app that is much more graphical in nature and the models that feed it are not really mapping to databases or web services they gel much more natural with your UI and mixing them up with each other is no problem at all.

I enjoyed MVVM a lot in WPF especially because of the two-way binding it provided. That was in an application that managed health care records so it was very text heavy and a lot of screens were taking context from Models left and right.

We went with full MVVM for complex screens and direct Model mapping when we had a screen where you would edit just a support table, like a list of doctors or treatment types.


Traditionally(on desktop applications) the model was injected into the view, then actions(save, delete, buttons etc) were performed on the controller.

However the way Apples IBOutlet system works, makes this difficult. You link up the UI to fields on the controller.

The first significantly reduces code size.


I completely agree. Years ago when starting an iOS app I suggested a few abstractions to the other devs and got the response that 'this is not an enterprise application.' The problem is that a complex iOS application can quickly become a lot of code. It is compounded by the fact that a lot of that code ends up in the view controllers.


>This is usually the collateral damage of an app growing within the overly tight conceptual confines of model/controller.

Well, you're supposed to have a different controller for every major view.

And said controller can always delegate to some object model specific to your app.


The MVVM and other ideas in the issue are, at the core, about broadening what the definition of "model" means in an app. The authors seem to think "model" currently is just the data store of an app. But that's never been correct.

The model in MVC is the aspect of the real world that's being reflected in the app. This can and should include network communications and business logic. The architectural issues here are that people are mis-using the idea of a model.


That's just the fat model approach. It suffers from similar issues as fat controllers, whereby unrelated functionality tends to accumulate.

Why do models know how to persist themselves? Or send themselves over the network? What does that have to do with the concept they represent? It conflates technical concerns ("how do I serialize myself?") with business concerns ("am I valid?").

It doesn't help that Core Data forces you into the framework superclass antipattern: http://michaelfeathers.typepad.com/michael_feathers_blog/201...


Hi there – I wrote the MVVM article, and I see your point. There is a line to be drawn somewhere, but that's often up to the developer. However, on iOS, models tend to be very thin, through convention (typically, they're only a Core Data "managed object" and have no logic at all in them). I hope that helps clarify where the article is coming from.


Hmm... If I may say so I find that the MVVM pattern in iOS to be very cumbersome when compared to how it can be done in WPF. You essentially need another layer of indirection in iOS where you need none in WPF. That's probably why I personally haven't heard about it before in CocoaTouch land.

And I guess technically it's MVVCVM.


I'm very glad, as iOS developer, that community focus more and more on good iOS architecture. Few years back, in my impression, it was hard to find good article bout this topic, if any. I'm really happy that objc.io is clearing that path with great developers willing to share theirs experience.


Agreed. As you work with the libraries you run across many different ways of doing things, and folks often just use the last one they saw instead of working to understand the options and making a choice on purpose. I'm thinking especially of messaging patterns, event handling (especially gestures), working with the view hierarchy, etc.


I think part of the reason that most apps don't use these techniques is that there are not enough examples.

The examples that are available on SO, the apple docs, and IB generated/influenced code work great for the simple case but fall down a bit when your app grows. there are much better and simpler ways to handle some of the common patterns in large apps, for example the great thin view controllers article.

Objc.io is a fantastic resource.


Skimming the MVVM article from a web programmer perspective is really interesting because it is conceptually the same thing as introducing a "service" layer between your controller layer and your dao/repository layer.

Which is generally a good idea, and has lots of benefits, including better testability.

It's another example of how "Model" is a vastly overloaded term, to the point of being almost meaningless. Depending on who's talking, a model is: a database entity representation, a domain logic container, an everything-but-controller-logic holder, a DTO from dao to service, a message from service to controller, a command object from controller to view.


If you're enamoured with MVVM and know C# you might consider trying out Xamarin + MvvmCross [1]. I'm using it on a few projects and the code shared across platforms is (ballpark) 70-90% depending on the size of the project.

Xamarin's come out with Xamarin.Forms which looks like it could supersede MvvmCross but I gave it a shot and it's pretty immature right now. Plus its dependency injection leaves a little to be desired [2].

[1] http://www.codeproject.com/Articles/566270/

[2] Out-of-the-box it appears to have a global service locator and no constructor injection.


I prefer ReactiveUI: https://github.com/reactiveui/ReactiveUI (though you can use it together with MvvmCross)

It might be an unfair comparison as MvX is a much older project but it felt more like something cobbled together over time than something really thought out. I also really like the reactive approach - your view model describes the relationships between its properties as they change rather than have a morass of interlinked event handlers.

Paul Betts is pretty active within the portable-C# community, with multiple active projects: https://github.com/paulcbetts and has a pretty good blog, where at the moment he's going back through the RxUI docs: http://log.paulbetts.org/


Do I need still need to spend $17,091 a year to equip 3 developers with reasonably unrestricted Xamarin on 3 iOS, Android and Windows Phone? Or $8,991 if I don't care for hot fixes.


Xamarin doesn't cost anything for Windows Phone. Xamarin Indie is reasonably unrestricted, but let's just go with Business for now:

    Order Summary
    Xamarin.Android Business    999    × 3    2997.00
    Xamarin.iOS Business        999    × 3    2997.00
                                            $5,994.00
    Multiple Licenses                  10%    –599.40
                                               Total:
                                            $5,394.60


Great articles for issue 13 and the rest of the website seems interesting too (past issues included).

Would have been nice to see the actual implementation / code of the Parallax Scrolling Behavior example[0].

[0]: http://www.objc.io/issue-13/behaviors.html


This is great.

Is there something equivalent for Android?


"Instead of focusing on the historical context of where MVVM came from, let’s take a look at what a typical iOS app looks like and derive MVVM from there..."

because that would turn off the readers.


Where I come from, friends don't let friends use singletons (drugs are okay though).

Show me a singleton and I'll show you a doubleton, no wait, its a tripleton....




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: