ブロック、セレクター、および関数ポインター (後の 2 つのうちどちらを名前付き関数として参照しているかは不明) はすべて互換性のない型であるため、別の型の引数が必要な場所に渡すことはできません。幸いなことに、ブロックベースの API で関数ポインターまたはセレクターを使用する必要がある場合は、非常に簡単に使用できます。ブロックは、作成時にスコープ内にある関数ポインターとセレクターをキャプチャし、ブロック内で使用できます (他の変数と同様に)。たとえば、次のビュー コントローラーは、セレクターまたは関数ポインターを引数として受け入れる GCD (ブロック ベースの API) へのラッパーを提供します。
ViewController.h:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m:
#import "ViewController.h"
void callback() { NSLog(@"call back function"); }
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self doSomethingWithCompletionSelector:@selector(callback)];
// [self doSomethingWithCompletionFunction:callback];
}
- (void)callback
{
NSLog(@"call back selector");
}
- (void)doSomethingWithCompletionSelector:(SEL)selector
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {
NSLog(@"Doing something");
// Causes a warning in ARC
[self performSelector:selector];
});
}
- (void)doSomethingWithCompletionFunction:(void (*)())function
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"Doing something");
function();
});
}
@end
もちろん、任意のメソッドまたは関数を明示的に呼び出すことができ、レシーバーと引数はすべてブロックによってキャプチャされます。