29
Jul
2008
 

Cocoa Tutorial: Windows OOP vs Cocoa MVC

by Matt Long

Encapsulate everything! Right? Or not. I was watching the Cocoa developers email list today and saw a post asking for help getting two views to communicate between one another. Having been a Windows programmer for longer than I’m willing to admit, I recognized the question as it was one that I also had when I moved to Objective-C on the Mac. I think I can ask the question more succinctly now than I could then. Better phrased it would be “I have a dialog object that I instantiated and obtained some data from the user with it. I now need to get that data out of my dialog object back into my main window object where I can do something with it. How can I get the information back into my main window from the dialog?”

In Windows, more specifically C# .NET, you would create a new window by adding a Windows Form object that you could then edit with the designer adding various controls pretty easily. But once that window was created, you now need to create an instance of it in your main window code and then provide public accessors to assign or obtain data between the two windows. The window class generated by the Windows Form template encapsulates everything for you. It certainly makes the code look clean, but it really breaks the Model View Controller paradigm so it’s no wonder Windows programmers (myself included) have a hard time shifting their way of thinking.

Disclaimer I admit up front that there is more than one way to do this. It is my hope that this post will help to clarify some things for Windows programmers who are making the transition to Cocoa.

I created a demo application in Visual Studio 2008 to see how this might work. Here is a screenshot of the application:

Multi-View Communication Windows

Multi-View Communication Windows

Take a look at the source code for the main window (view) here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public partial class Form1 : Form
{
    Panel p;
 
    public Form1()
    {
        InitializeComponent();
        p = new Panel();
        p.Show();
    }
 
    private void btnChangeText_Click(object sender, EventArgs e)
    {
        p.OutputText = this.tbInputText.Text;
    }
}

Notice that I’ve declared a Panel object. This is our secondary window (view) that we need to call into to set its text. Here is how the code is written for that class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public partial class Panel : Form
{
    public Panel()
    {
        InitializeComponent();
    }
 
    public string OutputText
    {
        set
        {
            this.tbOutputText.Text = value;
        }
    }
}

Ok, so the code is fairly easy to understand, but it demonstrates my point that the MVC model is now broken. While there really isn’t any programming logic in this example code, it’s pretty clear that the design leads you to just place your code right in the button handler rather than abstracting the logic away in a controller object.

So, you may ask, how can I do MVC in C#? Well, this is a Objective-C/Cocoa programming blog, so that’s an exercise for the glutton-for-punishment reader. Frankly, I don’t know. I know it’s possible, but there is nothing in the language that inherently leads you in that direction. I’ve read several articles online and they are terribly difficult to grok. Some of them are claiming MVC, but still miss it, so really you’re just on your own if you want to implement MVC in C#. All I have to say if you need to do so is that it’s better you than me. Good luck.

The Objective-C/Cocoa Way

In Objective-C, you must explicitly create a controller that will handle the updates between the model and view. As I’ve said elsewhere, I think that referring to the design as MVC is a bit of a misnomer if you are a visual learner. It should rather be called MCV, Model-Controller-View as the controller sits in between your model and view and delegates updates between them. If your model changes, your controller informs your view. If the user makes a change in the view, the controller updates the model. It won’t stick, but I suggest that we start calling it Model Controller View for those who are new to the concepts. But I digress.

Note: For you seasoned Cocoa programmers don’t flame me for the previous paragraph. I understand that there is much greater depth and complexity to MVC than this simple explanation lays out, but this post is intended to help those who are new to the concepts.

In the Objective-C/Cocoa world, we create a controller that we often refer to as an application delegate, or an app delegate for short. What confuses a lot of Windows programmers is that most of us learned that object oriented programming was just the way you’re supposed to do things not really paying attention to why you might want to or, maybe more importantly, why you might not want to. Don’t get me wrong, I’m not suggesting you don’t use OOP. In fact, to the contrary, I recommend it. The point is that abstracting everything for the sake of it is foolish. We should have a good reason to do what we do in code aside from, “I learned that when I was in college”, or “that’s just the way I’ve always done it.”

When you create an app delegate in Objective-C, that delegate can act as your controller for all of your models and views or you can create separate ones. It’s really up to you as the programmer. Having said that, it’s also important to remember that you can get really huge app delegate classes that are very difficult to sort through if you keep all of your code in a single app delegate class.

Some Sample Code

As a help to our new friend who was asking questions on the cocoa dev list, as well as any other “switchers” out there, I will present some code here that should help clarify the issues. If you want two views or windows to be able to communicate between each other, simply pass messages between them. Now, it isn’t in itself a bad thing to encapsulate your views in their own classes, but it is really often unnecessary. As in every language and on every platform there is more than one way to do it, so don’t read what I’m not saying. I’m not saying this is the only way. I’m saying this is a simple straight forward way that should help your understanding as well as give you the path of least resistance.

I created a simple demo application to demonstrate this. Here is a screenshot.

Multiple View Communication App

Multiple View Communication App

You can download the source for this application if you would like here: Multi-View Communication Demo App

Here is the pertinent source code. You simply need to declare your views as outlets in the app delegate header file like this:

1
2
3
4
@interface AppDelegate : NSObject {
    IBOutlet NSTextField *inputText;
    IBOutlet NSTextField *outputText;
}

And you will also need the action that will take place when the Change Text button is clicked.

1
- (IBAction)updateText:(id)sender;

Then you simply need to connect your actions and outlets to the AppDelegate object in interface builder and you are finished. It’s really that simple.

Why The Windows Way Is Bad And The Mac Way Is Good

Ok. So I’m just kidding with that sub title, so don’t get all bent out of shape if you’re a Windows pundit. I do, however, think that the C# .NET way of designing user interfaces leads people to write code that gets very messy and certainly not MVC compliant. Of course that is again up to you as the programmer to enforce, but the .NET GUI designer tool practically encourages you to break the MVC pattern. When you drag a button onto the window in the designer, and you then double click the button, it automatically takes you to the button handler code where most programmers are going to add their code. It makes sense when you’re in the middle of it to just put it there. However, it doesn’t enforce any sort of separation of presentation from business logic. You just slam it all in there whether it’s related to the GUI component you’re working on or not.

In Objective-C, it is very hard to break the MVC design pattern. You really have to work at it (it can be done, though). Even when you are dragging connections between your app delegate and your actions and outlets in Interface Builder, there is a visual representation of MVC. To connect the app delegate class (which is your controller), to your outlets such as text fields, you control-click and drag from the AppDelegate and drop onto the outlets. When you want to tell your AppDelegate to perform some action, you drag from the control that triggers the action to the AppDelegate object. When you think about it, it’s all pretty intuitive. It’s just very different than what a Windows developer is used to.

Conclusion

The transition from Windows developer to Mac developer can present a bit of a challenge, but the sooner you let go of your pre-conceived notions of how programming is done, the better. Things are done differently on the Mac. Get used to it rather than trying to change it to be what you’re used to. Let’s admit it folks, engineers are arrogant and think they know it all. When learning a new language, technology, platform, etc. we could all stand to come into it with a bit of humility. You should consider the rules you’ve always lived by as a programmer as subject to questioning. Goto is not inherently evil, you know? Until next time.

Matt Long

Matt Long works for Colorado Springs iOS Development shop, Skye Road Systems. He is the founder and principal developer there. Matt also works for a startup company called Galen Medical Systems where he develops apps for the medical industry. Contact Matt at Matt at CIMGF dot com to discuss your iOS software development needs. Matt is the co-founder of Cocoa Is My Girlfriend and is the co-author of "Core Animation: Simplified Animation Techniques for Mac and iPhone Development"

More Posts - Website

Follow Me:
Twitter

Comments

[...] Cocoa Is My Girlfriend: “Encapsulate everything! Right? Or not.” [...]

iamleeg says:

So, you may ask, how can I do MVC in C#? Well, this is a Objective-C/Cocoa programming blog, so that’s an exercise for the glutton-for-punishment reader. Frankly, I don’t know. I know it’s possible, but there is nothing in the language that inherently leads you in that direction. I think what you could adopt in the example you give (and hence elsewhere, probably) is the Mediator pattern from the GoF; specifically look at an architectural pattern called Model-View-ViewModel. Your ViewModel class works in a similar way to the Controller in Cocoa (which actually isn’t an MVC controller at all – NeXT seem to have hijacked the word back in the 1980s).

I should point out though that my experience of C# is not that great, and I’ve recently been using Cocoa# anyway (and writing Cocoa-style model and controller objects as a result). Google brings up some good M-V-VM results after a search for “ViewModel”, including some which compare it with traditional SmallTalk MVC.

Cheers, Graham.

SHatfield says:

Long time reader, first time poster :-)

In this article you talk about the MVC pattern, but you never explain why it is better than just placing code under buttons in the views (forms for Windows users).

As you state in the article, the .NET UI practically begs you not to use the MVC pattern, and so to some Windows developers who have now started to look at the Mac, the MVC pattern might actually be a foreign concept entirely!

So what is the answer to “Why is MVC important?”

It is because it allows the views to vary while giving them a single point of reference to code that provides (and maybe updates) their data.

Say for instance that you have an application that provides views that allow the data to be edited, but has security built in so that certain users can only view the data.

In the Windows world where the developer hasn’t used MVC, you would have to set the visible property of the Save buttons to false. Easy… but limiting. What if the controls in the views could be arranged so that they provide for better legibility to the “read only” user? What if a lot of controls in the forms need to be hidden because they are only relevant to users who can edit the data?

Without MVC, you are stuck writing a lot of code to move/resize or hide controls on your forms. Not fun!

In the MVC compliant application you can replace your views entirely with views that are designed with legibility in mind, while simply reusing the controller to get the data from your data source.

I hope this helps any other Windows developers who have started to look at the Mac as a development platform.

Best, Steven

Chris Snazell says:

With apologies, as a hoary old Smalltalk coder this is a hobby horse of mine …

MVC is essentially a data-management pattern – the view is a pool of data pulled from the model and manipulated by the controller. The view is so-called because it’s a window onto the content of the model.

In more complicated scenarios you have multiple view + controller pairs, each targeted at a particular category or subset of data in the model and servicing a particular aspect of the display. Typically in these scenarios the view + controller is merged into a single object that performs both duties. Let’s call it a view-controller.

Classically the MVC is always presented in relation to user-interfaces but the UI is never shown in the diagram and this leads people into assuming the view is the UI. Writing an MVC-based application is relatively trivial once you realise the UI is not the view.

In .NET terms, the data displayed on the form is bound to the appropriate properties of the appropriate view-controller and the event processing code-behinds call the methods exposed by the same view-controller. To provide easy access to the view-controller the coder can instantiate them in the application object’s constructor at start-up and expose them as properties. In this way the forms can always bind / call the required view-controller.

The majority of coders haven’t been exposed to the ‘full on’ object-oriented coding experience of using a language like Smalltalk, Objective-C or Ruby. They don’t ‘think in objects’ so MVC seems like witchcraft.

Ross says:

Thanks for this explanation, Matt. Before becoming obsessed with Cocoa, I had dabbled with other languages and platforms and none of them held my interest for very long. When I was about halfway through the Hillegass book, the Cocoa paradigms–MVC, target-action, view hierarchy, responder chain, and so on–suddenly made wonderful sense. I put the book down and started writing apps.

Your article explains exactly why Cocoa dev is so enjoyable. It’s not so much about learning how to do this and how to do that; it’s about understanding the paradigms. I constantly marvel at them; there’s a kind of elegance about the Cocoa way of doing things that makes coding a pleasure.

Matt Long says:

@SHatfield

I agree with you. I think I will also provide the why of MVC. Rather than try posting it here in the comments, though, I think I’ll do a follow up post. Thanks for the insight. It’s appreciated.

-Matt

warren416 says:

What if you’re like me: Poised on the brink of all this stuff, and unable to drink the MVC kool-aid?

Are there any short-cuts to enlightenment? I’m unconvinced that MVC makes your code better.

W

Matt Long says:

@warren416

It’s perfectly fine to remain unconvinced that it makes you a better programmer, but you won’t be able to do Cocoa development unless you do drink it in. ;-)

You have to decide whether or not you want to be a Cocoa developer. If the answer is yes, then buy the Hillegasse book and get going. No shortcuts–just diligence.

Best regards,

-Matt

[...] Cocoa Tutorial: Windows OOP vs Cocoa MVC How .Net object encapsulation differs from Cocoa. (tags: cocoa programming) [...]

[...] Cocoa Is My Girlfriend > Cocoa Tutorial: Windows OOP vs Cocoa MVC – An explanation of Cocoa’s MVC architecture for Windows Forms switchers. [...]

twidle-de says:

When trying to understand MVC, one should understand that there are many different flavors of MVC in use. I would argue that .Net uses a version of MVC, but the variant is that it uses what is called a “heavy component” approach. This approach means that the Model remains separate, but the controller and view are mashed together in the same class (thus giving this class it’s heavy weight). Java’s Swing library follows the same paradigm when it comes to MVC. I’m not saying this is a great way of doing MVC, but it is common enough that a good programmer should know of this version.

What is known as “True MVC” is the approach where the model and view and as dumb as can be, and the controller is the mediator through which all business logic processing happens. Cocoa follows close to this “True MVC” approach, however, Cocoa adds a little bit more flexibility through the delegation mentioned in this post, as well as the key value observing system, which makes it easy to link together complex views and do notifications of a change in data application wide.

nevyn says:

Cocoa’s version of MVC gives your user interface malleability like no other. Because your code isn’t in the view, you can edit the UI and the code completely separately. Delete an editfield, replace it with a slider, drag the outlet, done, you don’t need to change a line of code. (Whereas with the Form Editor, you’d have to save the handler code, delete the field, put in the slider, make a new handler, paste the old handler code, and adapt it to match the new control).

I would even say that Interface Builder + properly Cocoa MVC’d code gives you easier and greater UI malleability than HTML + well-written Javascript.

(Why am I harping on about UI malleability? Because the UI is your app’s most important aspect, and thus the UI has to be reiterated many times and evolve far before you get it right)

kickabit says:

Having switched between Windows and Cocoa development for the last couple years I have to agree that Cocoa is a far better framework for developing applications. To me Cocoa provides a really clean application framework. .Net on the other hand gives you a mess? Actually I’d label .Net as a component framework. There’s really not much baked into .Net to help you build apps quickly. I know people will disagree with that assessment, but I always find myself writing a lot of glue code to get an application up and running the way I want it. That’s not the case when I write a Cocoa app. If you look at application frameworks like Cocoa or even Ruby on Rails, all that glue code is baked into the framework. All you have to worry about is extending the functionality.

All that said I have built .Net apps that are like Cocoa apps using MVC. As you can see by the following example it’s not nearly as straight forward as developing in Cocoa, but it does mimic the Cocoa app above. What I really find interesting is both frameworks provide a very similar set of functionality, but the focus on how applications should be built is completely different.

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms;

namespace MVCSharp { public class FormInput : Form {

    public Controller controller = null;
    private TextBox textBox = new TextBox();
    private Button updateButton = new Button();

    public FormInput() {
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.Text = "FormInput";
        this.Padding = new Padding(10);
    }

    public void Initialize() {
        controller.ClientConnected++;

        textBox.Multiline = true;
        textBox.Dock = DockStyle.Fill;
        this.Controls.Add(textBox);

        updateButton.Dock = DockStyle.Bottom;
        updateButton.Click += new EventHandler(controller.updateText);
        updateButton.Text = "Update Text";
        this.Controls.Add(updateButton);

        textBox.DataBindings.Add(new Binding("Text", controller, "InputText"));
    }

    protected override void OnClosed(EventArgs e) {
        base.OnClosed(e);
        controller.ClientConnected--;
    }
}

public class FormOutput : Form {

    public Controller controller = null;
    private TextBox textBoxEcho = new TextBox();

    public FormOutput() {
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.Text = "FormOutput";
        this.Padding = new Padding(10);
    }

    public void Initialize() {
        controller.ClientConnected++;

        textBoxEcho.Multiline = true;
        textBoxEcho.ReadOnly = true;
        textBoxEcho.Dock = DockStyle.Fill;
        this.Controls.Add(textBoxEcho);

        textBoxEcho.DataBindings.Add(new Binding("Text", controller, "OutputText"));
    }

    protected override void OnClosed(EventArgs e) {
        base.OnClosed(e);
        controller.ClientConnected--;
    }
}

public class Model {
    public string inputText;
    public string outputText;
}

public class Controller {

    private Model _model = new Model();
    public int ClientConnected = 0;

    public void Initialize() {
        _model.inputText = "";
        _model.outputText = "";
    }

    public void updateText(object o, EventArgs e) {
        _model.outputText = _model.inputText;
        OnOutputTextChanged(new EventArgs());
    }

    public string InputText {
        get { return _model.inputText; }
        set { _model.inputText = value; }
    }

    public string OutputText {
        get { return _model.outputText; }
        set { _model.outputText = value; }
    }
    public event System.EventHandler OutputTextChanged;
    protected virtual void OnOutputTextChanged(System.EventArgs e) {
        if (null != OutputTextChanged) {
            OutputTextChanged(this, e);
        }
    }
}

static class Program {
    /// 
    /// The main entry point for the application.
    /// 
    [STAThread]
    static void Main() {

        Controller controller = new Controller();
        controller.Initialize();

        FormOutput viewOutput = new FormOutput();
        viewOutput.controller = controller;
        viewOutput.Initialize();
        viewOutput.Show();

        FormInput viewInput = new FormInput();
        viewInput.controller = controller;
        viewInput.Initialize();
        viewInput.Show();

        while (controller.ClientConnected > 0) {
            Application.DoEvents();
        }

        Application.Exit();
    }
}

}

[...] Cocoa Is My Girlfriend » Cocoa Tutorial: Windows OOP vs Cocoa MVC [...]

[...] Tutorial: Windows OOP vs Cocoa MVC Cocoa Tutorial: Windows OOP vs Cocoa MVC: “Encapsulate everything! Right? Or not. I was watching the Cocoa developers email list today [...]

btmac says:

Thanks for the quick walk through of the differences…. I’ve used VS and Flex 3 builder to build my apps and just started to look at cocoa. I’ve been scratching my head for the past couple of days… guess I’ve got the windows mindset ingrained… wished I had a format button to reset my thinking to make understanding cocoa and objective-c better.

[...] is My Girlfriend has a good article discussing some of the differenences between the way .NET encourages you to write code and the way [...]

brg666 says:

I’m not going to win any friends here, but i believe the partial class stuff that c# uses could be thought of as the controller part.

All the GUI is designed in a different code file (in vs2008 anyway) and if you stick to putting your event handlers in the partial class that vs gives to you then i think that that is separation enough.

OK its not oop mvc of course – but who cares, what i want is a separation of the form design and the event handlers – all i need to do is define a model to talk to and i’m away.

SubstanceMX says:

Hi, im a 2 or 3 months Cacao beginer (leaved ActionScript girlfriend) and what ever I read from apple the most confusing until a few days my sinapsis started and brain neurons connected just to “thing in Objetive-C” whay, as when you start solving things with something you recently adquired comprension.

Here I have a concrete problem, wich is a possibility in cacao but (as far as I can see) is not explained: work with documents and tool panels.

How can I have a document, wich contains a window and have tools in diferent panels, of course, wired with de document (or documents open that may be many).

BTW, this is one of my cacao’s guru bookmarks since a month ago and really apreciated your help a lot.