PDA

View Full Version : Using Introspection Properly?




ArtOfWarfare
Jul 15, 2011, 11:08 PM
I have a class that interprets accelerometer data (which makes it the model, right?) and then passes some info to the controller, whom it shouldn't know anything about beyond that it's an NSObject.

For example, in this code, the accelerometer interpreter determines that the device was moved abruptly enough to send a message to the controller:
if ((zData - lastStoredZData < -0.10) && ([controller respondsToSelector:@selector(pressUp)]))
{
[controller pressUp];
}
lastStoredZData = zData;

The issue is, xCode is giving me a warning that "Method '-pressUp' not found".

But I've already made sure that the controller has such a method before I tell it to run it. The app runs fine, but I'd rather make sure xCode doesn't give me false warnings, so I want to make sure, am I using introspection properly? I figure that having the accelerometer interpreter import the controller is a poor programing choice, because then it becomes too tightly integrated into this program and can't be as easily integrated into another program in the future (or if I decided to make it possible to change within this program which controller the accelerometer interpreter sends its data to.)

Edit: I just changed [controller pressUp]; to [controller performSelector:@selector(pressUp)]; which removed the compiler warning... is this actually somehow better?



jiminaus
Jul 15, 2011, 11:41 PM
[obj msg] and [obj performSelector:@selector(msg)] are pretty much the same thing. The former is likely to execute faster than the later, but that wouldn't matter in this case. It also becomes more cumbersome to use the later with many arguments, and you loose the compiler type checking of those arguments.

In the ideals of MVC, a model object should never have a connection from model to controller, even if it's a typeless connection. Instead, if a change happens in a model object that the controllers might want to react to, the model object should either use Key-Value Observing or broadcast a notification using NSNotificationCenter. Any interested controllers would have set themselves up to be notified of the change or notification.

In your case, this is an classic case for notification. To implement this the code in the model would be:

if (zData - lastStoredZData < -0.10) {
[[NSNotificationCenter defaultCenter]
postNotification:@"AbruptMovement"];
}
lastStoredZData = zData;


In your controller, you setup to observe the notification like so:

[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(pressUp:)
name:@"AbruptMovement"
object:nil];

And then:

- (void)pressUp:(NSNotification *)aNotification
{
}

Sydde
Jul 15, 2011, 11:49 PM
There are several ways to achieve the modularity you desire. First, you could define a protocol that your motion controller's client must conform to. That way, you will have a standardized set of methods to plug subsequent clients inti without the motion controller having to know anything else about the client.

Alternately, you could have the client supply selectors to the controller (@properties) for it to call.

In the first case, everything is cleanly defined and each object knows what to expect in the message passing. In the second case, the client object has the option of specifically directing messages to certain methods, depending on current circumstances, by setting the selector properties.

Note that a selector is a numerical value type, so 0 can be tested for, in case the client wants no message to be sent.