0

I'm in the process of learning Objective-C and I'm trying to store method references in an array where I can loop through the array and invoke the methods. I'm coming from an interpreted language background and in a language like Ruby you could do something like the following

method_arr = [objectOne.method(:methodOne), objectTwo.method(:methodOne)]

method_arr.each do |m|
    m.call
end

The closest thing I found was using NSInvocation to achieve this with the following

NSMethodSignature *signature = [objectOne methodSignatureForSelector:@selector(methodOne)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:@selector(methodOne)];
[invocation setTarget:objectOne];


NSArray *methodArr = @[invocation];

for (int i = 0; i < [methodArr count]; i++) {
    [methodArr[i] invoke];
}

Another way I found would be to use blocks which isn't referencing the methods but achieves similar results

NSArray *methodArr = @[^{ 
    [objectOne methodOne]
}];

NSInvocation seems a bit tedious for me and was wondering if there's a better way to do this.

Vvk
  • 4,031
  • 29
  • 51
Brian
  • 315
  • 3
  • 7
  • 12

2 Answers2

0

I would go with blocks. When creating the array, wrap each method call in a block and add the block.

NSArray *calls = @[
                   ^{ [classInstance methodOne; },
                   ^{ [classInstance methodTwo; },
                   ^{ [classInstance methodThree; },
                   ^{ [classInstance methodFour; },
                 ];

Be aware of memory issues with this approach; specifically reference cycles. You may want classInstance to be a weak reference.

You call the blocks by casting to dispatch_block_t and invoking.

((dispatch_block_t)calls[0])();

You can make that cleaner by typing the array.

NSArray<dispatch_block_t> *calls = @[

Now invocation is simply

calls[0]();
Avi
  • 7,469
  • 2
  • 21
  • 22
0

I would go with just strings in the array. Just store the method names in the array, loop the array, convert method name string to selector with NSSelectorFromString(), and call performSelector: on the object/s. However, this may result in unwanted warning saying

performSelector may cause a leak because its selector is unknown

which can be removed by wrapping your performSelector: code in these pragma's

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [object performSelector: someSelector withObject: anotherObject];
#pragma clang diagnostic pop

which is explained in here

Good luck, hope this was helpful!

Community
  • 1
  • 1
Fahri Azimov
  • 11,470
  • 2
  • 21
  • 29