开发者

Function injection in objective-c

I have a random number generator (R开发者_C百科NG) function.

-(double) generateRandomNumber
{
   ... do some stuff
   return randomNumber;
}

I have a function that calls this random number generator function to do a task - something along the lines of

-(double) GenerateSellPrice {
   double randomNumber;

   randomNumber = [self generateRandomNumber];

   return value*randomNumber;
}

I want to modify this so that the random number generator function is actually passed into the GenerateSellPrice function, so that I can swap in and out different RNGs for different purposes (i.e. unit testing, different ranges, etc).

How do I declare the RNG function so that it is in a form that I can pass it around (I'm assuming as a function pointer)? How do I declare the GenerateSellPrice to accept the function as a parameter? And how do I then invoke the function?


You could declare your PRNGs as Objective-C blocks and pass them around like any other object. http://www.mikeash.com/pyblog/friday-qa-2008-12-26.html has some info on the subject.


The classic Objective-C pattern would be to take a selector (SEL) and object (id) argument argument:

  -(double) GenerateSellPriceWithRNG:(id)rngObject selector:(SEL)rngSelector
       double randomNumber;

       randomNumber = [rngObject performSelector:rngSelector];

       return value*randomNumber;
    }

and call it with

[self GenerateSellPrinceWithRNG:self selector:@selector(generateRandomNumber)];

Modern practice would probably take a block (double (^)()) parameter. The syntax for a block is slightly uglier, but the power it brings is useful in this scenario. You get better type-checking from the compiler and you can easily generate a block inline where convenient rather than having to write an entire class & method.

In this case you could declare

-(double) GenerateSellPriceWithRNG:(double (^)())rngBlock {
   double randomNumber;

   randomNumber = rngBlock();

   return value*randomNumber;
}

and call it with

[self GenerateSellPriceWithRNG:^{ return [self generateRandomNumber]; }];

or with any other block that returns a double.


The easiest way to do that is to use the "selector" object. You can declare a selector by doing the following

@selector(generateRandomNumber)

Once you have a selector object, you use

SEL randomNumberFunction; // Most likely passed in as a parameter
NSObject *generatorObject;
[generatorObject performSelector:randomNumberFunction];


Worked it out using blocks. For those who want to know how I did it, I declared my RNG in my calling class (classA) as a class variable

double(^generateRandomNumber)(void) = ^{   
   ...do stuff;   
   return randomNumber; 
};

Then declared my function in my called class (classB)

-(double) generateSellPriceWithGenerator:(double(^)(void))generator {
   double randomNumber;

   randomNumber = generator();

   return value*randomNumber;
}

And then simply called the function from classA like so

double (^func)(void) = generateRandomNumber;
double value = [classB generateSellPriceWithGenerator:func];
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜