All the examples I've come across so far ( including Stanford podcasts ) reference a Model by declaring it as a property of a View Controller and using it from there:
#import "myClass.h" // assume it carries a single NSString property
#interface
#property (nonatomic,strong) myClass *myobject;
#end
#implementation ViewController
-(void)viewDidLoad {
self.myObject = [[myClass alloc] init]
.
.
.
-(void)someMethod{
displayLabel = self.myObject.myString;
seems like that's more self.C-V than M-V-C.
After messin' about on my own this works:
#import "myClass.h"
#implementation ViewController {
MyClass *myObject;
}
-(void)viewDidLoad {
myObject = [[myClass alloc] init]
}
.
.
.
-(void)someMethod{
displayLabel = myObject.myString;
my question is; is there any danger in using second example? or to ask differently, does it give the compiler an easier task of keeping MODEL separate from VIEW and CONTROLLER?
There are a couple of implementation details that are different between your two examples but they are essentially doing the exact same thing.
In both cases you are declaring a backing ivar. This line #property (nonatomic,strong) myClass *myobject; will implicitly #synthesize myObject = _myObject;, which is similar to you manually writing:
#interface ViewController : UIViewController {
MyClass *_myObject;
}
// or
#implementation ViewController {
MyClass *_myObject;
}
The only other difference is that #property (nonatomic,strong) myClass *myobject; will also create the accessor methods for you
- (void)setMyObject:(MyClass *)myObject;
- (MyObject *)myObject;
This is indeed still MVC but controllers that are subclasses of UIViewController always manage at least one view. The M component is your myObject instance. As in most diagrams the Controller sits there managing the communications between the V and M both of which the controller owns
Using singletons or holding the model as a property of the controller is also a question of lifetime. I prefer using singletons for helper classes (getting data from game center or fetching data from core data). Singletons are useful for things you need to access from different places within your app (where lifetime of your singleton is longer than your view controller's lifetime). But for view controller dependent models you can of course use them as properties of the view controller. Let's say you have ten view controllers in your app each displaying completely different content it does absolutely not make sense to keep all data for all possible view controllers in memory (in a singleton) just to have data ready in case the user wants to see any of the view controllers. In this case it's no shame to load your model's data from within your view controller implementation and hold it as a property. This guarantees that data is auto released when the view controller's lifetime ends and avoids conflicts. Holding data in singleton would make sense when you display data loaded from a server that does not need to be refreshed everytime you present your data to reduce the amount of traffic generated by loading the data. Using singletons might be dangerous regarding thread safety e.g. when data is mutated from a background thread while iterating over your datasource object to refresh a table view's content. Singletons can also lead to tigh coupling which should be avoided. Using an instance variable instead of a property is still a good choice if you want to hold a weak reference to an object as it is automatically set to nil if the referenced object gets auto released. A weak property would in this case lead to bad access.
Related
As I was thinking about all the incarnations of MVC in Cocoa, I figured I could make a custom class for every View in the application and fill it with a datasource and delegate - stuff primarily considered for Controller.
This way, instead of having the infamous Massive-View-Controller, I could chop off pieces of code and put them in separate files - one class for one View - along with their datasource and delegates.
Is it a good idea, or what are the downsides?
I'm afraid that your idea sounds like you will end up with a bunch of bloated views instead of a bunch of bloated controllers.
What I'd suggest is to consider the Single Responsibility Principle: an entity should have exactly one purpose or function. What's a view's function?
It's a representation, in code, of a region of the screen. That means it needs to do two things: draw to its area and register interactions with the area. Anything that's not absolutely essential to those two subtasks shouldn't be in the view class.
This is the idea of the "dumb view". It has no logic, no decisions to make. It just gets handed some data to render. And when it gets a tap or a click, it doesn't know what the input represents, or try to figure out what to do about it. It just knows the type of the interaction and tells another object.
That other object is the view's controller. A view controller's responsibility is to mediate between the view and the rest of the system. It gives the view its data. It also accepts messages from the view about input, and then reconfigures the view based on the result of those messages.
The view controller doesn't necessarily need to compute the result on its own, however. That's usually where view controllers start getting into "massive" trouble. The view controller should pick another object to help it get the new values that the interaction produces.
One possibility for this other object is the view model, in the MVVM structure. The view model is a display-focused representation of the raw data for the view. It transforms the information in the model into whatever format the view needs, and re-transforms or updates the data in response to input from the view controller.
Another idea is to split that responsibility even more finely, using a VIPER arrangement. Here the formatting of the data is handled by a "Presenter", and the transformation of the data is the job of an "Interactor".
It's possible to get into architecture astronaut territory here; blindly applying a complex structure can bite you if a view's needs are inherently very simple. But even if you choose not to formally apply one of these alternative patterns, a view controller needs other objects. You will want "controllers" with other specific jobs, that get messages from the view controller and pass data back.
The important thing is to keep in mind the original idea I mentioned: strive to make each type do one thing and do it well. That will keep your classes focused; easy to read, understand, and think about; and testable.
View doesn't compute it's data, it just displays them. However if you have custom control it can have some logic to compute it's inner data to trigger value change inside model.
Your approach is an overkill with unnecessary code.
So you are facing a problem where you need to set some values of your custom NSView or custom NSControl (e.g. NSButton title).
Some of available MVC solutions:
set the value inside controller manually and call setNeedsDisplay method inside within view on the changed property.
set the model object as the property of view. However, this introduces tight coupling but still is ok (so the view has to
know/import model class). +Include update/refresh method within view
use bindings to nsobjectcontroller. You don't need to set Class of nsobjectcontroller (that is needed only if you need additional
functionality for it like creating object automatically on add
method).
MVC pattern reminder
View has target action mechanism which is triggered in controller. Controller updates model (nothing else!). Model then has to propagate that it has changed and controller should react to it. It shouldn't react in the target action.
With bindings you skip the target action but the latter remains
You can combine 2 and 3.
If you are beginner forget about VIPER pattern. MVVM can help you to reduce size of your controllers.
How to use binding with NSObjectController:
#import <Foundation/Foundation.h>
#import "AppDelegate.h"
#import "Value.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSObjectController *objectController;
#property (strong) Value *value;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.value = [[Value alloc] init];
self.objectController.content = [self value];
}
#end
#interface Value : NSObject
#property NSString *value1;
#property NSString *value2;
#property NSString *value3;
#end
#import "Value.h"
#implementation Value
- (instancetype)init
{
self = [super init];
if (self) {
[self setValue1:#"Value1"];
[self setValue2:#"Value2"];
[self setValue3:#"Value3"];
}
return self;
}
#end
There is also an option to unload View Controllers with Coordinator objects. Shortly: each task in the app is managed by a Coordinator object, which manages its View Controllers.
There is the main Coordinator object, that is retained by application delegate and that retains all other Controllers. All the logic that doesn't belong in View Controller, is moved up to the Coordinator.
I'm building an app whereas I have a ViewController viewing a custom object, lets call this object "CustomObject". Upon a button press, a segue is triggered and hence prepareForSegue is called where I get the destination ViewController and pass self.myObject. The destination ViewController may change a few parts of the CustomObject, but those changes should not be reflected in the original ViewController if the user decides to go back to the original ViewController. The changes should only be reflected if the user pressed "Save" in the destination ViewController and hence triggering an NSNotification with a version of the CustomObject that should be reloaded in the original ViewController like so:
self.myObject = (CustomObject *)notification.object;
So my question is as follows: Which of these should I use (or any other that would be correct) - and why?
#property (nonatomic, strong) CustomObject *myObject;
#property (nonatomic, copy) CustomObject *myObject;
Thanks!
Update:
header file:
#interface CustomObject : NSObject <NSCopying>
implementation file:
- (id)copyWithZone:(NSZone *)zone
{
id copy = [[[self class] alloc] init];
if (copy)
{
// Copy NSObject subclasses
[copy setRegisterDate:[self.registerDate copyWithZone:zone]];
}
return copy;
}
You should use strong but (in prepareForSegue) create and pass a copy (or simply a different object, but in any case, don't pass the original object).
This is the opposite of the situation for which the copy property attribute was designed. With the copy property attribute, the recipient wants to ensure that the object is not mutated later behind his back: e.g., I accept an NSString but the caller passes me an NSMutableString and retains it as well, so that my string can now be changed behind my back. By calling copy, I turn the NSMutableString into an NSString, which is immutable.
Your situation, as I said, is just the opposite. Your first view controller wants to pass an object without any risk of affecting his own object. Therefore, it is up to your first view controller to make a new object and pass it, rather than passing a pointer to his own sacred object. It is not your second view controller's job to know that your first view controller needs protecting; it is up to your first view controller to protect himself.
I feel you can go for copy. Since it can be used when the object is mutable. Use this if you need the value of the object as it is at this moment. You don't want that value to reflect any changes made by other owners of the object. You will need to release the object when you are finished with it because you are retaining the copy.
Pl. refer to the below link also which gives good insight when to use which property.
Objective-C declared #property attributes (nonatomic, copy, strong, weak)
You should use "copy", because "copy" creates a duplicate instance of that object, and the new object is independent of the original object. "strong" adds a "link" to the object, it's only one object.
How you guys slim down your view controllers?, sometimes you end up implementing a lot of protocols in your view controller, so there’s a lot of code inside the controller itself. Reading about how to slim down view controllers in iOS I found that a common way is to move DataSources (http://www.objc.io/issue-1/lighter-view-controllers.html) to other class, but what about other delegates?, or if you create views by code?. First, I think about move each delegate to a NSObject class, so I try this:
self.locationManager.delegate = [[FRRYPetDescriptionViewControllerLocationDelegate alloc] init];
Then I ask in IRC and somebody suggest categories, so this is what I got so far:
// FRRYPetDescriptionViewController.h
#interface FRRYPetDescriptionViewController : UIViewController
#property (nonatomic) CLLocationManager *locationManager;
#property (nonatomic) TPKeyboardAvoidingScrollView *scrollView;
#property (nonatomic) UIView *contentView;
#end
// FRRYPetDescriptionViewController+Protocols.h
#interface FRRYPetDescriptionViewController (Protocols) <UITextViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate, MKMapViewDelegate, UIViewControllerTransitioningDelegate, CLLocationManagerDelegate>
#end
// FRRYPetDescriptionViewController+UIAdditions.h
#interface FRRYPetDescriptionViewController (UIAdditions)
- (void)createScrollView;
- (void)createContentView;
#end
// FRRYPetDescriptionViewController+Callbacks.h
#interface FRRYPetDescriptionViewController (Callbacks)
#end
// FRRYPetDescriptionViewController+LocationAdditions.h
#interface FRRYPetDescriptionViewController (LocationAdditions)
#end
This makes me think, what about “private” methods?, do I need to declare all properties in the view controller header file?. What you guys think about this approach or there’s some common pattern to follow to not end with a fat controller?.
Thank you.
The link that you have referred to has beautiful explanation for less bulky controller's programming. But techniques are bit tricky unless you are a seasoned developer. You have asked about multiple techniques in your question. Please check my views on them below: -
Delegates - I personally prefer to keep the delegate code in my controller itself to avoid unwanted confusion specially when you are working with multiple scenarios within the same controller.
Create Views Programmatically - This is the portion where we can cut the large amount of code from UIViewController. Unless it is a single control such as a single label or button, we should make a custom UIView class and let it set all the common properties for view customisation. Controller should only invoke it with necessary parameters.
Properties in Header File - No, concept of data encapsulation says that we should only make those variables public which are required. Rest should move to private domain so that we external objects can't interfere with the class object functionality. So you should declare these properties in class extension (inside .m file). Moreover it is not required to have all variables as properties, when they are private you can declare them as instance variables as property declaration does nothing but to create the getter/setter for that variable.
Private Methods - Same goes to methods as well. If it doesn't have to be exposed to other objects; it should not be in header file. Keep it in extention as private method.
Suppose I have several objects (models) that belong to a UIViewController. When one of the models changes or does something, I want it to notify the UIViewController so that the view can update immediately, or perform some animation in response.
How do I do this? Specifically,
(1.) How do the individual objects know about the ViewController? If I store a pointer to the ViewController inside each object, then I introduce a cyclical reference where a ViewController refers to children that refer to ViewController.
(2.) Even with a weak pointer, the model objects themselves don't know which view inside the ViewController corresponds to itself. For example, say there are 10 views and 10 models. The models aren't coupled with the views (i.e. each model has a view that represents it in the array of 10, but the index isn't always the same, since the user is constantly switching them around, so while the models have a stable index 0...9, the view representing model 0 could be at index 1, or later at index 2, 3, ..., 9), so when a model updates, it needs to tell the ViewController somehow which of the 10 views represents it, except it doesn't know. So the ViewController in turn can't know which View to update.
I should add that my current code just gives each model object a pointer to its corresponding View, so that it doesn't need to go through the ViewController to access the correct View and update its contents. But this would seem to violate MVC, so I'm trying to correct my code and realized I don't know how in this particular situation.
Sorry if that is confusing. I'll update the question if anything is unclear.
EDIT: Updated with more concrete example code.
#interface ViewController : UIViewController<ProfileViewControllerDelegate>
{
BattleModel* battle;
}
#property (nonatomic, strong) BattleModel* battle;
#property (nonatomic, weak) NSArray* heroPersons; // Person objects
#property (nonatomic, weak) NSArray* villainPersons; // Person objects
#property (nonatomic, strong) IBOutletCollection(PersonImageView) NSArray* villainImages;
#property (nonatomic, strong) IBOutletCollection(HealthBarView) NSArray* villainHealthBars;
#property (nonatomic, strong) IBOutletCollection(PersonImageView) NSArray* heroImages;
#property (nonatomic, strong) IBOutletCollection(HealthBarView) NSArray* heroHealthBars;
#property (weak, nonatomic) IBOutlet UITextView* reporter;
That describes the ViewController Interface. Now, each Person class handles modification of the Person, in addition to how the Person reacts to attacks.
#interface Person : NSObject
{
__weak Profile* profile;
__weak PersonImageView* personImg;
__weak BattleModel* currentBattle;
Reaction* currentReaction;
}
// Reaction happens in the following methods:
-(BOOL) targetedFoeWithMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(BOOL) wasTargetedByMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(void) hitFoeWithMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(void) wasHitByMove:(SelectedMove*)selMove log:(UITextView*)reporter;
As you can see, I currently violate MVC because the reporter is passed into the model Person, and also a pointer to the personImg, which the VC should handle. Anyways, as the battle happens, the Reaction* is queried inside the various targeted, hit routines, and that's where modifications happen, and the reporter is notified. Notice how the Person has NO IDEA whatsoever which index its corresponding PersonView is occupying in the grand scheme UIViewController, so when currentReaction triggers in some deep routine, and passes up the data, the ViewController has no idea which UIView to update. It knew at one point (when the Person was created), but the heroImages and villainImages array gets shifted around a lot (even switching sides if one Person goes from hero to villain), so the index it had at birth isn't the index it necessarily has at the point when a Reaction triggers and needs to update the PersonImageView. That's a bit of an annoyance, so I might need to have data passed back up to the UIViewController, telling it which PersonImageView just underwent a Reaction (how would I do that?).
Here is a sample Reaction, just for completeness and helping you understand the system:
-(void) wasHitByMove:(SelectedMove*)selMove log:(UITextView*)reporter
{
[self.currentReaction personWasHitByMove:selMove inBattle:self.currentBattle log:reporter];
}
And depending on if the Reaction is relevant (there are several subclasses of Reaction that do different things), a modification like "loseLife:(int)life" is called through a Person property setter, and that's when I need the report/animation to be bubbled up to the VC. Right now, the erroneous code (bad design) is simply going directly to the personImg for the animation, then the reporter for the textual notification. I realize this is bad design, which is why I'm here, but it isn't as simple as telling the VC through a callback, "(BOOL) Hey, something happened to me." because which PersonImageView is "me"? How does the ViewController, in the middle of its own method executing the logic of the battle, know to respond immediately to the callback? How is the callback even made? (Re: Delegates. So attach the delegate protocol to Person, PersonImageView, and UIViewController? And since they all follow the protocol, then they can interpret the common message through the protocol method?)
I also looked in NSNotification but find that too complicated for this purpose; it seems like it's more of a passive Observer type of thing, where in my application, when a Reaction triggers, I need the UIViewController to immediately update the screen with UITextView text + PersonImageView animations. Immediately in the sense that before the Reaction can trigger again, the animation needs to happen, as it could involve the PersonImageView recoiling, or falling down, or changing appearance. It isn't a real-time game, but the next attack will have already been queued and will be coming momentarily after the one before has triggered the currentReaction, so any kind of delay or passive observation might be bad.
Delegates.
Suppose you have a view with a button. Give it a protocol:
#protocol MyButtonViewDelegate
#required
- (void)buttonPressed;
#end
Now your view with a button has a property like this:
#property (nonatomic, weak) NSObject<MyButtonViewDelegate> *delegate;
Which is its reference to the view controller.
The view with a button's class will have a method like this which is hooked up to the button:
- (IBAction)buttonPressed:(id)sender {
[self.delegate buttonPressed];
}
Your view control conforms to the MyButtonViewDelegate protocol and sets itself as the delegate to the view. It then implements the method buttonPressed:
- (void)buttonPressed {
// do whatever you want to do when that button was pressed
}
If you need to pass a reference to the view in this method, you can do that too:
#protocol MyViewDelegate
#required
- (void)someMethod:(id)sender;
#end
Then:
- (IBAction)someUserInteractionWithView {
[self.delegate someMethod:self];
}
The delegate then implements the method from the protocol:
- (void)someMethod:(id)sender {
// sender is a reference to the view which called this method on delegate
}
You can write a protocol method to send as many arguments as you want. You can even have these methods return values that you make use of:
#protocol MyResizableViewProtocol
#required
- (CGRect)newSizeForResizableView:(MyResizableView*)resizableView;
#end
Something within the view class triggers this method to be called on the delegate and request a new size. The delegate implements this method:
- (CGRect)newSizeForResizableView:(MyResizableView*)resizableView {
return CGRectMake(0.0f, 0.0f, 100.0f, 400.0f);
}
And the resizable view makes use of the method as such:
- (void)timeToResize {
self.frame = [self.delegate newSizeForResizableView:self];
}
As far as I'm concerned, understanding protocols and delegates is one of the more important aspects of iOS development.
Bocks are a great way to implement callbacks in objective-c. Here is a link to Apple's documentation. Apple already implements blocks all over their APIs with NSOperationQueue, NSOperation, view animation, and many others. Check out this article about communication patterns in iOS, it explains the right circumstances for using delegation, blocks, notifications, and others.
There are several ways to do this. One way is by notifications. Have your models send out notifications when these interesting events happen. Your view controller can then sign up to receive these notifications and act accordingly.
In each model, do something like this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"somethingInModel3" object:self];
In the view controller, do something like this in init or viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleModel3Event:)
name:#"somethingInModel3"
object:nil];
The selector specifies the method that will handle the notification. You need to write that method as appropriate.
You'll also need to put (e.g., in dealloc in the view controller):
[[NSNotificationCenter defaultCenter] removeObserver:self];
I have read in multiple places that only one UIViewController should be on screen at a time. But I don't quite understand how to accomplish what I need otherwise.
Imagine the weather app. There is a single view controller with a scroll view, to which multiple views are added (the weather panels). Presumably these are all added and managed by the main UIViewController, which is also responsible for scrolling, etc.
But imagine each of those weather panels was instead a CarView, each with data about a specific type of car, and some controls to edit that data.
Wouldn't it make sense to have a series of CarViewControllers, each with a Car property that they can manipulate? Each CarViewController would be responsible for it's car data object, it's view, and glueing them together, and the main view controller would simply be responsible for adding each carViewController.view to its scrollview.
Isn't this better for re-usability and encapsulation? Not to mention more convenient.
I think it just comes down to whether it will make your life easier or not. One alternative I like to do is to just write composite UIView subclasses specifically for displaying a "conceptual" model - like a car - and then write categories on them to populate the view information using a specific model implementation. That way you can re-use the view when changing your model but still keep some of the logic from cluttering up the view controller. I try to reserve a view controller for something like radically different views toggled with a UISegmentedControl or something.
Edit: an example of a UIView and its populating category.
#interface CarView : UIView
#property (strong) UILabel *modelLabel;
#property (strong) UILabel *makeLabel;
#property (strong) UILabel *yearLabel;
//etc
#end
Then you have a model-specific category, that while a category on the view really fits more into the controller layer; while a little bit of a breach of MVC I think it works nicely from a responsibility assignment standpoint, doesn't couple your main view implementation to any data implementation, and keeps your view controllers leaner, so I think it's worth the tradeoff.
#interface CarView (CarEntityPopulating)
- (void)populateFieldsWithEntity:(NSManagedObject *)entity;
#end
#implementation CarView (CarEntityPopulating)
- (void)populateFieldsWithEntity:(NSManagedObject *)entity
{
self.modelLabel.text = [entity valueForKey:#"name"];
self.makeLabel.text = [[entity valueForKey:#"make"] valueForKey:#"name"];
self.yearLabel.text = [[entity valueForKey:#"year"] stringValue];
//etc....
}
It seems like this now explicitly supported in iOS 5 using a container view controller.
There are not a lot of resources yet that discuss it, but this WWDC session is useful.
This question also provides some resources.