Objective-Cでコールバック関数を実行する方法は?
完成した例をいくつか見たいのですが、それを理解する必要があります。
Objective-Cでコールバック関数を実行する方法は?
完成した例をいくつか見たいのですが、それを理解する必要があります。
回答:
通常、目的Cのコールバックはデリゲートで行われます。以下は、カスタムデリゲート実装の例です。
ヘッダーファイル:
@interface MyClass : NSObject {
id delegate;
}
- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end
@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end
実装(.m)ファイル
@implementation MyClass
- (void)setDelegate:(id)aDelegate {
delegate = aDelegate; /// Not retained
}
- (void)doSomething {
[delegate myClassWillDoSomething:self];
/* DO SOMETHING */
[delegate myClassDidDoSomething:self];
}
@end
これは一般的なアプローチを示しています。NSObjectに、コールバックメソッドの名前を宣言するカテゴリを作成します。NSObjectは実際にはこれらのメソッドを実装していません。このタイプのカテゴリは非公式プロトコルと呼ばれ、多くのオブジェクトがこれらのメソッドを実装している可能性があるというだけです。これらは、セレクターの型シグニチャーを転送宣言する方法です。
次に、「MyClass」のデリゲートとなるオブジェクトがあり、MyClassは、デリゲートのデリゲートメソッドを適切に呼び出します。デリゲートコールバックがオプションの場合は、通常、 "if([delegate respondsToSelector:@selector(myClassWillDoSomething :)){"のようなものでディスパッチサイトでそれらを保護します。私の例では、デリゲートは両方のメソッドを実装する必要があります。
非公式のプロトコルの代わりに、@ protocolで定義された正式なプロトコルを使用することもできます。その場合は、デリゲートセッターのタイプとインスタンス変数をid <MyClassDelegate>
、単に " id
" ではなく " "に変更します。
また、デリゲートが保持されていないことにも気づくでしょう。これは通常、「MyClass」のインスタンスを「所有」するオブジェクトが通常はデリゲートでもあるために行われます。MyClassがデリゲートを保持している場合、保持サイクルがあります。MyClassインスタンスがあり、デリゲートであるクラスのdeallocメソッドでは、弱いバックポインターであるため、そのデリゲート参照をクリアすることをお勧めします。それ以外の場合、何かがMyClassインスタンスを存続させていると、宙ぶらりんのポインタが表示されます。
完全を期すために、StackOverflow RSSは私のためにランダムに質問を復活させただけなので、他の(新しい)オプションはブロックを使用することです:
@interface MyClass: NSObject
{
void (^_completionHandler)(int someParameter);
}
- (void) doSomethingWithCompletionHandler:(void(^)(int))handler;
@end
@implementation MyClass
- (void) doSomethingWithCompletionHandler:(void(^)(int))handler
{
// NOTE: copying is very important if you'll call the callback asynchronously,
// even with garbage collection!
_completionHandler = [handler copy];
// Do stuff, possibly asynchronously...
int result = 5 + 3;
// Call completion handler.
_completionHandler(result);
// Clean up.
[_completionHandler release];
_completionHandler = nil;
}
@end
...
MyClass *foo = [[MyClass alloc] init];
int x = 2;
[foo doSomethingWithCompletionHandler:^(int result){
// Prints 10
NSLog(@"%i", x + result);
}];
以下は、デリゲートの概念を排除し、生のコールバックを行う例です。
@interface Foo : NSObject {
}
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector;
@end
@interface Bar : NSObject {
}
@end
@implementation Foo
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector {
/* do lots of stuff */
[object performSelector:selector withObject:self];
}
@end
@implementation Bar
- (void)aMethod {
Foo *foo = [[[Foo alloc] init] autorelease];
[foo doSomethingAndNotifyObject:self withSelector:@selector(fooIsDone:)];
}
- (void)fooIsDone:(id)sender {
NSLog(@"Foo Is Done!");
}
@end
通常、メソッド-[Foo doSomethingAndNotifyObject:withSelector:]は非同期であり、コールバックがここよりも便利になります。
この質問を最新に保つために、iOS 5.0のARCの導入は、ブロックをさらに簡潔に使用してこれを実現できることを意味します。
@interface Robot: NSObject
+ (void)sayHi:(void(^)(NSString *))callback;
@end
@implementation Robot
+ (void)sayHi:(void(^)(NSString *))callback {
// Return a message to the callback
callback(@"Hello to you too!");
}
@end
[Robot sayHi:^(NSString *reply){
NSLog(@"%@", reply);
}];
Objective-Cのブロック構文を忘れた場合は、常にF **** ngブロック構文があります。
+ (void)sayHi:(void(^)(NSString *reply))callback;
ないはずです+ (void)sayHi:(void(^)(NSString *))callback;
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
注でparameterTypes
はないparameters
)
コールバック:Objective Cには4種類のコールバックがあります
セレクタのタイプ:NSTimer、UIPangestureがセレクタコールバックの例であることがわかります。コードの非常に限定された実行に使用されます。
Delegate Type:一般的で、Appleフレームワークで最も使用されています。UITableViewDelegate、NSNURLConnectionDelegate。これらは通常、サーバーからの多数の画像の非同期ダウンロードなどを示すために使用されます。
他にご不明な点がございましたらお聞かせください。よろしくお願いします。