Organization and Structure of iPhone/iPad Projects - ios

I've been developing iPhone apps for a while now and something that's always peeved me is that I haven't found a comprehensive way to organize my application files.
I know that an iPhone project is technically MVC, but it seems like most everything I do is in a ViewController. I notice that as a project goes on, my ViewControllers continue to get more and more bloated and I can't help but think that there has to be a better way than this. I also do some ruby on rails and I like the fact that on that platform there is such a clear separation of concerns and an established way to organize an application.
Has anyone discovered a way that they especially fond of for organizing the application?
Also how do cut back on the view controller bloat?

I agree, just about everything seems to land in view controller classes, and they get unwieldy in a hurry. There are several things you could try:
Create separate classes for delegates, if they don't actually need to be part of the view controller;
Put delegate method implementations into a category, as described here;
Factor out any methods that don't actually interact with the rest of the view controller, and put them in separate classes
Use blocks for asynchronous callbacks when they make sense, because they are often less verbose than explicit callback methods;
Or even just organize your methods carefully and use #pragma mark so Xcode can help you navigate through the file.
This isn't an exhaustive list, of course, and others may have better suggestions.

Related

Class Accessibility Throughout Project

When I first began working on a long iOS project, my first, I had need for a small class that was readily accessible throughout the project. At first I passed it around as a property and it became way too much of a headache.
So, even though I've seen posts here advising against it, I created that class in the AppDelegate and access it as needed through a pointer to the AppDelegate. Then, I would revisit it later.
So, it is now later, I'm approaching release of the project, and I want to deal with this issue. It works just fine as it is but if it is lousy practice I want to fix it before release.
I don't understand why it is lousy practice. Sometimes you just need a class that is readily available and these seems like as good a way as any to get it. But there could be some downside I'm not understanding.
Assuming I need this class instance (it is very lightweight but heavily used) to be accessible throughout the project (probably about 50 VCs, total), what would be a good alternative to just referencing it via the App Delegate?
TIA for comments. I hope it doesn't start a war.
There's no hard-fast rule for for this and hundreds of opinions to be had. Here's my take on it.
I don't understand why it is lousy practice. Sometimes you just need a class that is readily available and these seems like as good a way as any to get it. But there could be some downside I'm not understanding.
You're right to feel this way and yes sometimes you need a class readily available with your data. It's lousy because it is not how AppDelegate should be used. In an ideal world it shouldn't contain lots of unrelated state-data and should serve a singular purpose: delegating system calls to your app. The trick is where do you put your model so that everyone can have access to it?
Assuming I need this class instance (it is very lightweight but heavily used) to be accessible throughout the project (probably about 50 VCs, total), what would be a good alternative to just referencing it via the App Delegate?
Put your state in a class using the singleton pattern. It will ensure that only one copy of it is ever created and all your classes should be able to access it. This is a well accepted pattern in the iOS SDK (NSUserDefaults, UIApplication, etc..). Just beware of this class growing too large or doing too many things. Try your best to keep it simple and focused and the Object-Oriented Police will leave you alone.
Other resources and opinions worth considering:
http://www.cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
Is it a bad practice to use your AppDelegate as your Singleton?
Is it good practice to use AppDelegate for data manipulation and Handling?

How evil is a UIViewController?

This is a somewhat open ended question about the UIViewController class, and their proper role in an iOS app.
I recently read this article, and I partially agree with the author. It's obviously important that every bit of logic related to your views and models doesn't end up getting dumped into the UIViewController, but it seems a bit extreme to build all of your views separately and use delegate methods to access the actions.
I'm curious about which design is most efficient in regards to the memory and performance of the app (clearly an important consideration when dealing with mobile apps)? As the author of the post pointed out, Apple doesn't seem to strongly advocate against putting logic in the UIViewController.
Ultimately, I'd like to know the right way of doing things. So the question is, should the views and any logic associated with it be completely separated out of the VC? Should I really be using delegates to communicate with the UIViewController?
A view controller is not evil by nature, although it's common for them to grow into monolithic messes because they are so convenient to extend.
…it seems a bit extreme to build all of your views separately and use delegate methods to access the actions.
Think of it as breaking up your program into smaller units, whatever that may be. Subclassing UIViews in every case isn't the best solution (as one example).
Each developer's tolerance is a bit different and it varies by program/case, but it's pretty easy to recognize and eliminate duplicate code, and to break your programs down into smaller units.
I think most classes:
should not exceed a few ivars (e.g. 2)
should not require more than 100 lines
should favor composition over inheritance. in many cases where you think you need inheritance, protocols may be used.
Of course, there will be exceptions.
I'm curious about which design is most efficient in regards to the memory and performance of the app (clearly an important consideration when dealing with mobile apps)?
It matters more that you will gain a lot by writing more reusable programs. Invest more time and effort into these reusable designs, reduce duplicate code, and focus on quality. Write performance and memory into your designs where it is a concern. Generally, this will result in a big win when compared to the dreaded freshly written, poorly tested, monolithic VCs.
Ultimately, I'd like to know the right way of doing things. So the question is, should the views and any logic associated with it be completely separated out of the VC? Should I really be using delegates to communicate with the UIViewController?
Oversimplification: No, you don't have to go that far if you eliminate redundant code, focus on reusability where applicable, and ensure your units/classes maintain low complexity. Absolutely, fix those problems before they grow into monolithic classes, regardless of whether they are VCs or another type.
I've also read this article a year ago, when I was looking for better iOS coding practices than what you see everywhere (dumping all kinds of crap in view controllers...). I agree with its points, although unfortunately it doesn't provide any kind of solution to the problem.
After a year of working on a fairly large iOS application, with complicated data model, remote services and highly nonlinear navigation, my experiences come down to these points:
Use view controllers for a single unit of user interaction, like prompting for login credentials etc. Basic validation (e.g. checking for empty fields, number formats etc.) takes place in the view controller, but if validation is part of your business logic, it should be put in your model.
I usually have a so-called controller object which orchestrates the UI flow, and connects it with the domain model. The controller receives user input from the view controllers via delegate mechanisms, so they're loosely coupled.
A single monolithic controller should be avoided; so I usually try to split my controller functionality between simpler, modular parts. For example, I have a controller which manages a registration process with a mostly linear UI flow, and its embedded in the main controller of the application so its

Separate the controllers in a new project? Is this a good design?

My colleague told me to separate my controllers in a separate project to make the unit testing as easy as possible, and he also told me to create a solution for the controllers project and test project to avoid loading the whole application when conducting unit testing. Is it a good approach to separate the controllers in a new project?
I am not sure if there is a simple yes or no answer to this question. I would think that your project would have to be very, very large as to have impact on your unit testing. My personal opinion is to leave the controllers in the web project along with the views and view models. However, I am a fan of moving the models to a separate project. My reasons for doing so have less to do with easier unit testing but rather reusing the data access (models) in other applications.
In my opinion you should always at least separate the controllers from your view project (usually a web project for me), because the idea is that the controllers should be able to be used with any view (maybe later you decide to use them for a Windows Forms project, for example). It keeps the namespaces a bit cleaner as well.
From my point of view, making you move out the controllers to a separate project has two things to consider, if you do so, then it enforces you to think how to solve problems with low coupling and precisely low coupled classes can be tested more easily than tight coupled classes.
On the other hand, having the controllers in the same project than the views is kind of logical because the controllers normally know about the views.
If you think of reusability there may be something arguable here because often controllers are "glue" components this means, there is a lot of wiring in them.
This seems like a good idea at first. Creating a prensentation layer in the middle and keeping your MVC project containing only views, making it truly a UI project. On the other hand, you will probably lose the tooling support for the views. Since you have to ignore all the warnings, you have to make sure all views are there, strongly typed to your object.
I don't understand the concern for referencing your MVC project in your test suite since you will probably bring in the MVC namespace anyway.

Model-Controller Abstraction with Core Data

In learning about Core Data, I've noticed how (in Xcode's templates) Apple directly used the query classes inside the view controller. This seems like it is bad MVC (having database access logic directly inside the view controller). Would it make sense to abstract out these kinds of actions to a separate suite of classes that obtain the data from the database and pass it back to the view controller calling it?
EDIT–
So, just to be clear, when I say "kinds of actions", I specifically mean CRUD Operations. Though if you have ideas about other things that a so-called "Model-Controller" would do, I'd be interested in hearing about them.
It's a matter of opinion, and often yes the templates are the most simple form of working example. It's hard to have a template spin out multiple files, for example.
Yes, personally, I generally spin out a separate NSManagedObject subclass. I like to have a _MySubclass object that has all the auto-generated stuff, then have the model actually reference MySubclass which has model-based business logic (you can use mogenerator or other methods to do this too if so inclined). Perhaps thinking of it as "Model-Controllers" and "View-Controllers" is another way of putting it.
This is a very good question and the answer likely depends on your situation. Perhaps architecture purists would insist on separate Model controllers and there are a lot of benefits to this approach. However, sometimes I find myself using Key Values when I'm doing a simple view. When things are more complex, for example, when coding the same Model for the Mac and iOS, having separate Model Controllers will allow you to reuse a lot of code. When you must diverge, Obj C Categories are a very clean way to extend functionality without adding a lot of overhead. I personally favor categories over extensive subclassing.
Since NSFetchedResultsController was released, my model classes are leaner. There are a lot of nuances to this and experience will help you come up with the best solution for your App. I've also found that writing unit tests up front will help you force through issues and validate your design, or send you back to the drawing board :)

Why does Apple documentation that getting ManagedObjectContext from UIApplicationDelegate is bad?

Just curious why ManagedObjectContexts should be passed to UIViewControllers when they are created, rather than just grabbing them from a UIApplicationDelegate?
The docs say that this makes your applications more rigid, but I am failing to see the nuances of when to use which pattern.
Thanks!
Imagine that I ask you to do some task, like painting a room. If I just tell you "go paint a room," you'll need to ask me a lot of questions, like:
Which room?
Where's the paint?
Where are the brushes?
Should I use a dropcloth?
In short, you won't be able to complete the task without help from me. If you have to depend on me every time, you won't be a very flexible painter. One way to deal with that problem is for me to give you all the stuff you need at the outset. Instead of "go paint a room," I'll say "please paint room number 348 using this bucket of paint and this brush, and don't bother with a dropcloth." Now, you've got everything you need, and you can get right to work with no further help from me. You're a much more flexible worker because you no longer depend on me.
The same thing applies to view controllers (and objects generally); it's better to give them everything they need than to have them depend on a particular object like the app delegate. It's true not just for managed object contexts, but for any information they need to do their job.
This is mainly because you want to use dependency injection with your UIViewControllers instead of just grabbing everything from UIApplication, this keeps your delegate clean instead of full of reference hacks.
This is also to keep with the MVC pattern:
Model
View Controller (Only for view logic)
Controller (For coordinating between the view and the model)
I tend not to agree with this pattern.
First of all I try to treat Core Data as an implementation detail, and as any implementation detail it should be hidden behind a good facade. The facade is the interfaces I expose for my model objects. For example if I have two model objects; Cource and Student, any cource can have a number of students. I do not want to let the controller take upon the duty to setup predicates and sort descriptors, and jump through all Core Data hoops just to get a list of students for a particular class. There is a perfectly valid way to expose this in the model:
#interface Cource (StudentAccess)
-(NSArray*)studentsStortedByName;
#end
Then implement the ugly stuff once and for all in the Model class. Hiding all the complex details of Core Data, and no need to pass around managed object contexts. But how would I find the sources, it has to start somewhere right? Yes, it does but you need not expose it to the controller. Adding methods such as these are perfectly reasonable as well:
#interface Cource (CourceAccess)
+(Cource*)caurceByID:(NSString*)courceID;
+(NSArray*)allCources;
+(NSArray*)courcesHeldByTeacher:(Teacher*)teacher;
#end
This also helps in minimizing dependencies between controllers. And reducing he dependencies between the model and controller. Assuming I have a CourceViewController and a StudenViewController is I did not hide the Core Data details behind a facade and wanted to pass around the managed object context as well, then I would end up with a designated initializer like this:
-(id)initWithManagedObjectContext:(NSManagedObjectContext*)moc
student:(Student*)student;
Whereas with good a good facade I end up with this:
-(id)initWithStudent:(Student*)student;
Minimizing dependencies behind facades, in favor of dependency injection also makes it much easier to change the internal implementations. Passing around the managed object context encourages each controller to implement their own logic for basic stuff. Take for example studentsSortedByName method. At first it might be sorter by last/first name, if later changed to last/first name sort you would have to go to each and every controller that has sorted students and make the change. Where a good facade method requires you to change in one method, and all controller automagically get the update for free.
The Apple Docs try to foster the most widely applicable and sustainable design patterns.
Dependency injection is preferred because it allows for the most flexible, expandable, reusable and maintainable design.
As apps grow in complexity, using a quasi-singleton like parking the context in the app delegate breaks down. In more complex apps, you may have multiple context tied to multiple stores. You might want the same view-controller/view pair to display data from different context at different times or you may end up with multiple context on different threads/operations. You can't pile all those context up in the app delegate.
If you have a simple app with a single context then using the quasi-singleton with the app delegate can work well. I've used it on several smaller apps in the past without immediate issue but I did hit scalability problems on a couple of apps when the apps grew overtime.
Which pattern to use depends on your shipping constraints and you best guesses about of the evolution app over its entire lifecycle. If its a small one shot app, then the app delegate quasi-singleton will work fine. If the app is more complex, might grow more complex or might spawn other related apps that will reuse existing components, then dependency injection is the way to go.

Resources