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.
Related
I have been fiddling with this for a while but can't seem to settle on a particular answer to the dilemma. I have been building this GUI program that is organized around an MVC-style pattern, and I run into the following issue: as one may know if one is familiar with this architectural pattern, the "controller" objects are supposed to handle events generated by the "view" objects (the stuff that presents the GUI to the user) that come from user input, such as a button click.
However, in some cases, the response to clicking a button may involve in it the need to put up another view, such as a dialog box or a pane in a window, depending on just how our GUI is laid out. But when doing this, it seems "logical" to me that the controller should not have to worry about the layout of the GUI, only that it needs to put up a view like such. That is, views have context to them, and nest together, and we want the controller not to have to know about that context and nesting.
The trick is, then, how to best go about achieving that isolation - or to know if it is really "bad design" to not have it there, as the simplest and most obvious solution is to just forget it, make the view in the controller, and the controller has to know the context, and has to be changed if we rearrange the GUI. But that seems to go against principles like the "single responsibility principle" of object-oriented programming (which this program uses). It gives the controller more "reasons to change". And that's clearly not ideal if it can be avoided.
The alternative, I come up with, is to use a "view manager" that has full control over the creation of views, which knows all the context. But even here, there seems to be a more subtle leak of knowledge in that, because "which view goes with which containing view" can become ambiguous in the case that there are multiple containing views available. If a controller asks for the sub-view, but not the parent (no knowledge of that, remember?) then the view manager has a dilemma as to where to put that sub-view unless it's informed of it somehow, or else (as in the current program), the view manager only allows one view, and then returns that same view to the controller, which then has the apparent issue of potentially creating a subtle cross-talk between controllers, if the controller was designed under the assumption it would be getting a separate view just for its own use.
Is there a more elegant answer to this?
Short answer: simply, you don't.
Slightly longer answer: MVC is a presentational pattern. Meaning that it helps to handle the Presentation layer of your app.
Don't get confused by the word "Controller": they're not meant to handle business logic, but to forward UI calls to the proper services.
Controllers have to be "thin", just simple proxies (or, in extreme cases, mappers from DTO/ViewModels to proper Business Models).
Make sure all the groundwork is encapsulated and abstracted away into an UI-agnostic layer.
The UITableView can be used to create a list view if the at least the UITableViewDataSource is adopted by the relevant class. I have the below questions:
Why is it designed in such a way that based on the section and row , the controls are created through data source methods and given back to the UITableView instance. Why not provide all these information in UITableView instance with out using the UITableViewDataSource. What difference is it going to make?
EDIT1:
#hermann and #JOhn: You have mentioned that it breaks the MVC pattern. Let us assume I am creating a custom UITableView like control myself. I design it in such a way that I do not pass the data directly to the UITableView but instead I pass the relevant subviews that needs to be added in the rows and section and their relavant headers alone. I think this will not break the MVC..Am I correct? But still it has the problem that the current UITableView implementation style solves..the ability to reuse controls and images instead of bloating the memory usage.
First, doing so allows to stick on the MVC pattern. A UI object, meaning a view, should never directly communitcate with the model, wich is the business data. Plus it should not perform any business logic, which belongs to the controller.
Second, it is more flexible without the need of subclassing the UITableView object.
Third, the full concept is quite efficient from a performance and memory management point of view. Instead of loading all data upfront, that may be displied within a table, it can be fetched or calculated or whatever on a just in time "need to know now" basis.
Plus data containers, especially memory consuming once like images, can be released as soon as the data has been provided using the delegate/data source methods.
Of course, a subclass of UITableView could do the same in principle. I just doubt this would result in more maintainable code or even save any time or work resprectively.
If you don't want to stick with MVC, then feel free to subclassing the table view and hand all its data over in its init method or enable the table view subclass to load all that data from webservices or data bases or wherever it comes from.
And when you run into problems and get back to us searching for guidance, then be prepared for some nasty replies like "Why don't you stick to the established best practices or the MVC pattern?" ect.
In the event that your very table just displays some rather static values, such as if it just acts as menu for further navigation drill down etc. then this concept may look a bit rediculous. But it does not hurt either. And when it comes to more complex tasks of data providing then it certainly has its advantages.
Give it a chance. Give it a try!
For MVC you want to try to clearly separate what the model, controller, and views are responsible for doing. By allowing the view (tableview) to ask for the data from a delegate, the view can be create extremely generalized.
Using the delegate pattern, the controller can "stage" the data in anyway that is wants and then give it to tableView as the tableView needs it. The tableView doesn't care where the data comes, how it was transformed, what ADT is used, nothing. It is complete ignorant to where or what the data is. All it knows it should show this string at this location for this section and row.
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've created my first iPhone app that presents audio tracks of a similar genre in a tableview. The user can play audio tracks using ipod-like controls which streams mp3.
All of my code is in two main classes: RootViewController and CustomCell.
My RootViewControllerClass is massive. I'm assuming it is poor design to stuff almost all of my code in one class?
Initially, I thought it made sense because I only have one View Controller. To practice better coding conventions, I'd like to split up my RootViewController class into smaller, specific classes (assuming this is the correct practice?).
Here are the components of RootViewController that I plan to separate out into individual classes:
DataSource - pulls data from server; modifies and organizes the data for the tableView
TopChartsView - includes buttons in a view to modify the audio tracks(dataSource) by top rated weekly/monthly/all-time
GenreChange - includes buttons in a view to filter the dataSource by genre
AudioPlayerControls - includes buttons in a view that are similar to iPod controls
Am I organizing my classes correctly? It seems to make sense that I organize my classes by function. However, I'm having difficulty grasping how classes should interact with each other in an ideal design.
Do I use protocols and delegation to link my classes together?
Designing iOS apps is mostly about the MVC design pattern, which means that you seperate your model, view and controller. In your case I would put the DataSource logic in a seperate file or files (it's your model). This also makes it easier to reuse the same logic in another view controller in a later point. Maybe you can also subclass your UITableView if lots of code resides there.
Protocols and delegates are a great way to connect your classes and they are very frequently used in a good design. Since you don't have many viewcontrollers in your application (as far as I see), there are not very much opportunities to use them, please correct me if I'm wrong ;)
It's more about object-oriented-programming than especially about iOS and I think, you should get familiar with some concepts of OO-Design (if you really interested), but from my point of view you don't have to. To answer your questions first:
I'm assuming it is poor design to stuff almost all of my code in one class?
Some say so...
Am I organizing my classes correctly?
Hard to tell, by the information you gave.
Do I use protocols and delegation to link my classes together?
Not necessarily.
But: If your code works fine, you are the only one, who works on it, you don't plan to re-use your code as a library or by taking full classes from it (i.e. if you only plan to copy & paste), there is no need to refactoring everything just for the sake of doing it.
Even though: If you want to move forward or if you're planning to write libraries or something, it would be a good idea to learn about OO (sometimes it's even entertaining). Since you're working with objective-c this one from apple's docs could be a good start to learn.
And: If you read a bit about OO-programming and (more important) take the time and to read code of others, you'll know how and when it is useful to organize your own code.
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.