Related
I've been struggling to understand the best way to insert controller logic when using IB, NSObjectController sub-classes and bindings.
I need to insert controller logic between the model and the view, and I'm struggling to find an elegant way to do so. Yes, you can send actions to the file owner and handle controller logic in there, but when some core data models can extend across fifty entities or more with deep relationship structures, this starts to mount up to an incredible amount of boiler-plate code.
A very simplified example would be this; imagine you have an entity with four string attributes myTextWinter, myTextSpring, myTextSummer, myTextAutumn. You have a view which connects to this in IB via an NSObjectController. Now, say the user can select which 'Season' they wish to view by choosing Spring, Summer, Autumn, Winter from a Menu somewhere - when that season is selected, I would like to display the appropriate season's text.
In this simplified example I could probably fetch the object in the NSDocument sub-class, create a property called mySeasonText which I bind to in my view, and then check my NSUserDefaults for the appropriate season and route the requests to the appropriate attribute in the model.
The problem comes when I have fifty entities, some with relationships some two, three or more deep, each with their own set of season specific text attributes that I wish to switch between when selecting from the Season menu. Or if I have a bunch of nsarraycontrollers chained together to access objects at a deeper, and deeper level.
To date, I've been doing the following; adding a property in each of my model objects called 'mySeasonText', then grabbing the setting from my controller setting, and routing to the appropriate season. I refresh these objects whenever a new item in the menu is selected.
Whilst this works and eliminates an absolute ton of boiler-plate code, my controller logic is now in my model.
There must be a better way! Could someone please point me in the correct direction?
This is a tricky topic. Apple even mentions these challenges in its own documentation:
By using the bindings technology, you can easily create a Cocoa MVC application whose views directly observe model objects to receive notifications of state changes. However, there is a theoretical problem with this design. View objects and model objects should be the most reusable objects in an application. […] Design-wise, it's best to keep model and view objects separate from each other, because that enhances their reusability.
The design pattern you are looking for is a Mediating Controller - a way to use the cocoa-bindings classes to insert controller logic:
Mediating controllers are typically ready-made objects that you drag from the Interface Builder library. You can configure [Mediating controllers] to establish the bindings between properties of view objects and properties of the controller object, and then between those controller properties and specific properties of a model object. As a result, when users change a value displayed in a view object, the new value is automatically communicated to a model object for storage—via the mediating controller; and when a property of a model changes its value, that change is communicated to a view for display.
Here is how I like to think of them: Have you ever seen a movie or TV show where two characters need to talk, but they don't speak any of the same languages? They find someone else (or in a comedy 5 other people) who each have one language in common, and they communicate by playing a giant game of translation telephone.
Mediating controllers are kind of like that.
As your application grows they learn all the super specific rules about where to look for this one thing on this one view. This is the kind of code that an app needs to run, but you rightly feel that it is nasty when put in your model.
For several specific and detailed examples, Apple provides this amazingly detailed document: Bindings Message Flow.
For some really good discussions about this and related MVC + Bindings please see:
MVC and cocoa bindings best practices question
Why use NSObjectController?
Replacing model objects using an NSArrayController
For quite a while I've been looking at objective c examples, watching the Stanford lectures, and playing around with some code to get a hang of creating an iOS app.
However there are a few things that I can't find a good answer on:
How do I properly separate my layers? I understand the MVC structure, and I saw some examples of creating Categories for models to implement business logic. Is that the proper way, by enriching models or should I create dedicated classes (e.g. to authenticate users, extract models from json, group orders)?
How smart should views be? Can I make a view that displays a Contact (by assigning the contact property) or should I create separate properties for all of the Contact fields or should the view request it's information via a delegate call?
I'm using a Storyboard in my application. On my screen I want to
have a navigation bar, and let's say a view that displays orders. On
other screens I want to reuse the order-view.
How can I re-use the order-view's ViewController and View in other ViewControllers?
If I have 4 screens with the same look-and-feel, do I have to simply copy them in the Storyboard? This seems like a pain to main, what if I want to change my background? Or add a button to all of the views? When I create a setup-wizard I don't want to define the look-and-feel for every screen separately.
Coming from a C# background I probably have to get into the objective-c mindset :)
Any help on this would be great.
1) ObjC-Categories will easily distort your understanding of the main problem you're facing. ObjC-Categories are completely unnecessary. You could always approach these extensions by subclassing, object composition, additional methods in the actual model, or some customization in the controller or view. So if you need to format data (e.g. which is present in the model) for display in a view -- that task would often land in the controller. As far as the examples you provide: You may opt for models in simple cases -- as well, any of the examples could merit dedicated class, if complex enough or if it would keep you from redundant implementation. Note that these may be accessory classes, which simply produce a model, or they may be composites of multiple concrete of abstract classes. Not everything needs to land squarely in the definition of M-or-V-or-C. You're free to use many design patterns with ObjC. Think of MVC as the patterns Cocoa typically uses -- you will need to know them, and you will need to know how to subclass and extend these types, but these patterns lose dominance as implementations move away from Cocoa's libraries (e.g. as complexity increases).
2) They can be smart. However, under MVC, you want to focus its implementation on the view/presentation aspect. A view which represents a collection of information could in fact perform some tasks which are typically reserved for the controller -- however, you would generally cede that the implementation were a dedicated MONContactView in doing so. If you go that route, you would generally do so for easy reusability or to achieve a simple interface. Displaying information about a Contact could be very complex - In simple scenarios, these tasks are often handled by the controller. Specifically, a MONAwesomeContactView is likely less complex (e.g. in SLOC) than MONAwesomeContactViewController (unless you have some very special drawing or layout to perform). It would be more common to set the controller's contact, and let the controller push the contact data to the views' fields. Again, in the case of a very specialized subclass -- a view could very well hold its own controllers in some cases.
3a) There's nothing wrong with creating multiple instances of a class.
3b) No need to copy. When duplication is smelled, I push the implementation to actual code -- the programs can apply the look and feel you desire, or add or manipulate the subviews as you desire. Of course, they will not be present in Xcode's NIB editor. There are of course alternate approaches, but this replication often makes me move the implementation to compiled code. Achieving a good balance of both is not so difficult (personally, I do most of my views programmatically, rather than using NIBs).
This is a pretty abstract question and it's not clear what oh mean by 'layers'. Yes, you should create your own classes where appropriate, but categories also give you the option of adding functionality to existing classes. If you can be more specific with the question it'll be easier to provide a better answer.
It's a judgement call. If you want to create a view class that knows how to display an instance of your Contact type, that's fine in my book. If that view knows where Contacts are stored in the app, though, that's not so good.
Remember that the things in a storyboard are objects, not classes. You don't want to try to re-use a view from one scene in another scene -- that'd mean sharing a view between scenes, which really won't work. If you want to use the same order-view in several places, that'd be a good candidate for creating a class. On the other hand, you can set up your storyboard so that several different scenes all transition to the same scene. If you want different parts of your app to modally display a scene that displays an order, for example, you can do that.
I am a little confused as to .. well simply put.. how MVC is completely object oriented?
I know from working with a lot of java and c# that OOP that objects have states and behaviors.
I find that I am separating object actions, and placing them all in my controller rather than keeping them in one implementation (along with the View is where I am most tempted, but obviously you cannot do this).
For example, say I have a balloon object..
Its model holds its state such as its color, location, speed that it moves on screen, direction it moves, etc..
However, if I attempt to put any actions like
-(void)moveBalloon:(CGPoint)destination
this is generally unaccepted in the model because the model only holds data about the object, and the view only draws the object and cannot know about its location, etc.
Maybe I'm thinking about this in an odd way.. I generally think of BalloonView as a separate object from BalloonModel, and the controller as its own object.
Is my thinking completely wrong here?
Also.. In terms of reusability, if I wanted to give this object to someone else to use in their app, I would give them the BalloonView and BalloonModel, but they wouldn't have access to any actions that I've already implemented as part of the Balloon object because they're in the controller.
MVC is all about separating your business logic (the model) from your user interface (views and controllers). On its own, MVC has little to do with Object-Oriented (OO) programming. You could easily write software that follows an MVC design strategy without following an OO strategy.
The core of a program is its business logic. In your balloon example, the model should definitely have a moveBalloon: method if moving balloons is something that your program needs to do. To put it another way, Model code should be capable of doing everything that your program needs to do. It should store program state, handle data, and anything else related to the inner workings of the software. Views should be actual UI elements (windows, buttons, text fields, graphics, etc.) They should usually be "dumb" (i.e. with no business logic built into them). Controllers should handle the inner workings of your UI.
If the user is expected to move that balloon around with the mouse, then a Controller and a View would usually handle all of the clicking and dragging and moving around, while the Model would handle only the pure logic portion: the position of the balloon.
You are partially right. By distributing your balloon into MVC parts you cannot easily hand over view and model and controller. Nevertheless, don't worry, you will see, you still can have a reusable balloon even with MVC. But you need a bit to change your view.
You develop your balloon to run in a MVC application the same way you always do. Give it some setters and getters and call it BalloonView. The balloon only hosts the data that is given to it using these setters.
Then you decide what data is necessary to run the balloon. May be the balloon location. Create the BalloonModel and give it the location properties. In your MVC application the data might be stored in the model tier. Another user of your balloon (another application) may store the data right in the main class or even set up static data while setting up the object. It's up to the user how he/she handles the balloon data.
The controller then connects the balloon with the application. There could be a button that triggers the controller. The controller accesses the BalloonModel, updates it with a new location. The BalloonModel change must be then in some way propagated to the BalloonView. There are different techniques how this can be accomplished. The MVC frameworks typically expect the model to dispatch events and a view mediator to connect this event and the particular view. So the view does not necessary need to know its model. But it may do. In our example, the model will dispatch an UPDATE event, a mediatator will receive that event and update the view's location properties.
Another user (application) may leave out a controller entirely by connecting a button directly with the balloon positioning:
onclick: balloonView.x += 5;
You see, even if you do not hand over model and controller, your balloonView can still be reusable.
--
MVC makes sense for applications that have a significant size. Simple applications do not need to follow MVC. This would be overkill. Larger applications need some advanced structuring to easily locate responsibilities such as: Where is the data coming from, what actions are allowed and where can I find them.
UI component developer often create a mini MVC architecture only for a particular component. Model, view and controller are then in the same directory and may be compiled into a binary (my_super_list_component.binary) and reused in other projects.
MVC and OOP:
The different parts of the MVC application communicate via events (or signals or messages). An actor (view, model, or controller) may dispatch such an event, and another actor listens to that event. This is not OOP in the sense that one object knows the other and invokes methods via a defined interface, and this is worrying you.
However, using MVC even encourages a better OOP design! Then let's have all your objects host their data and actions on their own. What connections will you need to let them play together. MVC enables you to limit the necessary connections between objects. This is one of the OOP principles. The other feature of MVC is to encapsulate the entire application responsibilities. Not using MVC requires your application logic to be distributed throughout the code which is not what OOP suggests. MVC lets you encapsulate the different parts of the application and is therefore OOP for the macro level of the application. And - we are on the OOP principles - you easily might change controller or model or view and make them reusable and extensible :D
I'm working on a multiview app for iPhone and currently have my views (VIEW) set up and their transitions (CONTROLLER?) working nicely. Now I'd like to add objects for the actual program data (MODEL).
My question is: How should I structure my data to adhere to the Model View Controller (MVC) design pattern? I know I should create separate classes to implement my data structures and that my controller classes can pass messages to them from the view, but are there any other organizational considerations I should examine? Especially those particular to Cocoa Touch, Xcode, or iOS?
Other particulars: Playback of pre-recorded and perhaps user-generated audio will also be essential. I know these are model elements, but how exactly they relate to the "V" and the "C" I'm still a bit fuzzy on. I suppose when a user action requires audio playback, the CONTROLLER should pass a message to the MODEL to ready the appropriate sounds, but where exactly should regulation of the playback live? In a "PlayerController" separate from the ViewController I imagine?
Many thanks and pardon my MVC noobery.
Caleb gives a good introduction and overview of how to think about the problem. In your particular case, here are some of the pieces you would might have given your description:
Clip (M) - Responsible for holding the actual audio data. It would know how to interpret the data and given information about it, but it wouldn't actually play anything.
Player (V) - Actually plays a clip on the speakers. Yes, that's a kind of view in MVC. Audio is just another kind of presentation. That said, you'd never call it "PlayerView" because that would suggest it were a subclass of UIView.
PlayerView (V) - A screen representation of the Player. Knows nothing about Clips.
ClipManager (C) - An object that would keep track of all the clips in the system and manage fetching them from the network, adding and removing them to caches, etc.
PlayerViewController (C) - Retrieves a Clip from the ClipManager, and coordinates a Player and a PlayerView to display and play it, as well as any other UI elements (like a "back button" or the like).
This is just an example of how you might break it down for some theoretical audio player app. There are many correct MVC ways to do it, but this is one way to think about it.
Lord John Worfin (and, I'm sure, someone before him) said: "Character is what you are in the dark." Well, a model is what an application is when nobody is looking -- it's the data and logic that defines how the app behaves regardless of how it's presented on screen.
Imagine that you decide to add a command-line interface to your application. You'd still want to use the same structures for managing your data, and your logic for sorting, sifting, and calculating based on the data should still be the same too. The code in your app that remains important/useful no matter how the user sees or interacts with the app is the model.
A model can be very simple and made up entirely of standard objects. iOS apps are often more about retrieving, storing, and displaying data than they are about crunching numbers, so it's not unusual to have a model that's just an array of dictionaries, or a hierarchy of dictionaries that's several levels deep. If you look at Core Data's NSManagedObject class, it's similar in many respects to NSMutableDictionary. So, don't be afraid to use standard objects if they're appropriate.
That said, you can certainly also create your own model objects, and that's useful if you have certain requirements that you want to enforce on your data, or if you want to be able to derive information from the data.
Beginners often wonder how each controller gets access to the model. Some folks advocate using the singleton pattern for this, mainly because it provides a single, shared, globally accessible object. I don't recommend this. Instead, have some high-level object in your app such as the app delegate create/load the model (which will likely be a graph of many individual objects) and give a pointer to the model to any view controllers that need it. If those controllers in turn create other view controllers, they can again provide a pointer to the model (or part of it) to their child controllers.
I hope that helps.
Working on a game in Objective-C/Cocoa for OS X, and I finished the prototype as much as it's worth being finished. It's a mess of code, being my first game, but everything works. I've been reading up on the best way to put things together, and MVC seems to make the most sense, but I'm a bit confused.
Where does it start? With the controller? That seems to make the most sense to me, but how is it started? In my mess of a prototype, I have everything starting from the init of the view and going from there. Would I just do the same for the controller, and put what's needed in the init? Or is there something else I can use to do this? If it's started from the init, how do I init the controller?
How would I set up the game world? I currently use two arrays, one for the world (Walls, Floors, Doors, Water, Lava, etc.), and one for the items (I'll be adding a third for characters). The map (a .plist) is loaded, and then the objects are created and added to the array it belongs to. Where do the arrays go? In the prototype, they're also part of the view, so I guess you could say I combined the two (View and Controller) together. Would there be a Map object created for each map? Would there be a Maps object that contains all of the maps?
How does it all work together? The player presses a key, which moves the character in the game. The view would be handling the input, right? Would you send that to the controller, which would check for everything (walls, monsters, etc) in the map/other arrays, and then return the result? Or would you send it to the player, which would go to the controller, which would do all of the the checks, and then return the result?
I thought I had it pretty nicely laid out in my head, but the more I think about it, the less solid my ideas become and the more confused I get. By all means do not hesitate to draw something up if you think it will get the point across more efficiently.
If you've taken the time to read all of this, thank you for your patience. From what I've gathered, most people that write code don't use any sort of design. After reading up on this, I can see why some people would avoid it, it's confusing and people seem to think it isn't worth the time. I personally think that the advantages totally outnumber the disadvantages (are there any?) and it only makes sense to keep things organized in a way that you won't have to do a total rewrite every time you want to implement a new feature. You wouldn't build a house, car, or an appliance without a design, why would you write a complex program without one?
I asked this question because I want to do it the right way, instead of hacking and half-assing my way to "victory".
You may be interested in a presentation I gave to ACCU '09 - "Adopting Model-View-Controller in Cocoa and Objective-C".
Where does it start? With the
controller? That seems to make the
most sense to me, but how is it
started?
Create a new Cocoa app project and you'll see that there's already a controller class provided by the template - it's the app delegate class. Now look in MainMenu.xib. There's an instance of the app delegate, and it's connected to the "File's Owner" object's delegate outlet. In this case the NSApplication is the File's Owner; it's the thing that wanted MainMenu to be unpacked. So this really is the delegate of the application.
That means we've got something which is a controller object, can talk to the NSApplication instance, and can have outlets to all the other objects in the XIB. That makes it a great place to set up the initial state of the application - i.e. to be the "entry point" for your app. In fact the entry point should be the -applicationDidFinishLaunching: method. That's called once the application has finished all of the stuff needed to get your app into a stable, running state - in other words Cocoa is happy that it's done what it needs to and everything else is up to you.
-applicationDidFinishLaunching: is the place where you want to create or restore the initial Model, which is the representation of the application's state (you could also think of it as representing the user's document, if that analogy is suitable for your app - document-based apps are only a little more complex than the default) and tell the View how to represent things to the user. In many apps you don't need to load the whole Model when the app has launched; for a start it can be slow and use more memory than you need, and secondly the first View probably doesn't display every single bit about the Model. So you just load the bits you need in order to show the user what's up; you're Controlling the interaction between the View and the Model.
If you need to display other information in a different View - for example if your main View is a master view and you need to show a detail editor - then when the user tells you what they want to do you need to set that up. They tell you by performing some action, which you could handle in the app delegate. You then create a new Controller to back the new View, and tell it where to get the Model information it needs. You could hold the other View objects in a separate XIB, so they're only loaded when they're needed.
How would I set up the game world? I
currently use two arrays, one for the
world (Walls, Floors, Doors, Water,
Lava, etc.), and one for the items
(I'll be adding a third for
characters). The map (a .plist) is
loaded, and then the objects are
created and added to the array it
belongs to. Where do the arrays go? In
the prototype, they're also part of
the view, so I guess you could say I
combined the two (View and Controller)
together. Would there be a Map object
created for each map? Would there be a
Maps object that contains all of the
maps?
We can work out what objects we're modeling by analysing your statement above - you may not realise it, but you've sketched out a specification :-). There's a world which contains walls, doors etc., so we know we need objects for those, and that they should belong to a World object. But we also have items and characters - how do they interact with a world? Can a place contain water and a character? If so, perhaps the world is made up of Locations, and each Location can have a wall or a door or whatever, and it can also have items and characters. Note that if I write it like this, it seems that the item belongs to the location, not the location to the item. I would say "the mat has a cat on it" rather than "the cat has a mat underneath it".
So simply think about what you want your game world to represent, and the relationships between the things in the game. This is called domain modeling, because you're describing the things in the game world rather than trying to describe things in the software world. If it helps, write down a few sentences describing the game world, and look for the verbs and nouns like I did in the last paragraph.
Now some of your nouns will become objects in the software, some will become attributes of other objects. The verbs will be actions (i.e. methods). But either way, it will be easier to think about if you consider what you're trying to model first, instead of jumping straight down to the software.
How does it all work together? The
player presses a key, which moves the
character in the game. The view would
be handling the input, right? Would
you send that to the controller, which
would check for everything (walls,
monsters, etc) in the map/other
arrays, and then return the result? Or
would you send it to the player, which
would go to the controller, which
would do all of the the checks, and
then return the result?
I like to follow the "tell, don't ask" policy, which says that you command an object to do something rather than asking it to give you the information to make the decision. That way, if the behaviour changes, you only need to modify the object being told. What this means for your example is that the View handles a keypress event (it does because they're handled by NSControl), and it tells the Controller that this event occurred. Let's say the View receives a "left arrow" keypress, and the Controller decides this means the player should move left. I would just tell the player "move left", and let the player sort out what happens when moving left means bumping into the wall or a monster.
To explain why I want to do it that way around, imagine that you add in game 1.1 the ability for the player to swim. Now the player has some ableToSwim property, so you need to change the player. If you're telling the player to move left, then you update the player to know what moving left over water means depending on whether they can swim. If instead the Controller asks the player about moving left and makes the decision, then the Controller needs to know to ask about being able to swim, and needs to know what it means near water. As does any other controller object in the game that might interact with a player, as does the controller in game for iPhone ;-).
It seems like your main confusion is how things are constructed during app start up. A lot of people get stuck on this, because it feels like something magic is going on, but let me see if I can break it down.
App is launched by user
C main() function is called
main() calls NSApplicationMain()
NSApplicationMain() load the MainMenu.nib (or another nib specified in the info.plist)
Nib loading initializes all of the objects defined in the nib (including the application delegate)
Nib loading makes all the connections defined in the nib
Nib loading calls awakeFromNib on all the objects it just created
-applicationWillFinishLaunching: is called in the application delegate.
NSApplication (or a subclass specified in the Info.plist) is initialized
-applicationDidFinishLaunching: is called in the application delegate.
Note that the application delegate is initialized BEFORE the NSApplication (sub)class. That is why application(Will|Did)FinishLaunching: takes a notification as opposed to the NSApplication it is a delegate of.
The general consequence of this is that your views are created for you via nibs, and you controllers are created as a side effect of nib launching since they tend to either be root level objects in the nibs, or the nib's File's Owners. Your model is usually created either in the application delegate or as a singleton that is lazily initialized when something first access it.
You should create a model for the the whole game. It should contain everything about the game except the GUI interaction. The views, on the other side, contain all GUI stuff without knowing anything about the game flow.
The whole point is that models and views are expected to be reusable. The model classes should play with any GUI (and maybe even the console or command line). The view classes should be able to be used with other similar-looking games. Models and views should be completely decoupled.
Then, the controller fills the gap. It reacts on user input, asks the model classes to perform a specific game move, and asks the views to show the new situation. The controller is not expected to be reusable. It's the glue which holds the game together. The controller ensures that model classes and view classes remain indenpendent and reusable.
In addition, don't try to make the design perfect from the start. Don't hesitate to refactor at any time. The faster a bad design decision gets corrected, the less evil it does. Designing everything upfront means that a bad design decisions won't be corrected at all, unless you make a perfect design upfront, which is simply improssible even with decades of experience.
Always remember the third design rule of the X Window System: "The only thing worse than generalizing from one example is generalizing from no examples at all."
For your game the model would include things like the current position of the character, the number of health points, and other values that involve the "state" of the game. It would notify the view whenever something changed so that the view could update itself. The view would simply be the code required to show everything to the user. The controller is responsible for responding to user input, and updating the model when necessary.
The controller is the central component in this, and it is what should instantiate the model and view.
When the player presses a key, the view should simply pass that command onto the controller, which decides what to do.
You are wrong that most people don't design. Perhaps most amateurs, or perhaps the people who ask the most questions online, but not anyone working on a project that is even somewhat sophisticated. Professional programmers are all experienced in software design; without it they literally would not be able to do their job (write software to do X).
Your game sounds like it is complicated enough to warrant an architecture pattern like MVC. There are some instances where a piece of software is simple enough that MVC is overkill and needlessly complicates things, but the threshold for using MVC is pretty low.
You might find this article Introduction to MVC design using C# useful. Although the example is in C#, the principle should apply.