I'm a part-time notepad website coder taking steps into IOS apps. I got my first mac last week and have cobbled together a half working app. Now, convinced by this SO answer, I am restarting trying to learn MVC. I am on a very steep learning curve so please bear with me.
I have read up on MVC, separation of layers, three boxes and some arrows, I get it. However, translating the theory into the real world is frustrating. Most example apps I have looked at do not seem to use MVC. Even this LazyTableImages example from Apple seems to use app delegate
as the model which confuses me. I have built on this excellently simple MVC example.
My app retrieves location markers from a web service. I have a tabbed application using ARC. One tab has a Mapkit map to display the markers.
A simple class to hold a marker record:
@interface MarkerRecord : NSObject
@property (strong, nonatomic) NSDecimalNumber *lat;
@property (strong, nonatomic) NSDecimalNumber *lon;
@property (strong, nonatomic) NSString *des;
A Model class, holding a collection of Marker classes, to serve both views. This is my Model class .h:
@interface MarkersModel : NSObject
- (void)getMarkers; // Send HTTP GET to web service to retrieve JSON markers
- (void)postMarker; // Send HTTP POST to web service to INSERT new marker record
And the implementation:
@interface MarkersModel ()
@property (strong, nonatomic) NSArray *data;
@end
@implementation MarkersModel
@synthesize data;
- (void)getMarkers
{
// Send HTTP GET to web service to retrieve JSON markers
...
}
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
// Thanks to Restkit data is an array of Marker classes
data = objects;
// Pass data to controller
}
A mapViewController class .h:
#import <MapKit/MapKit.h>
#import "MarkersModel.h"
@interface MapViewController : UIViewController<MKMapViewDelegate> {
MarkersModel *markersModel;
}
@property (nonatomic, strong) IBOutlet MKMapView *mapView;
@end
And the implementation:
@interface MapViewController ()
@end
@implementation MapViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Create instance of markers model
markersModel = [[MarkersModel alloc] init];
}
-(void)viewWillAppear:(BOOL)animated
{
[markersModel getMarkers];
}
- (void)putMarkersOnMap
{
// To be called by Markers Model
...
}
Here's my main question:
If so:
I strongly suspect the answer is a custom delegate on the controller but I cannot for the life of me see how to implement it. I cannot relate any examples to my situation. I think I need something like this on the controller:
@class MapViewController;
@protocol MapViewControllerDelegate;
While I am at it some additional questions:
unsafe_unretained
(I am compiling to 4.3)?I hope this is clear and an acceptable question. Thanks for your patience, Polly.
Model-View-Controller, or MVC for short, is a widely used design pattern for architecting software applications. Cocoa applications are centered around MVC and many of Apple's frameworks are impregnated by the pattern.
MVC is the most-known architecture pattern when it comes to iOS development. In this first article, we saw it in action being applied to a small application. We used the naive approach, where each screen is represented by a View Controller.
As a new iOS developer, there is a huge amount of information you need to master: a new language, new frameworks and APIs, and Apple's recommended architectural pattern Model-View-Controller, or MVC for short. The MVC pattern is commonplace in iOS development.
The difference between the MVC and MVVM is View and controller are responsible for calculating the value and assigning the value so the load is more on View and Controller where in MVVM View and Controller are only responsible for assigning the value not calculating the value.
Is my code outline above (the beginnings of) a decent MVC implementation?
By my standards, yes
how do I get the Model to update the Controller
You are correct, you want to use a delegate. You declare the delegate protocol along with the class it is a delegate for. So expanding on your MarkersModel
header:
@protocol MarkersModelDelegate<NSObject>
-(void) markersDidUpdate:(MarkersModel*)model;
@end
@interface MarkersModel : NSObject
{
__weak id<MarkersModelDelegate> delegate;
}
@property(weak,nonatomic) id<MarkersModelDelegate> delegate;
Then in your view controller:
@interface MapViewController : UIViewController<MKMapViewDelegate, MarkersModelDelegate> {
Then in the model implementation:
@implementation MarkersModel
@synthesize delegate;
//...
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
// Thanks to Restkit data is an array of Marker classes
data = objects;
// Pass data to controller
if( delegate != nil )
{
[delegate markersDidUpdate:self];
}
}
Will I create any dangling pointers - I suspect something should be unsafe_unretained (I am compiling to 4.3)?
Not that I am aware of
Is my MarkersModel declaration in the controller class correct? I am concerned that it will not be managed by ARC. I also suspect it is public but should be private.
You can declare it as private by adding the @private
header beforehand:
@interface MapViewController...
{
@private
MarkersModel *markersModel;
...
Should the MarkersModel.getMarkers method be static?
If by static, you mean as a class-level instead of instance-level method, that entirely depends on your implementation. If all MarkersModel
objects are supposed to retain the same data, then yes it makes sense to make it class-level. But if each MarkersModel
object is supposed to retain its own set of Markers
then no, it should remain an instance-level method
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With