Хранить ссылки на методы объекта в массиве (Objective-C)

Я нахожусь в процессе изучения Objective-C, и я пытаюсь сохранить ссылки на методы в массиве, где я могу выполнить цикл через массив и вызвать методы. Я исхожу из интерпретируемого языкового фона, и в языке, таком как Ruby, вы можете сделать что-то вроде следующего

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

method_arr.each do |m|
    m.call
end

Ближайшая вещь, которую я нашел, это использование NSInvocation для достижения этого со следующим

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];
}

Другой способ, который я нашел, — использовать блоки, которые не ссылаются на методы, но достигают аналогичных результатов

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

NSInvocation кажется немного утомительным для меня и задавался вопросом, есть ли лучший способ сделать это.

2 ответа

  1. Я бы пошел с блоками. При создании массива оберните каждый вызов метода в блок и добавьте блок.

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

    Имейте в виду проблемы с памятью при этом подходе; в частности, ссылочные циклы. Вы можете classInstanceбыть слабой ссылкой.

    Вы вызываете блоки путем приведения к dispatch_block_tи вызова.

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

    Вы можете сделать это чище, введя массив.

    NSArray<dispatch_block_t> *calls = @[
    

    Теперь призыв просто

    calls[0]();
    
  2. Я бы пошел только со строками в массиве. Просто сохраните имена методов в массиве, замкните массив, преобразуйте строку имени метода в selector with NSSelectorFromString()и вызовите performSelector:объект/объекты. Однако это может привести к нежелательному предупреждению

    performSelector может вызвать утечку, так как его селектор неизвестен

    который можно удалить, обернув ваш performSelector:код в этиpragma

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

    что объясняется здесь

    Удачи, надеюсь, что это было полезно!