How to build a NSArray (or NSMutableArray) of class methods in Objective-C? - objective-c

I'm trying to build a NSArray of methods in Objective-C.
(What I'm trying to accomplish here is something like the following in C)
typedef (void)(*handler)(int command);
void handleCommandA(void) { ... }
void handleCommandB(void) { ... }
static const handler handler_table[10] = {
handleCommandA, handleCommandB, handleCommandC
};
I have to port this to Objective-C and I don't know how to
build an array of function pointers (in Objective-c world,
class methods) at compile-time.
In Objective-C I have the following.
- (void)handleCommandA { ... }
- (void)handleCommandB { ... }
/* Now how to add above 2 functions into NSArray? */
NSArray *handler_table = [NSArray arrayWithObjects:... ]; /* This doesn't seem to work. */

The problem here is that to bind those functions you must use the selector keyword which returns a SEL type. This is a pointer type whereas NSArray stores objects.
You thus have three options;
Use a regular C-type array
Fold the functions into an NSObject derived class that will call them.
Use a protocol.
The second is likely the nicer and for this you can use the NSValue class to hold the selector results. E.g;
NSValue* selCommandA = [NSValue valueWithPointer:#selector(handleCommandA:)];
NSValue* selCommandB = [NSValue valueWithPointer:#selector(handleCommandB:)];
NSArray *handler_table = [NSArray arrayWithObjects:selCommandA, selCommandB, nil ];
When you have retrieved the correct entry from the array, to convert back you would do;
SEL mySelector = [selCommand pointerValue];
[someObject performSelector:mySelector];
(Note I'm assuming that from your objective-c syntax that these are intended to be used as methods on an object and not global functions. If you wish to use them globally then you should write them as you would in plain C.)
Another option is to formalize the command methods into a protocol. This allows you to write functionality that will work on any object which implements that protocol and the compiler will provide more checking than if you were just calling selectors.
E.g.
// some header
#protocol CommandHandler
#required
-(void) handleCommandA;
-(void) handleCommandB;
#end
// some other header
#interface someClass : NSObject<CommandHandler>
{
// you will receive compiler warnings if you do not implement the protocol functions
}
Your handling and dispatch code is then written to work with objects of type "CommandHandler". E.g
-(void) registerForCommands:(CommandHandler*)handler

Use NSValue.
For example:
NSArray* handlers = [NSArray arrayWithObjects:[NSValue valueWithPointer:handleA] ... ];
then to access :
handleptr* handle = (handlerptr*)[[handlers objectAtIndex:0] pointerValue];
handle(foo_bar);

In Objective-C, you don't pass around methods; you pass around selectors, which are basically the canonical names of methods. Then, to make an object respond to a selector message, you send it performSelector:. For example:
NSString *exampleString = [NSString stringWithString:#"Hello"];
SEL methodName = #selector(stringByAppendingString:);
// ^This is the selector. Note that it just represents the name of a
// message, and doesn't specify any class or implementation
NSString *combinedString = [exampleString performSelector:methodName withObject:#" world!"];
What you'll want is to make an array of NSStrings containing the names of the selectors you're interested in. You can use the function NSStringFromSelector() to do this. Then, when you want to use them, call NSSelectorFromString() on the strings to get the original selector back and pass it to the appropriate object's performSelector:. (As shown in the example above, the receiver isn't encoded in a selector — just the method name — so you might need to store the receiver as well.)

Related

How to set expectations on parameters to mocked methods in Kiwi

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.

Implementing a Dispatch Table in Objective-C: how to declare an array of selectors

I'm trying to implement a dispatch table, so that I can call a selector with the following example code:
NSInteger i = 2;
[myObject performSelector:selectors[i]];
I'm trying to store user preferences which affect which method of an API gets called. Right now, I use the string name of the selector and use NSSelectorFromString, but that's a bit messy. If I use a dispatch table, then I can store an enum instead.
How can I make an array of selectors, or a dispatch table in Objective-C?
Edit:
The compiler complains when I try to set an array of selectors as a property. #property SEL[] won't compile.
Edit2:
I'm using my KosherCocoa API library and I want to call a single method at once, based on a saved user setting. I'm saving to and reading from a Plist file.
You can use the SEL type to hold selectors. Simply:
SEL dispatchTable[3] = { #selector(doThis:),
#selector(doThat:),
#selector(doTheOther:)
};
To your edit, use an NSArray/NSDictionary/etc of selectors as your property instead. You are not allowed to use C arrays as properties in Objective C; they are not one of the supported types (which are ObjC objects, CF types and basic C 'Plain Old Data' types.)
OK, on our comments below, you need to wrap the selector in an NSValue to allow you to use it in an objc container (because SEL is a C pointer type):
NSMutableArray * dispatchTable2 = [[NSMutableArray alloc] initWithCapacity:3];
SEL selIn = #selector(doThis:);
// Wrap the selector in an NSValue instance
[dispatchTable2 addObject:[NSValue valueWithPointer:selIn]];
// On extracting:
NSValue * valOut = [dispatchTable2 objectAtIndex:0];
SEL selOut = [[dispatchTable2 objectAtIndex:0] pointerValue];
[anObject performSelector:selOut];
So now your table is an objc container stored as a property or ivar, and you use NSValue to wrap SEL pointers with valueWithPointer: and get the SEL out with pointerValue.
I would recommend using NSInvocation instead of selectors. They are far more flexible, as you can send the same invocation to many objects and you can change its properties as you go.
One way to do this is using an array of NSStrings, then converting those to SELs at runtime, if that increases readability for you..
NSString *selectors[] = { ... }
[myObject performSelector:NSSelectorFromString(selectors[i])];
To use this as a property, use
#property(nonatomic, assign) NSString **selectors;

Writing my own #dynamic properties in Cocoa

Suppose (for the sake of argument) that I have a view class which contains an NSDictionary. I want a whole bunch of properties, all of which access the members of that dictionary.
For example, I want #property NSString* title and #property NSString* author.
For each one of these properties, the implementation is the same: for the getter, call [dictionary objectForKey:propertyName];, and for the setter do the same with setObject:forKey:.
It would take loads of time and use loads of copy-and-paste code to write all those methods. Is there a way to generate them all automatically, like Core Data does with #dynamic properties for NSManagedObject subclasses? To be clear, I only want this means of access for properties I define in the header, not just any arbitrary key.
I've come across valueForUndefinedKey: as part of key value coding, which could handle the getters, but I'm not entirely sure whether this is the best way to go.
I need these to be explicit properties so I can bind to them in Interface Builder: I eventually plan to write an IB palette for this view.
(BTW, I know my example of using an NSDictionary to store these is a bit contrived. I'm actually writing a subclass of WebView and the properties will refer to the IDs of HTML elements, but that's not important for the logic of my question!)
I managed to solve this myself after pouring over the objective-c runtime documentation.
I implemented this class method:
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
NSString *method = NSStringFromSelector(aSEL);
if ([method hasPrefix:#"set"])
{
class_addMethod([self class], aSEL, (IMP) accessorSetter, "v#:#");
return YES;
}
else
{
class_addMethod([self class], aSEL, (IMP) accessorGetter, "##:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
Followed by a pair of C functions:
NSString* accessorGetter(id self, SEL _cmd)
{
NSString *method = NSStringFromSelector(_cmd);
// Return the value of whatever key based on the method name
}
void accessorSetter(id self, SEL _cmd, NSString* newValue)
{
NSString *method = NSStringFromSelector(_cmd);
// remove set
NSString *anID = [[[method stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:#""] lowercaseString] stringByReplacingOccurrencesOfString:#":" withString:#""];
// Set value of the key anID to newValue
}
Since this code tries to implement any method that is called on the class and not already implemented, it'll cause problems if someone tries calling something you're note expecting. I plan to add some sanity checking, to make sure the names match up with what I'm expecting.
You can use a mix of your suggested options:
use the #dynamic keyword
overwrite valueForKey: and setValue:forKey: to access the dictionary
use the objective-c reflection API's method class_getProperty and check it for nil. If it's not nil your class has such a property. It doesn't if it is.
then call the super method in the cases where no such property exists.
I hope this helps. Might seem a bit hacky (using reflection) but actually this is a very flexible and also absolutely "legal" solution to the problem...
PS: the coredata way is possible but would be total overkill in your case...
Befriend a Macro? This may not be 100% correct.
#define propertyForKey(key, type) \
- (void) set##key: (type) key; \
- (type) key;
#define synthesizeForKey(key, type) \
- (void) set##key: (type) key \
{ \
[dictionary setObject];// or whatever \
} \
- (type) key { return [dictionary objectForKey: key]; }
sounds like you should should be using a class instead of a dictionary. you're getting close to implementing by hand what the language is trying to give you.
There is a nice blog with example code with more robust checks on dynamic properties at https://tobias-kraentzer.de/2013/05/15/dynamic-properties-in-objective-c/ also a very nice SO answer at Objective-C dynamic properties at runtime?.
Couple of points on the answer. Probably want to declare an #property in the interface to allow typeahead also to declare the properties as dynamic in the implementation.

Objective C run-time parameter binding

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".

How to detect a property return type in Objective-C

I have an object in objective-c at runtime, from which I only know the KVC key and I need to detect the return value type (e.g. I need to know if its an NSArray or NSMutableArray) of this property, how can I do that?
You're talking about runtime property introspection, which happens to be something that Objective-C is very good at.
In the case you describe, I'm assuming you have a class like this:
#interface MyClass
{
NSArray * stuff;
}
#property (retain) NSArray * stuff;
#end
Which gets encoded in XML something like this:
<class>
<name>MyClass</name>
<key>stuff</key>
</class>
From this information, you want to recreate the class and also give it an appropriate value for stuff.
Here's how it might look:
#import <objc/runtime.h>
// ...
Class objectClass; // read from XML (equal to MyClass)
NSString * accessorKey; // read from XML (equals #"stuff")
objc_property_t theProperty =
class_getProperty(objectClass, accessorKey.UTF8String);
const char * propertyAttrs = property_getAttributes(theProperty);
// at this point, propertyAttrs is equal to: T#"NSArray",&,Vstuff
// thanks to Jason Coco for providing the correct string
// ... code to assign the property based on this information
Apple's documentation (linked above) has all of the dirty details about what you can expect to see in propertyAttrs.
Cheap answer: use the NSObject+Properties source here.
It implements the same methodology described above.
The preferred way is to use the methods defined in the NSObject Protocol.
Specifically, to determine if something is either an instance of a class or of a subclass of that class, you use -isKindOfClass:. To determine if something is an instance of a particular class, and only that class (ie: not a subclass), use -isMemberOfClass:
So, for your case, you'd want to do something like this:
// Using -isKindOfClass since NSMutableArray subclasses should probably
// be handled by the NSMutableArray code, not the NSArray code
if ([anObject isKindOfClass:NSMutableArray.class]) {
// Stuff for NSMutableArray here
} else if ([anObject isKindOfClass:NSArray.class]) {
// Stuff for NSArray here
// If you know for certain that anObject can only be
// an NSArray or NSMutableArray, you could of course
// just make this an else statement.
}
This is really a comment addressing an issue raised by Greg Maletic in response to answer provided by e.James 21APR09.
Agreed that Objective-C could use a better implementation for getting these attributes.
Below is a method I quickly threw together to retrieve attributes of a single object property:
- (NSArray*) attributesOfProp:(NSString*)propName ofObj:(id)obj{
objc_property_t prop = class_getProperty(obj.class, propName.UTF8String);
if (!prop) {
// doesn't exist for object
return nil;
}
const char * propAttr = property_getAttributes(prop);
NSString *propString = [NSString stringWithUTF8String:propAttr];
NSArray *attrArray = [propString componentsSeparatedByString:#","];
return attrArray;
}
Partial list of attribute keys:
R Read-only
C Copy of last value assigned
& Reference to last value assigned
N Nonatomic property
W Weak reference
Full list at Apple
You can use isKindOfClass message
if([something isKindOfClass:NSArray.class])
[somethingElse action];
If you know that the property is defined :
id vfk = [object valueForKey:propertyName];
Class vfkClass = vfk.class;
And compare with isKindOfClass, isSubClass, etc.