LondonGuy
LondonGuy

Reputation: 11098

How do I identify a model, view and controller in objective-c?

Coming from ruby on rails in sublime text editor my folder layout had model, view and controller folders and his made it easy to identify what was what.

In objective-c I've just created a new project for a new tutorial I'm following. I have the files:

BullsEyeViewController.h BullsEyeViewController.m BullsEyeViewController.xib

It seems that the xib file is the view. I know that the .h file is for declarations and .m is for my implementation for those declarations. Would these 2 files be classed as the controller?

If so how would I identify a model? I've completed the boring but necessary objective-c programming book from the big-nerd-ranch but still find myself slightly confused when it comes to MVC in objective c.

I'm now doing another course and I thought I'd clear this up once and for all. In ruby on rails as I said I can easily identify models views and controllers but in objetive-c when i try to i start to get confused.

xib is a view? but has viewcontroller in it's name which twists me up slightly. Would appreciate some help clearing this all up. Lets say I wanted to create a file that dealt with all my storage and communicated with the db.. how would that look in terms of file name structure?

Also I've put the appdelegate files in the supporting folder for now to less confuse things. What I'd like to do is create a model, view and controller folder and put the related files inside them.

Upvotes: 2

Views: 4462

Answers (5)

Fruity Geek
Fruity Geek

Reputation: 7381

No programming language really enforces MVC separation. Frameworks like Ruby of Rails help to guide you into MVC separation using the Ruby language.

You can safely move files into folders without much issue to make your project easier to grok.

In UIKit, the following occurs:

Views

UIView objects are usually views. UIViews can be associated with zero to one UIViewController. UIView can be serialized as an XIB file or a storyboard.

Controllers

UIViewController is the View Controller. Objects that implement the UIApplicationDelegate are the controller of controllers for the main application. UIViewController can also be subclassed in a way that makes it also a controller of controllers like UISplitViewController, UINavigationController and UITabBarController.

So why does Xcode name XIB files the same name as the corresponding UIViewController?

UIViewController's implementation of loadView searches for XIB files in the specified bundle in three phases.

  1. For a nib named nibName if nibName is not nil in the specified bundle.
  2. For a nib named the class name minus the word "Controller" in the specified bundle.
  3. For a nib named the class name in the specified bundle.

This is why when you override loadView in a subclass, no nibs are loaded.

So you can safely rename your XIB files to remove the word "Controller" and everything will still work as long as your UIViewController doesn't specify a value in its nibName property. Why Apple decided to have Xcode pick the third case as the default when automatically creating a nib with a controller is anyone's guess.

Models

Models are usually subclasses of NSObject. When you use Core Data, the models are subclasses of NSManagedObject. The xml file it creates is like a nib file - it's just a serialization of the meta data of your models.

Upvotes: 4

Ayush
Ayush

Reputation: 3999

i just maintain this structure.

|view
|--all the .xib's and Storyboard
|Controller
|--All the View Controller both .h and .m file
|model
|--.h and .m file for each controller which would be call models.

Example.

|view
|--login.xib
|Controller
|--loginViewController.h
|--loginViewController.m
|model
|--loginModel.h
|--loginModel.m

In LoginModel I normally Handle API Calling and convert all json to object either NSMutableDictionary and send data to controller for further processing.

In My loginController it would perform operations on data received.

Example: I am Using AFNetworking for API Calling.

AFHTTPAPIClient.h

#import "AFHTTPClient.h"
#import "AFJSONRequestOperation.h"

@interface AFHTTPAPIClient : AFHTTPClient

+ (AFHTTPAPIClient *)sharedClient;

@end

AFHTTPAPIClient.m

#import "AFHTTPAPIClient.h"

@implementation AFHTTPAPIClient

// Singleton Instance
+ (AFHTTPAPIClient *)sharedClient {
    static AFHTTPAPIClient *sharedClient = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedClient = [[AFHTTPAPIClient alloc] initWithBaseURL:[NSURL URLWithString:@"www.yourdomain.com"]];
    });
    return sharedClient;
}

- (id)initWithBaseURL:(NSURL *)url {

    self = [super initWithBaseURL:url];
    if (!self) {
        return nil;
    }
    [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
    [self setDefaultHeader:@"Accept" value:@"application/json"];

    return self;
}

@end

loginModel.h

#import "AFHTTPAPIClient.h"

+ (void)loginWith:(NSDictionary *)parameters withBlock:(void (^)(NSMutableDictionary *, NSError *))block;

LoginModel.m

+ (void)loginWith:(NSDictionary *)parameters withBlock:(void (^)(NSMutableDictionary *, NSError *))block {
[[AFHTTPAPIClient sharedClient] postPath:@"/api/login" parameters:parameters
                                 success:^(AFHTTPRequestOperation *operation, id responseObject){
                                     NSLog(@"%@",responseObject);
                                     if (block) {
                                         block(responseObject, nil);
                                     }

                                 }
                                 failure:^(AFHTTPRequestOperation *operation,NSError *error){
                                     if (block) {
                                         block([NSArray array], error);
                                     }
                                 }];
}

and then finally use them in Controllers.

loginViewController.m

NSDictionary * loginParametes = [[NSDictionary alloc] initWithObjectsAndKeys:_txtUsername.text,@"username", _txtPassword.text,@"password",nil];
[LoginModel loginWith:loginParametes withBlock:^(NSMutableDictionary *loginInfo, NSError *error) {
    if (!error) {                    
        if([[loginInfo objectForKey:@"status"] boolValue]==YES){
                // Login Success
        }
        else {
                // Login Failure
        }
    }
    else {
                // API Responce failure if content type is not a valid json or valid status code.
    }
}];

Upvotes: 5

CocoaEv
CocoaEv

Reputation: 2984

Don't be confused by the "view" in "view controller".

It is generally your "controller". If your using xib files or storyboards then they would typically be your "view".

Models, for clear separation should be in separate files, however, in many tutorials, the model will be represented by code in the "view controller" and typically be a data store made up of an array or dictionary.

Area's that will confuse you when learning is when you find "view" code, actually in code. You can usually identify this when you see code like [self.view addSubView:someOtherView] along with lots of code creating UI elements and setting their frames and masks, etc.

Don't let that confuse you. They should probably be in separate files as well, but often as not it's mixed in. Even though it is in the "view controller" it is really the "V" in MVC.

In some examples I recall reading, I didn't know it at the time, but later realized they had represented the entire MVC in a single view controller. This is quite possible, although not recommended obviously.

Other things that may be confusing: class properties can serve as models. An array of 25 photos for instance. You may find examples that show the code to make the network connection and retrieval of the photos in side of the "view controller", yet this is really "M" code. Once the photos are retrieved and stored, the holder of that data becomes the model. The correct way would be to design a class to execute the network call and return the photos to the controller (view controller) and then maybe call a method that updates the UI (view) with the new data. Frequently this is mixed into the view controller and you may see something like a network call that provides a completion block and in the completion block, properties on the view are being updated. In small "scenes" where that network call is the only callout to bring in model data, then maybe it really is simpler and more efficient to have that single block statement in the controller (view controller). However, if many callouts are made for retrieve data, then it really should be isolated in its own class file and be a "M".

in most IOS apps, you actually get a new MVC for each "scene" or new view that is presented. You don't really have one controller, but rather many. In my own words, I would also say you have the concept of "controllers of controllers" in an IOS app. Examples of these would be the appDelegate, navigation controllers, tabbar controllers, split view controller. You might also have a model controller, like Core Data for instance, one big controller that controls many model objects through its context. And the storyboard, if you think about it, is really just a controller of views. In these cases, you pluck out the specific controllers, views and model objects you need for each scene and connect them together.

hopes that helps and does not cause more confusion. be well.

Upvotes: 1

Uzziel
Uzziel

Reputation: 300

XCode doesn't enforce MVC structures in quite the same way Rails does, as you've seen. It's been a few years since I worked with Rails, so I may be out of date, but this is what I remember: when you start a Rails project you can provide database files, and Rails will use those to generate model objects which describe the database entities, along with views to see/edit those model objects, and controllers to connect the models and views.

When you create a new Single View Application in XCode, it does not generate any model files for you. It can't, since it doesn't give you the opportunity to specify what your models look like before you create the project. All it knows is that you're going to have a view, so it creates that view for you (in a .xib file) and a controller for that view (in the .h and .m files).

The .xib file gets named after the controller. I always found this confusing, but that's a decision that Apple made.

You can kind of simulate the model creation in XCode by going in to the Core Data editor and creating a new Core Data Model (File -> New -> File -> Core Data -> Data Model). When you fill out this model, you can create files that describe the new model objects by selecting the entities you've created and going to Editor -> Create NSManagedObject Subclass; this will generate .h and .m files that wrap the model objects you've described.

Of course, your model objects don't have to be backed by a persistent store; you can just create new files for them without going the Core Data route. But XCode does not enforce the directory structure that Rails does. It will happily lump all your MVC files together in the same directory. It's up to you to create that structure if you want it.

xib is a view? but has viewcontroller in it's name which twists me up slightly.

Yes - I agree, this is confusing. XCode names the view files (.xibs) after their controller objects. I don't think this is a great approach, but there you have it.

In short: XCode will create view and controller files for you automatically whenever you add a new view file to your projects. It never (as far as I know) creates a model file for you explicitly except when you use the Core Data editor, and even then it doesn't put "model" in the file name - it just names the file after the entity that you created.

Upvotes: 1

Farhan Misarwala
Farhan Misarwala

Reputation: 182

This is from what I have understood in past few weeks about MVC paradigm in iOS. The MVC design pattern in iOS programming follows a slightly different approach when implemented in objective C , compared to other languages. Your class BullsEyeViewController is your controller according to MVC paradigm. Your .xib file is your view. Xcode follow the pattern of naming your files according to the classes you specify in the create-project window. Your model classes will implement your applications logic. Most of your database management will be handled by your controller. To abide by the MVC here , you will have to create your model classes differently.The model classes will notify the controller. The controller will do the job of updating the views and models. and responding to user-actions in the view.

Upvotes: 2

Related Questions