In the book The Pragmatic Programmer, the authors suggest that all method inputs should be validated. This allows problems with a method to be caught early and their sources traced easily.
In my Mac application, I accomplished this by creating an Assert class. This class has several class methods. These methods determine if some precondition is met, and if it is not, then an exception is thrown. A typical assertion might looks something like this:
-(void) setWidth: (int) theWidth {
[Assert integer: width isGreaterThanInteger: 0];
width = theWidth;
}
This works really well, and significantly reduced the amount of time I've spend bug hunting. However, I've noticed lately some of the assertion methods are very useful as predicates. For example, my integer:isGreaterThanInteger:andLessThanInteger: and my stringIsNotEmpty: methods are equally useful. To this end, I created a second class Predicate, which I filled with several of my more useful predicate methods. So I took the logic from the assert methods, and moved it into Predicate, and then rewrote my Assert methods like the following:
if ![Predicate predicateMethod]
throw exception
This has turned into a maintenance nightmare. If I change the name of a method name in Predicate, I must also change it in Assert to stay consistent. If I update the documentation of an Assert method, then I must do the same to a Predicate method.
Ideally, I would like the reconstruct the Assert class so that when any method is called on it, it intercepts the selector. The Predicate class can then be checked to see if it responds to the selector, and if it does, the method is called on Predicatewith the same arguments that were passed into the Assert method. If the Predicate method returns false, then an exception is thrown.
Is there a way to do this in Objective-C?
Thanks.
You could use -forwardingTargetForSelector: to simply forward the method to another object, but if you want advanced behavior (like checking the return value to see if it's false), you may need to use -forwardInvocation:. (However, note that the documentation says this is "much more expensive" than the former option.)
If you're using pure Objective-C, you should see the "Forwarding" discussion here. It basically describes how to do exactly what you want, including example code.
If you're using Cocoa then you might have to use forwardInvocation: instead.
I ended up overriding resolveClassMethod:. While overriding forwardInvocation might have worked (I would have had to figure out some way to override it for the class object), resolveClassMethod: seems like it's the easier and more efficient method. Here's what my final implementation ended up looking like:
#import "Assert.h"
#import "Predicate.h"
#include <objc/objc-runtime.h>
void handlePredicateSelector(id self, SEL _cmd, ...);
#implementation Assert
+(void) failWithMessage: (NSString *) message
{
NSLog(#"%#", message);
[NSException raise:#"ASSERTION FAILURE" format:message];
}
+(void) fail
{
[Assert failWithMessage:#"An unconditional failure has been detected."];
}
+(BOOL) resolveClassMethod: (SEL) selector
{
if ([(id) [Predicate class] respondsToSelector:selector])
{
/*
The meta class fix was taken from here: http://iphonedevelopment.blogspot.com/2008/08/dynamically-adding-class-objects.html
*/
//get the method properties from the Predicate class
Class predicateMetaClass = objc_getMetaClass([[Predicate className] UTF8String]);
Method predicateMethod = class_getClassMethod(predicateMetaClass, selector);
const char *encoding = method_getTypeEncoding(predicateMethod);
Class selfMetaClass = objc_getMetaClass([[self className] UTF8String]);
class_addMethod(selfMetaClass, selector, (IMP) handlePredicateSelector, "B#:?");
return YES;
}
return [super resolveClassMethod:selector];
}
#end
void handlePredicateSelector(id self, SEL _cmd, ...)
{
//get the number of arguments minus the self and _cmd arguments
NSMethodSignature *predicateMethodSignature = [(id) [Predicate class] methodSignatureForSelector:_cmd];
NSUInteger numberOfArguments = [predicateMethodSignature numberOfArguments] - 2;
NSInvocation *predicateInvocation = [NSInvocation invocationWithMethodSignature:predicateMethodSignature];
[predicateInvocation setTarget:[Predicate class]];
[predicateInvocation setSelector:_cmd];
va_list ap;
va_start(ap, _cmd);
for (int i = 0; i < numberOfArguments; i++)
{
void *arg = va_arg(ap, void *);
[predicateInvocation setArgument:&arg atIndex:i+2];
}
va_end(ap);
BOOL returnValue;
[predicateInvocation invoke];
[predicateInvocation getReturnValue:&returnValue];
//determine if the assertion is true
if (!returnValue)
{
[Assert failWithMessage:[NSString stringWithFormat: #"The following assertion failed: %#", NSStringFromSelector(_cmd)]];
}
}
The only thing I couldn't really figure out was how to get the type encoding from the method signature. It didn't seem to affect the output of the methods, but I would like to fix it if I can.
Related
Using OCMockito and OCHamcrest, I can set up expectations on the arguments to mocked methods, thusly:
[verify(aMockObject) doSomething:allOf(is(instanceOf([NSArray class])), hasCountOf(3U), nil)];
There doesn't seem to be an equivalently simple way to do this using Kiwi. It is possible to capture arguments using a spy, something like:
KWCaptureSpy *spy = [aMockObject captureArgument:#selector(doSomething:) atIndex:0];
NSArray *capturedArray = spy.argument;
And then to check expectations on the captured object:
[[capturedArray should] haveCountOf:3U];
Is there a less clumsy way to do this in Kiwi?
(I'm aware I could probably use hamcrest matchers in here, but for the moment I'm exploring what Kiwi is capable of).
One option that I have used is stub:withBlock:
NSArray* capturedArray; // declare this as __block if needed
[aMockObject stub:#selector(doSomething:)
withBlock:^id(NSArray *params) {
capturedArray = params[0];
// this is necessary even if the doSomething method returns void
return nil;
}];
// exercise your object under test, then:
[[capturedArray should] haveCountOf:3U];
This works fine, and I find it easier to implement than the spy pattern. But your question made me wonder about expectations using message patterns. For example:
[[[aMockObject should] receive] doSomething:myArray];
[[[aMockObject should] receive] doSomething:any()];
The first example will verify that aMockObject received the doSomething: message with an argument that isEqual:myArray. The second example will simply verify that doSomething: was sent, with no expectation about the array arugment. It would be great if we can specify some type of Matcher in the message pattern, to express that we don't care what specific array instance is sent in the message, just that it has a count of 3.
I haven't found any examples of being able to do this, but it looks like there are some possibilities. To verify a message-sending expectation, Kiwi uses the KWMessagePattern class, specifically the matchesInvocation: and argumentFiltersMatchInvocationArguments: methods. This checks for three types of "argument filters":
Literal object values (such as myArray in the example above), which are compared to the actual value sent in the message using isEqual:
An object of type KWAny (such as the any() macro in the example above), which will match any argument value
Objects that satisfy [KWGenericMatchEvaluator isGenericMatcher:argumentFilter], which basically means that the object responds to matches:(id)obj
Thus, you should be able to use objects that implement matches: in message-pattern expectations to do things like verify the length of arrays sent to stubbed methods, without resorting to spys or blocks. Here's a very simple implementation: (available as a Gist)
// A reusable class that satisfies isGenericMatcher:
#interface SOHaveCountOfGenericMatcher : NSObject
- (id)initWithCount:(NSUInteger)count;
- (BOOL)matches:(id)item; // this is what KWMessagePattern looks for
#property (readonly, nonatomic) NSUInteger count;
#end
#implementation SOHaveCountOfGenericMatcher
- (id)initWithCount:(NSUInteger)count
{
if (self = [super init]) {
_count = count;
}
return self;
}
- (BOOL)matches:(id)item
{
if (![item respondsToSelector:#selector(count)])
return NO;
return [item count] == self.count;
}
#end
// Your spec:
it(#"should receive an array with count 3", ^{
NSArray* testArray = #[#"a", #"b", #"c"];
id argWithCount3 = [[SOHaveCountOfGenericMatcher alloc] initWithCount:3];
id aMockObject = [SomeObj nullMock];
[[[aMockObject should] receive] doSomething:argWithCount3];
[aMockObject doSomething:testArray];
});
It would be nice to be able to reuse Kiwi's built-in matcher classes here, but I haven't yet found out exactly how to do this.
Is it possible to create an Objective-C class that can have an arbitrary number of dynamic properties at runtime?
I want to be able to call mySpecialClass.anyProperty and intercept this inside my class to be able to provide my own custom implementation that can then return an NSString (for instance) at runtime with raising an exception. Obviously this all has to compile.
Ideal would be if I could refer to my properties using something similar to the new literal syntax, e.g. mySpecialClass["anyProperty"].
I guess in a way I want to create something like a dynamic NSDictionary with no CFDictionary backing store, that executes 2 custom methods on property getting and setting respectively, with the property name passed in to these accessor methods so they can decide what to do.
There are at least two ways to do this.
Subscripting
Use objectForKeyedSubscript: and setObject:forKeyedSubscript:
#property (nonatomic,strong) NSMutableDictionary *properties;
- (id)objectForKeyedSubscript:(id)key {
return [[self properties] valueForKey:[NSString stringWithFormat:#"%#",key]];
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key {
[[self properties] setValue:object forKey:[NSString stringWithFormat:#"%#",key]];
}
Person *p = [Person new];
p[#"name"] = #"Jon";
NSLog(#"%#",p[#"name"]);
resolveInstanceMethod:
This is the objc_sendMsg executed by the runtime for all methods:
If you look at the bottom, you have the opportunity to resolveInstanceMethod:, which lets you redirect the method call to one of your choosing. To answer your question, you need to write a generic getter and setter that looks-up a value on a dictionary ivar:
// generic getter
static id propertyIMP(id self, SEL _cmd) {
return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}
// generic setter
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
id value = [aValue copy];
NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];
// delete "set" and ":" and lowercase first letter
[key deleteCharactersInRange:NSMakeRange(0, 3)];
[key deleteCharactersInRange:NSMakeRange([key length] - 1, 1)];
NSString *firstChar = [key substringToIndex:1];
[key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar lowercaseString]];
[[self properties] setValue:value forKey:key];
}
And then implement resolveInstanceMethod: to add the requested method to the class.
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) hasPrefix:#"set"]) {
class_addMethod([self class], aSEL, (IMP)setPropertyIMP, "v#:#");
} else {
class_addMethod([self class], aSEL,(IMP)propertyIMP, "##:");
}
return YES;
}
You could also do it returning a NSMethodSignature for the method, which is then wrapped in a NSInvocation and passed to forwardInvocation:, but adding the method is faster.
Here is a gist that runs in CodeRunner. It doesn't handle myClass["anyProperty"] calls.
You're asking different things. If you want to be able to use the bracket syntax mySpecialClass[#"anyProperty"] on instances of your class, it is very easy. Just implement the methods:
- (id)objectForKeyedSubscript:(id)key
{
return ###something based on the key argument###
}
- (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key
{
###set something with object based on key####
}
It will be called everytime you use the bracket syntax in your source code.
Otherwise if you want to create properties at runtime, there are different ways to proceed, take a look at NSObject's forwardInvocation: method, or look at the Objective-C Runtime Reference for functions to dynamically alter a class...
Guillaume is right. forwardInvocation: is the way to go. This answer gives some more details: method_missing-like functionality in objective-c (i.e. dynamic delegation at run time)
This has even more details: Equivalent of Ruby method_missing in Objective C / iOS
And these are some other lesser known Obj-C features that might help you: Hidden features of Objective-C
Enjoy!
In C# you can create a delegate method, assign it to a variable or pass it into a method as if it were a variable. For example:
public delegate int Lookup(String s);
//...
public static int Evaluate(String exp, Lookup variableEvaluator)
{
//...
}
I heard that in C you can create a pointer to any method and then pass that pointer to a method.
Can anyone give me a simple example of doing that in Objective-C? Of course, I can create an object with a singe method and pass that object into a method. But I am curious if there is a way of doing that similar to that of C# or C.
Lots of ways.
One: the good. Use blocks (closures, lambda calculus, however you call it):
typedef void (^MyCallback)();
- (void)callTheCallback:(MyCallback)blockToInvoke
{
blockToInvoke();
}
MyCallback cb = ^{
NSLog(#"I was called! :D");
};
[self callTheCallback:cb];
Two: the bad. Grab a pointer to the method function itself and call that. (Warning: if you use this approach, I'll sue you.)
- (void)callTheCallback:(IMP)funcPtrToCall withObject:(id)obj selector:(SEL)sel
{
funcPtrToCall(obj, sel);
}
- (void)someCallbackMethod
{
NSLog(#"I was called! :D");
}
IMP implemt = [[self class] instanceMethodForSelector:#selector(someCallbackMethod)];
[self callTheCallback:implemt withObject:self selector:#selector(someCallbackMethod)];
Three: the ugly. Use a delegate:
- (void)delegateMethodOfSomeObject:(SomeObject *)obj
{
NSLog(#"I was called! :D");
}
SomeObject *obj = [[SomeObject alloc] init];
obj.delegate = self;
[obj makeThisObjectSomehowCallItsDelegateThatIsCurrentlySelf];
Two quick thoughts come to mind.
The short answer is called "blocks", but it's lower level than is probably recommended for what you need.
The "cleaner" solution (read: higher level) is to pass two params: and object (called "target") and a selector (called "action"). This is a very common pattern in Objective-C, so I'll only demonstrate this one. If you are interested in the blocks idea, check out this doc.
Essentially, the object should be passed as an id, and the selector as a SEL, for which we have the handy #selector() construct:
-(void) doThingWithTarget:(id) targetObj action:(SEL) actionSel {
if([targetObj respondsToSelector:actionSel]) {
[targetObj performSelector:actionSel withObject:self];
}
}
// ...
[thatOtherObject doThingWithTarget:self action:#selector(myMethod:)];
// ... where
-(void) myMethod:(id) sender {
// sender is the calling object, or should be by contract.
}
Objective C uses selectors. http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocSelectors.html
Does anyone know why NextStep/Apple decided to take the "convenient method" of doing nothing when passing a Nil object a message, but the "Java method" of raising an exception when passing an instantiated object an invalid selector?
For example,
// This does "nothing"
NSObject *object = Nil;
[object thisDoesNothing];
object = [[NSObject alloc] init];
// This causes an NSInvalidArgumentException to be raised
[object thisThrowsAnException];
So on one hand, we have the convenience of not having to check for Nil (assuming we don't care too much about the result of the method call)--but on the other hand we have to check for an exception if our object doesn't respond to a method?
If I'm not sure if the object will respond, I either have to:
#try {
[object thisThrowsAnException];
} #catch (NSException *e){
// do something different with object, since we can't call thisThrowsAnException
}
Or,
if([object respondsToSelector:#selector(thisThrowsAnException)]) {
[object thisThrowsAnException];
}
else {
// do something different with object, since we can't call thisThrowsAnException
}
(The latter is probably the better way to do it, since if object is Nil, the selector would NOT raise an exception, thus your code might not behave the way you want it to).
My question is:
WHY did Apple decide to implement it this way?
Why not have the unrecognized selector call to an instantiated object not raise an exception?
Alternatively, why not have the Nil object raise an exception if you try to call a method on it?
I can't fully answer your question, but I can answer part of it. Objective-C allows you to send a message to nil because it makes code more elegant. You can read about this design decision here, and I will steal its example:
Let's say you want to get the last phone number that some person dialed on her office phone. If you can't send messages to nil, you have to write it like this:
Office *office = [somePerson office];
// Person might not have an office, so check it...
if (office) {
Telephone *phone = [office telephone];
// The office might not have a telephone, so check it...
if (phone) {
NSString *lastNumberDialed = [phone lastNumberDialed];
// The phone might be brand new, so there might be no last-dialed-number...
if (lastNumberDialed) {
// Use the number, for example...
[myTextField setText:lastNumberDialed];
}
}
}
Now suppose you can send messages to nil (and always get nil back):
NSString *lastNumberDialed = [[[somePerson office] telephone] lastNumberDialed];
if (lastNumberDialed) {
[myTextField setText:lastNumberDialed];
}
As for why sending an unrecognized selector to an object raises an exception: I don't know for sure. I suspect that it's far more common for this to be a bug than to be harmless. In my code, I only want an unrecognized selector to be silently ignored when I need to send an optional protocol message (e.g. sending an optional message to a delegate). So I want the system to treat it as an error, and let me be explicit in the relatively rare case when I don't want it to be an error.
Note that you can tinker (to some extent) with the handling of unrecognized selectors in your own classes, in a few different ways. Take a look at the forwardingTargetForSelector:, forwardInvocation:, doesNotRecognizeSelector:, and resolveInstanceMethod: methods of NSObject.
From the good ol' documentation:
In Objective-C, it is valid to send a message to nil—it simply has no
effect at runtime.
As for the other problem of the unrecognized selector behavior, an old implementation file of NSObject (from the MySTEP library) shows that the culprit is the NSObject method -doesNotRecognizeSelector:, which looks a bit as follows:
- (void) doesNotRecognizeSelector:(SEL)aSelector
{
[NSException raise:NSInvalidArgumentException
format:#"NSObject %#[%# %#]: selector not recognized",
object_is_instance(self)?#"-":#"+",
NSStringFromClass([self class]),
NSStringFromSelector(aSelector)];
}
Which means that ObjC methods could feasibly be tinkered with so that they do not in fact have to raise an error. Which means the decision was entirely arbitrary, just like the decision to switch to "method-eating" messages to nil. A feat which can be done through method swizzling NSObject (wholly dangerous, as it will raise an EXC_BAD_ACCESS, or EXC_I386_BPT on mac, but at least it doesn't raise an exception)
void Swizzle(Class c, SEL orig, SEL new)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
}
-(void)example:(id)sender {
Swizzle([NSObject class], #selector(doesNotRecognizeSelector:), #selector(description));
[self performSelector:#selector(unrecog)];
}
The category:
#implementation NSObject (NoExceptionMessaging)
-(void)doesNotRecognizeSelector:(SEL)aSelector {
NSLog(#"I've got them good ol' no exception blues.");
}
#end
For everyone's amusement, due to the discussion CodaFi and I were having, here's a quickly-hacked-together way to eat normally unresponded-to messages and have them return nil:
#interface EaterOfBadMessages : NSObject
#end
#implementation EaterOfBadMessages
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature * sig = [super methodSignatureForSelector:aSelector];
if( !sig ){
sig = [NSMethodSignature signatureWithObjCTypes:"##:"];
}
return sig;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
id nilPtr = nil;
[anInvocation setReturnValue:&nilPtr];
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
EaterOfBadMessages * e = [[EaterOfBadMessages alloc] init];
// Of course, pre-ARC you could write [e chewOnThis]
NSLog(#"-[EaterOfBadMessages chewOnThis]: %#", [e performSelector:#selector(chewOnThis)]);
}
return 0;
}
Please don't use this in real life.
I'd like (at runtime) to bind a parameter to a function as you can do in boost::bind - a little like the following:
-(void)myFuncWithParameter:(NSString*)param {
NSLog(param);
}
-(void)init {
UIButton *helloButton = [UIButton buttonWithType:UIButtonTypeCustom];
[helloButton addTarget:self action:#selector(myFuncWithParameter:#"hello") forControlEvents:UIControlEventTouchUpInside];
}
So... I'm dynamically binding (at runtime) the value #"hello" to a parameter.
Obviously the above isn't the correct Syntax. Does anyone know if this is possible and the correct syntax?
Cheers,
Nick.
The short answer is no, or at least not at that level.
The long answer is that it is technically possible to build something akin to using NSInvocations (and/or forwardInvocation:), doing something clever in methodForSelector: and or by dynamically registering method implementations, but it is very tricky, especially if you care at all about speed.
If I had some code where building curried methods like that was really worthwhile, what I would do is something like this (written in this comment, untested);
//FIXME: In a real implementation you would do some mangling, this code will get confused if you have _s in the curried selector, and thus could be exploitable
//This method makes a unique selector by mangling the arguments
- (SEL) selectorForSelector:(SEL)bindSel withString:(NSString *)bindString {
NSString *mangle = [NSString *stringWithFormat:#"LGBind_%#_%#"], NSStringFromSelector(bindSel), bindString];
SEL retval = NSSelectorFromString(mangle);
//Register the imp. You probably want to check if it is already reg
if (![self respondsToSelector:retval]) {
class_addMethod([self class], retval, LGBind_IMP, "v#:")l
}
}
//Generic dispatcher imp
void LGBind_IMP(id self, SEL _cmd) {
NSString *selectorName = NSStringFromSelector(_cmd);
NSArray *array [selectorName componentsSeparatedByString:#"_"];
//Skip index 0; it is #"LGBind"
NSString *originalSelectorString = [array objectAtIndex:1];
NSString *originalArgString = [array objectAtIndex:2];
//Get our the SEL and the IMP
SEL originalSEL = NSSelectorFromString(originalSelectorString);
IMP originalIMP = [self methodForSelector:originalSEL];
//call the original imp
originalIMP([self class], originalSEL, originalArgString);
}
Obviously depending on your exact needs you could do things somewhere differently, for instance you could lazily by the imps in forwardInvocation, or stash data about the managled selector in a dict in the instance instead of just managling it into the selector name.
The general answer is that the target-action mechanism only allows for a target, a sender and a message that takes the sender; therefore, if you need to access data, you must get it from the target or the sender.
One option would be to create a class that represents the binding of a parameter value, a method and an object. This class would have an action that invokes the method on the object, passing the value. Use an instance of this class as the target. Here's a simplistic example:
#interface UnaryBinder : NSObject {
id target;
SEL selector;
id parameter;
}
#property id target;
#property SEL selector;
#property (retain) id parameter;
-(id)initWithTarget:(id)anObject selector:(SEL)aSelector param:(id)aParameter;
-(void)action:(id)sender;
#end
#implementation UnaryBinder
...
-(void)action:(id)sender {
[target performSelector:selector withObject:parameter];
}
#end
If you want to support an arbitrary number of parameters, you'd need to use NSInvocation (as Louis mentions) rather than performSelector:withObject. Of course, controls don't retain their targets, so you need some way of keeping the UnaryBinder around. At that point, you might as well skip the special class and just store the data in the control, as you mention in your comment about using KVP. Alternatively, factor out the action into a controller class and use an instance of that as the target. UnaryBinder and its ilk doesn't really offer any advantages when it comes to target-action. For related topics, google "higher order messaging".