Need some tips regarding the Cocoa MVC/KVO patterns - cocoa

This is a very wide-ranging/vague question, but here goes. Apologies in advance.
The app (desktop app) I'm building takes different kinds of input to generate a QR code (I'm just building it to learn some Obj-C/Cocoa). The user can switch between different views that allow input of plain text (single text field), VCard/MeCard data (multiple text fields), and other stuff. No matter the input, the result is a QR code.
To keep things contained, I'd like to use the views as view-controllers, so they handle they're own inputs, and can simply "send" a generic "data to encode" object containing all the data to a central encoder. I.e. the plain text view would make a data object with its textfield's text, while the VCard/MeCard view would use all of its fields to make structured VCard/MeCard data.
I can bind all of this stuff together manually in code, but I'd really like to learn how bindings/KVO could help me out. Alas, after reading Apple's developer docs, and the simpler tutorials/examples I could find, I'm still not sure how to apply it to my app.
For instance: The user edits the textfields in the VCard-view. The VCard view-controller is notified of each update and "recalculates" the data object. The central encoder controller is then notified of the updated data object, and encodes the data.
The point of all this, is that the input views can be created completely independently, and can contain all kinds of input fields. They then handle their own inputs, and "return" a generic data object, which the encoder can use. Internally, the views observe their inputs to update the data object, and externally the encoder needs only observe the data object.
Trouble is I have no idea how to make this all happen and keep it decoupled. Should there be an object controller between the input-view and its fields? Should there be another one between the view and the encoder? What do I need where? If anyone has a link to a good tutorial, please share.
Again, I can roll my own system of notifications and glue code, but I think the point is to avoid that.

Definitely a vague question, but one beginner to another, I feel your pain :)
I downloaded and unpacked every single example and grep through them frequently. I've found that to be the most valuable thing to get me over the hump. I definitely recommend not giving up on the examples. I hacked up this script to download and unpack them all.
In terms of good KVO patterns, I found the technique described here to be very useful. It doesn't work as-is in Objective-C 2.0 however. Also he doesn't give much detail on how it's actually used. Here's what I've got working:
The KVODispatcher.h like this:
#import <Foundation/Foundation.h>
#interface KVODispatcher : NSObject {
id owner;
}
#property (nonatomic, retain) id owner;
- (id) initWithOwner:(id)owner;
- (void)startObserving:(id)object keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
selector:(SEL)sel;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context;
#end
And the KVODispatcher.m is as so:
#import "KVODispatcher.h"
#import <objc/runtime.h>
#implementation KVODispatcher
#synthesize owner;
- (id)initWithOwner:(id)theOwner
{
self = [super init];
if (self != nil) {
self.owner = theOwner;
}
return self;
}
- (void)startObserving:(id)object
keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
selector:(SEL)sel
{
// here is the actual KVO registration
[object addObserver:self forKeyPath:keyPath options:options context:sel];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
// The event is delegated back to the owner
// It is assumed the method identified by the selector takes
// three parameters 'keyPath:object:change:'
objc_msgSend(owner, (SEL)context, keyPath, object, change);
// As noted, a variation of this technique could be
// to expand the data passed in to 'initWithOwner' and
// have that data passed to the selected method here.
}
#end
Then you can register to observe events like so:
KVODispatcher* dispatcher = [[KVODispatcher alloc] initWithOwner:self];
[dispatcher startObserving:theObject
keyPath:#"thePath"
options:NSKeyValueChangeNewKey
selector:#selector(doSomething:object:change:)];
And in the same object that executed the above, you can have a method like so:
- (void) doSomething:(NSString *)keyPath
object:(id)object
change:(NSDictionary *)change {
// do your thing
}
You can have as many of these "doSomething" type methods as you like. Just as long as they use the same parameters (keyPath:object:change:) it will work out. With one dispatcher per object that wishes to receive any number of notifications about changes in any number of objects.
What I like about it:
You can only have one observeValueForKeyPath per class, but you may want to observe several things. Natural next thought is "hey maybe I can pass a selector"
Oh, but it isn't possible to pass multiple arguments via performSelector unless wrapper objects like NSNotification are used. Who wants to clean up wrapper objects.
Overriding observeValueForKeyPath when a superclass also uses KVO makes any generic approaches hard -- you have to know which notifications to pass to the super class and which to keep.
Who wants to re-implement the same generic selector-based observeValueForKeyPath in every object anyway? Better to just do it once and reuse it.
A nice variation might be to add another field like id additionalContext to KVODispatcher and have that additionalContext object passed in the objc_msgSend call. Could be useful to use it to stash a UI object that needs to get updated when the observed data changes. Even perhaps an NSArray.

Related

Why use delegate and protocol instead of just passing an instance in Swift?

I was trying to pass around variables between views in Swift, and ran into the rather abstract concept of protocols and delegates.
Then I tried storing a reference to the first view in a second view and call functions on that directly. This seems to work:
SCREEN 1
class Screen1: UIViewController {
var myName = "Screen1"
override func viewDidLoad() {
super.viewDidLoad()
}
//
// checking if the segue to screen 2 is called and then passing a reference
//
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if segue.identifier == "screen2Segue"{
let vc = segue.destinationViewController as Screen2
vc.storedReference = self
}
}
func getName() -> String {
return myName
}
}
SCREEN 2
class Screen2: UIViewController {
var storedReference:Screen1!
override func viewDidLoad() {
super.viewDidLoad()
}
func testReference() {
// calling a function on the stored reference to screen 1
var str = storedReference.getName()
println("Leaving screen 2, going to " + str)
}
}
My question: what's wrong with this code? Why use delegates and protocols if you can just pass around a reference directly?
Perhaps related: when does a view get un-initialized and replaced by an entirely new view instance? Am I calling 'getName()' on an old instance?
Protocols are useful for separating implementation from interface, which helps increase code reusability, understandability, and testability.
For example, perhaps you wish to store items in a List of some sort. Some possible implementations of a List include array-based implementations and node-based (linked-list) implementations. If you were to declare a protocol called List and have classes ArrayList and LinkedList that implemented that protocol, anything that required the use of a list (variable passed as a parameter to a method, a property, etc) could use List as the variable type, and be able to function without caring about whether a the list was an ArrayList or a LinkedList. You could change which type was used, or how they were implemented, and it would not matter to whatever was using them, because only the exposed interface declared in the protocol would be visible.
Protocols can also be useful for emulating something like multiple inheritance, as a class can inherit from a superclass, as well as implement one or more interfaces. (eg. A bat is both a mammal and winged, so it could be represented as a Bat class inheriting from a Mammal class that implements the Winged protocol).
The delegate pattern uses protocols to delegate some responsibilities to another object, which is especially good for code separation and reusability. For example, the UITableViewDelegate protocol in iOS allows a UITableView to react to things like cell selection by delegating another object to handle the event. This has probably been used by millions of objects in thousands of applications, without the developers at Apple who implemented UITableView and UITableViewDelegate having ever known anything about the objects that were implementing the protocol.
By directly passing a reference between your view controllers, you are forcing the second to be completely dependent upon the first. If you ever wished to change the flow of your application so that the second view controller could be accessed from somewhere else, you would be forced to rewrite that view controller to use the new origin. If you use a protocol instead, no changes to the second view controller would have to be made.
It is a basic design principle to not expose any more of a design than you have to. By passing the reference around you are exposing the whole object. Which means that others can call any of its functions and access any of its properties. And change them. This isn't good. Besides letting others use the object in ways it might not have intended, you will also run into issues if you try to change the object in the future and find out that it breaks somebody else who was using something you didn't intend. So, always a good idea to not expose anything that you don't have to. This is the purpose of delegates and protocols. It gives the object complete control over what is exposed. Much safer. Better design.
I think you didn't fully get the understanding what protocols are.
I always say protocols are like contracts.
The delegate object that implements a certain protocols promises that it can do things the delegator can't do.
In real world I have a problem with my house's tubes.
I (the delegator) call a plumber (the delegate) to fix it. The plumber promises (by contract) to be able to duo it. The promise is the protocol. I don't care how he do it, as long as he does it.
But these contracts are not only useful for delegation.
I am just writing a food ordering app. As it has a menu it need item to display in it.
I could go with basic inheritance and write a class MenuItem, that all sub classes must inherit from.
Or I write an protocol to express: «No matter what object you are, as long as you fulfill this contract we have a deal». this allows me to create many different classes or annotate existing classes in categories, although I don't have the tool of multiple inheritance.
Actually I do both: I write a protocol MenuItem and a class MenuItem that conforms to the protocol. Now I can use simple inheritance or use classes that do not inherit from the class MenuItem.
Code in Objective-C (sorry: I am still transitioning to Swift)
#protocol MenuItem <NSObject>
-(NSString *)name;
-(double) price;
-(UIColor *)itemColor;
#end
#interface MenuItem : NSObject <MenuItem>
#property (nonatomic, copy) NSString *name;
#property (nonatomic, assign) double price;
#property (nonatomic, strong) UIColor *itemColor;
#end
#import "MenuItem.h"
#implementation MenuItem
-(id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self) {
self.name = [decoder decodeObjectForKey:#"name"];
self.price = [decoder decodeDoubleForKey:#"price"];
self.itemColor = [decoder decodeObjectForKey:#"itemColor"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeDouble:self.price forKey:#"price"];
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeObject:self.itemColor forKey:#"itemColor"];
}
#end
Apple uses the same Architecture for NSObject: there is a protocol and a class NSObject. This allows classes, that aren't intact inheriting from the class NSObject to act ash an NSObject. One famous example:NSProxy.
in your case Screen1 promises to be able to understand messages that are send by the detail view controller Screen2. These allows decoupling: any object that does understand Screen1's protocol can be used. Also it helps to maintain a sane object tree, as we don't have to have circular imports. But in general you have to keep in mind that the delegator (Screen2) must keep a weak reference to it's delegate, otherwise we have a retain circle.
Of course an important example it UITableView:
The table view object knows everything about rendering it's cells, handling scrolling and so one. But the engineer who wrote it couldn't now how you want your table view look like. That's why he introduced a delegate to give you the chance to create the right cell. As he couldn't also know what your data looks like, he also introduced the datasource - that works exactly like a delegate: you will be asked to provide all information about your data, that are needed.
This is mostly a matter of opinion so this question should probably be closed, but I think the developer community as a whole is in an agreement on this so I am going to answer it anyway.
An important concept in Software Architecture (the design of the structure of code) is called Separation of Concerns. The basic principle is that you should break down what your code has to do into small components that only have one distinct purpose. Each of these components should be able to stand mostly on their own without much concern with other components other than the ones it needs to directly be interacting with.
This helps greatly with code reuse. If you design a small component that is independent of most / if not all other components, you can easily plug that into other parts of your code or other applications. Take UITableView for example. By using the delegate pattern, every developer can easily create a table view and populate it with whatever data they want. Since that data source is a separate object (with the separate concern of coming up with the data) you can attach that same data source to multiple table views. Think of a contact list on iOS. You will want to access that same data in many ways. Instead of always rewriting a table view that loads the specific data and displays it in a specific way, you can reuse the data source with a different table view as many times as you want.
This also helps with the understandability of your code. It is tough for developers to keep too many thing in their head about the state of your app. If each of your code components are broken down into small, well defined responsibilities, a developer can understand each component separately. They can also look at a component, and make accurate assumptions about what it does without having to look at the specific implementation. This isn't such a big deal with small apps, but as code bases grow, this becomes very important.
By passing in a reference to your first view controller, you are making your second view controller completely dependent on the first. You cannot reuse the second view controller in another instance and its job becomes less clear.
There are lots of other benefits to separation of concerns but I believe those are two compelling and important ones.
I think the problem with the latter arises with multiple reuse of a single class.
Take for example a custom UITableViewCell called CustomTableViewCell. Let's say you have Class A and Class B which both have tableViews and both would want to use CustomTableViewCell as their cell. You now have two options. Would you rather:
A. Use a delegate/protocol for CustomTableViewCell called CustomTableViewCellDelegate. Declare a single object inside the class CustomTableViewCell named "delegate" which implements the mentioned protocol and call on that regardless of what class it calls on
or
B. Declare an object for each class (Class A, Class B) inside CustomTableViewCell so you can hold a reference to each of them.
If you need to use CustomTableViewCell for a number of classes, then I think you know which option to take. Declaring multiple objects for different classes inside CustomTableViewCell would be a pain to see from a software architecture standpoint.

sending data back to the main ViewController xcode

I am attempting to send back data from a second view controller named "waitViewController" to the main ViewController. I am using the same method as i used to send data from the first to the second only in reverse. The problem is xcode wont allow me to use ViewController in the waitViewController.h but instead wants me to write UIViewController. How do I fix this?
What i want it to be:
The errors its giving me:
Might be that you need to use an '#class' instead of '#import ViewController.h'
So replace that import statement with:
#class ViewController;
You need this if two classes depend on each other for their definitions, as your two view controller classes seem to do.
If you end up using an #class, you have to then import 'ViewController.h' in your implementation file. the #class prevents an infinite loop of (otherwise) co-dependent class definitions. As I understand it, #class means "this class "SomeClass" exists, so don't worry about it, even though I'm not going to import its interface just yet."
EDIT:
By the way, I feel like I should mention that #class is a hack and there's another, more elegant solution: a (formal or informal) protocol. To use a formal protocol: put a protocol definition at the top of 'WaitViewController.h':
#protocol WaitControllerDelegate
-(void) useThisNewData: (NSWhateverDataType *) theData;
- (void) useThisOtherData:(SomeOtherDataType) otherData;
#end
In the WaitViewController interface, don't define 'turnData' as type 'ViewController *'. Instead define it as type "id ":
#property (nonatomic, assign) id <WaitControllerDelegate> turnDataDelegate;
(Note that you use 'assign' instead of 'retain' under the assumption that ViewController owns a 'retain' reference to WaitViewController and you don't want two objects that have strong references to each other--they'll create a 'retain loop', i.e. will mutually never allow each other to deallocate.)
In the WaitViewController implementation file, whenever you need to send back data, call
[turnDataDelegate useThisNewData: someData];
In ViewController.h, announce that you're adopting the 'WaitControllerDelegate' protocol:
#interface ViewController : UIViewController <WaitControllerDelegate> {
Then, in ViewController.m implement the 'WaitControllerDelegate' methods, just like you would any other methods, but you don't have to declare them in the interface:
- (void) useThisNewData: (NSWhateverDataType *) theData {
...do whatever you want
}
This approach involves a little more work but is better because it allows the 'WaitViewController' class to be more self contained and, in general, in theory, makes your classes more reusable.

Is passing a controller in a construtor always a bad practice?

I occasionally instantiate a class from my view controller by passing in the view controller instance itself so that the objects that I create can invoke methods of the controller to update the view.
Is that always, often, or never a bad practice?
Concretely:
ViewController.h has
-(void)updateButtonValue:(NSString*)value;
MyObject.h has
-(id)initWithViewController:(ViewController*)aViewController;
I instantiate that class from my view controller with:
[[MyObject alloc] initWithViewController:self];
thus allowing that MyObject instance to update a button value in my view by a simple call like:
MyObject.m
[self.viewController updateButtonValue:#"example"];
It does not seem ideal since I am passing to MyObject much more (the view controller itself) than it should need, but it is certainly quick and functional. If there is a cleaner approach, such as relying on protocols, that is also succinct, a brief code sample would be much appreciated.
It is always bad practice to pass a class-typed pointer in, as you are tightly coupling your objects together (each object needs to know the class of the other, they might as well be a single object). This is what the delegate pattern is for. It minimises the info MyObject needs (minimally, nothing more than a pointer type id - preferably, a protocol specified by MyObject to offer it some behavioural guarantees)
So to translate your example
MyObject.h
replace...
-(id)initWithViewController:(ViewController*)aViewController;
with...
-(id) init;
(which you can dispense with if you have no further reason to override)
and...
#property (nonatomic, weak) id delegate;
Instantiation in myViewController (which does need to #include MyObject) ...
MyObject* object = [[MyObject alloc] init];
Followed by
object.delegate = self;
(Note that object gets a pointer to myViewController without needing to know anything else about it)
Now you can do this from inside object:
[self.delegate updateButtonValue:#"example"];
However ... you will want to ensure that your delegate can receive the message updateButtonValue:
To do this, you declare a protocol in MyObject.h with the signature of this method
#protocol MyObjectDelegate
- (void) updateButtonValue:(NSString*)string;
#end
And in your viewController, declare that you conform to this protocol using <> in the interface line
#interface ViewController <MyObjectDelegate>
(this is no big deal, ViewController already has to #include MyObject to alloc/init it, so needs no more info to do this)
And expand your property declaration thus:
#property (nonatomic, weak) id <MyObjectDelegate> delegate
Now you have given the compiler enough information for it to ensure that you can only pass conformant messages around. The brilliant thing here is that MyObject can confidently pass messages to MyViewController without needing to know anything about MyViewController other than that it is reached via the delegate pointer.

Accessing an NSMutableArray inside my custom object

I'm sure this is an complete Noob question... but I've actually never had to deal with this scenario before so I'm a bit befuddled...
Let's say I have a custom object I'll call person, and each person object can have an array of "possessions", a kind of inventory if you will. I would set it up like this:
interface person : NSObject {
NSString *name;
NSMutableArray *posessions;
#property (copy) NSString *name;
#property (copy) NSMutableArray *posessions; // no idea if this is even necessary...
}
Of course, I would also synthesize my properties in the implementation file... Now, in my actual controller object, I would make an instance of my object (or usually an array of instances, but for this example, one will work fine...) as so:
person *aPerson;
I know that to access the persons name, I could make a call like this:
[aPerson setName:#"Bob"];
and to retrieve that name, I might use this:
aVar = [aPerson name];
What I'm stuck on is how exactly would I go about adding or retrieving objects to the NSMutableArray located inside my person class? Let's say I want to use the "count" method for the NSMutable Array.
I've done some trial and error with attempts such as:
[aPerson.posessions count];
[[aPerson posessions] count];
Likewise, to add an object to an array, I have often used:
[someArray addObject:anObject];
but attempts like this haven't worked:
[aPerson.posessions addObject:anObject];
After reading up a bunch and searching the web, I can't seem to find exactly how to interact with this NSMutableArray in my custom class. I'm sure it's something obvious that I'm just not quite getting, and it's become a sort of mental block...
Also, am I correct in synthesizing accessor properties for the NSMutableArray? If so, setX and X don't seem to be quite so obvious with NSMutableArray... unless they simply copy the entire array into a local variable...
Perhaps is this what needs to be done? use the accessor methods to get the entire array, place it in a local variable, make my changes, then use the set accessor method to put the entire array back into my person object?
Can someone enlighten me a bit on the syntax I should be using here?
* EDIT *
I thought I'd add a bit of clarification to this question. My custom objects (in the above example, my person object) are basically database records. I have several databases I am working with in my project, so for example:
Person - a custom sub-class of NSObject containing multiple NSString Objects, as well as Ints and BOOLs.
personDatabase - An Array of Person objects (set up and controlled within my main CONTROLLER object)
All of the set and get methods are called from "Controller".
What I have been attempting to do is to directly access the individual objects contained within the personDatabase from within my Controller object. I have done this by declaring another object this way:
Person *activePerson;
Then, all of my calls are made to the currently active Person record (the one currently selected from the personDatabase), such as:
someOutput = [activePerson name];
etc.
Is there a way to directly access the objects inside the NSMutableArray object inside the activePerson object from my Controller object?
You've specified the 'possessions' property as 'copy'. Therefore, when you write aPerson.possessions you are getting a copy of the possessions array. The call to addObject adds anObject to a new array that is a copy of aPerson's array of possessions. The simplest 'fix' would be to change 'copy' to 'retain' (and probably 'readonly'). [Edit: Wrong; it is 'copy on assign' - not 'copy on read']
However, there is a bigger issues. A person has possessions but how you store them is an implementation detail. When you put NSMutableArray in the public interface you overly restrict your implementation. You might be better served to change the Person interface along the lines of:
#interface Person : NSObject {
#private
NSString *name;
// ...
}
- (Boolean) addPossession: (NSObject *) obj;
- (Boolean) remPossession: (NSObject *) obj;
- (Boolean) hasPossession: (NSObject *) obj;
- (NSArray *) allPossessions;
#end
Then, how you implement these possession methods depends on if you use an array, a set, a linked-list, a tree, a whatever.

Understanding and Reproducing the KVC Hillegass Way to Insert/Remove Objects in/from Controllers

In Aaron Hillegass' Cocoa Programming for Mac OS X, the Raiseman application connects a button in Interface Builder (IB) to an NSArrayController with sent action -remove:. In the MyDocument class he implements two KVC methods:
- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index;
- (void)removeObjectFromEmployeesAtIndex:(int)index;
When this button is pressed, the -removeObjectFromEmployeesAtIndex: method is called and the currently selected Person (Model) object is removed from the array.
How does the remove: method used in IB cause the -removeObjectFromEmployeesAtIndex: method to be called?
How do I reproduce this effect with an NSTreeController?
If you want a simple built-in option, then it's only going to create an instance of the class you specified in IB. To create another instance, you're going to need to code it yourself. You should have all the information you need from the Tree Controller to insert the new class into the proper place in the hierarchy. Some diligent searching should give you the code you need.
To attempt to help you understand how the NSArrayController mechanism works, I'll explain the best I can from my knowledge of Objective-C and the runtime. Objective-C is a very dynamic language, and you can dynamically call selectors (methods). Since the NSArrayController knows the name of your class (e.g. "Employee"), its internal implementation probably looks something like the following (or easily could):
NSString *removeSelectorName = [NSString stringWithFormat:#"removeObjectFrom%#sAtIndex:",
self.objectClassName];
SEL removeSelector = NSSelectorFromString(removeSelectorName);
[dataRepresentation performSelector:removeSelector
withObject:[NSNumber numberWithInt:self.selectionIndex];
There are examples of this elsewhere in KVO, as with the +keyPathsForValuesAffecting<Key> method (documentation here), which describes which keys cause another key to be updated. If your key is named fullName and it updates whenever the first or last name changes, you would implement this in your class:
+ (NSSet *)keyPathsForValuesAffectingFullName {
return [NSSet setWithObjects:
#"firstName",
#"lastName",
nil];
}
Further searching (and this question) turned up this documentation page, which explains the semantics of how that method gets called.

Resources