I have been endeavoring to wrap my head around building larger apps using the recommended MVC approach that most of the apple docs and various tutorials seem to embrace. That is, nested controllers each holding their own view, and while I 'get it', I don't necessarily like it -- in my particular app, I have a view (and controller) hierarchy that's now several classes deep. For example, a main controller/view -> sidebar -> upper half of sidebar (NSSplitView in an NSView) -> NSTableView.
I've been playing with passing the data/objects I need up and down this hierarchy, but it's getting kind of messy and seems to be leading me down a tight-coupling road I don't like very much, passing lots of things in the init methods for each controller -- for instance a data model.
I've also played with an idea a friend suggested, a singleton service. Essentially, it's a wrapper around whatever data model or 'thing' my controllers might need, in my case an EKEventStore that surfaces an NSArray property and emits notifications (on the main thread). So far this approach seems to be leading me down the road of much cleaner code, and certainly makes unit testing easier (I think), but I'm wondering if I'm way off with my approach.
Has anyone taken this approach before with large apps? Are there any pitfalls or land mines I'm about to stumble on? I realize a lot of this is style/preference, but I'm curious if I'm headed down a bad path.
Is your singleton just holding collections of objects to use or is it also holding mutable global state? For object instantiation and easy testing you should take a look at a DI implementation like Objection. For test mocking check out OCMock.
Using Objection, you can inject a DataModelService into any controller that needs access to the data model for example.
Related
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.
Fairly early on in my app, when I was a lot less experienced than I am now, I wanted to spice up some transitions between view controllers with my own custom animations. Having no idea where to start, I looked around SO for a pattern like MVC that could be accessed from nearly any controller at any time, and as it turns out, a singleton was the way to go.
What I didn't realize is that there seems to be a strong and well-defended hatred of the singleton pattern, and I myself am starting to see why, but that is beside the point.
So, a while later, I decided to move my very same implementation into a category on UINavigationController (after all, it handles transitions!), kept the original classes around for comparison, and am wondering which method would work best. Having thoroughly tested both implementations, I can say without a doubt that they are equal in every way, including speed, accuracy, smoothness, frame-rate, memory usage, etc. so which one is 'better' in the sense of overall maintainability?
EDIT: after reading the well-written arguments you all have made, I have decided to use a singleton. #JustinXXVII has made the most convincing argument (IMHO), although I consider every answer here equally worthy of merit. Thank you all for your opinions, I have upvoted all answers in the question.
I believe the best option is use the category.
Because if you are already using UINavigationController, do not make sense create a new class that will only manage the transition, like you told: (after all, it handles transitions!)
This will be a better option to maintain your code, and you will be sure that the thing do what they expect to do, and if you already have an instance that do the transitions, why create another?
The design patterns, like singleton, factory, and others, need to be used with responsibility. In your case, I do not see why use a singleton, you use it only to no instantiate new objects, you do not really need to have only one instance of it, but you do it because you want only one.
I'll make the case for a singleton object. Singletons are used all over UIKit and iOS. One thing you can't do with categories is add instance variables. There are two things about this:
MVC workflows don't tolerate objects with intimate knowledge of other objects
Sometimes you just need a place to reference an object that doesn't really belong anywhere else
These things go against each other, but the added ability to be able to keep an instance variable that doesn't really have an "owner" is why I favor the singleton.
I usually have one singleton class in all of my XCode projects, which is used to store "global" objects and do mundane things that I don't want to burden my AppDelegate with.
An example would be serializing/archiving objects and unarchiving/restoring. I have to use the same method throughout several classes, I don't want to extend UIViewController with some serializing method to write and read arbitrary files. Maybe it's just my personal preference.
I also might need a quick way to lookup information in NSUserDefaults but not want to always be writing [[NSUserDefaults standardUserDefaults]stringForKey:#"blah"], so I will just declare a method in my singleton that takes a string argument.
Until now i've not really thought too much about using a category for these things. One thing is sure though, I'd rather not be instantiating a new object a hundred times to do the same task when I can have just one living object that sticks around and will take care of stuff for me. (Without burdening the AppDelegate)
I think that the real question is in "design" (as you said, both codes work fine), and by writing down your problem in simple sentences, you will find your answer :
singleton's purpose is to have only one instance of a class running in your app. So you can share things between objects. (one available to many objects)
category purpose is to extend the methods available to a class. (available to one class of objects only ! ok...objects from subclasses too)
what you really want is to make a new transition available to UINavigationController class. UINavigationController, which has already some method available to change view (present modal views, addsubviews, etc.) is built to manage views with transitions (you said it yourself, it handles transitions), all you want to do is adding another way of handling transitions for your navigation controllers thus you would preferably use a category.
My opinion is that what you want to achieve is covered by the category and by doing this you ensure that the only objects which are accessing this method are entitled to use it. With the singleton pattern, any object of any class could call your singleton and its methods (and... it could work nobody knowing how for an OS version n but your app could be broken in n+1 version).
In this implementation, for which there is no need to use a Singleton, there may be no difference at all. That doesn't mean that there isn't one.
A plastic bucket holds as much water as a metal bucket does, and it does it just as well. In that aspect there seems to be no difference between the two. However, if you try to transport something extremely hot, the plastic bucket might not do the job so well..
What I'm trying to say is, they both serve their purposes but in your case there seemed to be no difference because the task was too generic. You wanted a method that was available from multiple classes, and both solutions can do that.
In your case, however, it might be a whole of a lot simpler to use a Category. The implementation is easier and you (possibly) need less code.
But if you were to create a data manager that holds an array of objects that you ONLY want available at one place, a Category will not be up to the task. That's a typical Singleton task.
Singeltons are single-instance objects (and if made static, available from nearly everywhere). Categories are extensions to your existing classes and limited to the class it extends.
To answer your question; choose a Category.
*A subclass might also work, but has its own pros and cons
Why don't you simply create a base UIViewController subclass and extend all of your view controllers from this object? A category doesn't make sense for this purpose.
Singletons, as the name suggests, has to be used when there is a need to be exactly one object in your application. The pattern for the accessor method ensures only this requirement being a class method:
+ (MyClass*) sharedInstance
{
static MyClass *instance = nil;
if (instance == nil) instance = [[MyClass alloc] init];
return instance;
}
If implemented well, the class also ensures that its constructor is private thus nobody else can instantiate the class but the accessor method: this ensures that at any time at most one instance of the class exists. The best example of such class is UIApplication since at any time there might be only one object of this class.
The point here is that this is the only requirement towards singleton. The role of the accessor method is to ensure that there is only one instance, and not that it would provide access to that instance from everywhere. It is only a side effect of the pattern that, the accessor method being static, everybody can access this single object without having a reference (pointer) to it a priori. Unfortunately this fact is widely abused by Objective C programmers and this leads to messed up design and the hatred towards singleton pattern you mentioned. But all in all it is not the fault the singleton patter but the misuse of their accessor method.
Now turning back to your question: if you don't need static / global variables in your custom transition code (I guess you don't) then the answer is definitely go for categories. In C++ you would subclass from some parent BaseTransition class and implement your actual drawing methods. Objective C has categories (that in my opinion is another way that easily messes up the design, but they are much more convenient) where you can add custom functionality even accessing the variables of your host class. Use them whenever you can redeem singletons with them and don't use singletons when the main requirement towards your class is not that it would be only one instance of it.
I have a new project, kind of a board game, and I'm using a storyboard which has multiple view controllers in it - the game simply moves from one view to the next with the player making various decisions and then loops back.
I have an object which holds information about the player (along with a couple of methods) - the score etc. I obviously only need one instance of this object and as I want each View Controller to access the same instance, should it be a singleton? I've never used them before and I've read they're often over-used, so I just want to check if this is the correct way to do this from the start. Many thanks.
What you have described is the Model for your application, holding the game data and core logic. Is there any reason to make this a singleton rather than passing it between your controllers?!
I would assume one controller calls the next and so can pass this information across?! We use singletons for services and the like but not for model data, it's not really the point of them in our experience.
I personally have nothing against singletons, as long as you don't use too many of them in one project. While other people might recommend you use some other mediation for this project, I say go for it—this is exactly what you'd use a singleton for.
Singleton's can be be bad if you are developing a library component, a large server project, or for unit testing. But since you are doing an iphone game don't fret about it, it'll will be easier and faster just to use a singleton.
If you are worried about unit testing, since objetive-c is latebound and singletons are made with factory methods instead of constructors it's not hard to changeout the singleton for your unit test anyway.
I am creating a simple application using the MVC design pattern where my model accesses data off the web and makes it available to my controllers for subsequent display.
After a little research I have decided that one method would be to implement my model as a singleton so that I can access it as a shared instance from any of my controllers.
Having said that the more I read about singletons the more I notice people saying there are few situations where a better solution is not possible.
If I don't use a singleton I am confused as to where I might create my model class. I am not over happy about doing it via the appDelegate and it does not seem viable to put it in any of the viewControllers.
any comments or pointers would be much appreciated.
EDIT_001:
TechZen, very much appreciated (fantastic answer as always) can I add one further bit to the question before making it accepted. What are your thoughts on deallocating the singleton when the app exits? I am not sure how important this is as I know quite often that object deallocs are not called on app teardown as they will be cleared when the app exits anyway. Apparently I could register the shared instance with NSApplicationWillTerminateNotification, is that worth doing, just curious?
gary
There is a lot of push back on the use of singletons because they are often abused. Lazy coders either (1) don't put enough functionality in the singleton which results in having logic spread out in other objects like spaghetti or (2) they put in to much functionality such that the singleton becomes the entire program. Lazy coders way to often use singletons instead of doing data validation, object testing and object tracking. People get sick of trying to untangle and maintain lazy singleton use so they try to suppress the use of singletons.
I thoroughly understand the impulse and I myself ritualistically warn against singleton abuse.
However, a data model is one of the few legitimate uses for a singleton. This is especially true in small apps like those which run on mobiles. In the end, you will either use a singleton for your data model or you will attach it to a singleton.
For example, suppose you decide to park your non-singleton data model object in the app delegate. Well, you've done this: dataModel-->appDelegate-->application(singleton). To access it, you would call:
[[[UIApplication sharedApplication (a singleton)] delegate] theDataModelObj];
Even if you pass it around like a token from object to object you will still have to have the dataModel obj begin as the property of a singleton.
When an object really does have to meet the "Highlander" pattern ("There can be only one!") then a singleton is the best choice. In addition to the application object, you have user defaults as a singleton as well as the file manager. Clearly, in all three cases, you want one and only one instance in existence for the entire app. For example, if you had more than one user defaults object, your app would be a train wreck trying to track all the preference settings. If you have more than one file manager, file operations could step on one another.
A properly designed user data model is just a larger version of user defaults. It should be the only object that directly manipulates the user's data. No other object in the app should have that task in the least. That makes the singleton design pattern the best one to use in this particular case.
Singletons are a very powerful tool but just as with a physical tools, the more power they give you, the more opportunities they create for you to cut you head off if you use them carelessly. For this reason, a singleton should seldom be your first choice. There are usually better design patterns to employ.
However, when you really need a singleton, you shouldn't shy away from using them just because the laziness of others has given them a bad rep.
Knowing when and when not to use a powerful and dangerous tool is part of the programmers intuition you develop with experience. You can't go by formula. It is one of those factors that makes good coding an art and the programmer a craftsman.