Objective C の iPhone 開発における「デリゲート」とは何ですか?
10 に答える
デリゲートは、デリゲート所有者が呼び出す方法を知っている一連のメソッドを持つオブジェクトへのポインターです。つまり、後で作成されたオブジェクトから特定のコールバックを有効にするメカニズムです。
良い例UIAlertView
です。UIAlertView
ユーザーに短いメッセージ ボックスを表示するオブジェクトを作成し、 "OK" と "キャンセル" のような 2 つのボタンを選択できるようにします。にはUIAlertView
コールバックする方法が必要ですが、コールバックするオブジェクトとコールするメソッドに関する情報がありません。
この問題を解決するには、self
ポインターをUIAlertView
デリゲート オブジェクトとして に送信し、その代わりに (UIAlertViewDelegate
オブジェクトのヘッダー ファイルで を宣言することによって) をUIAlertView
呼び出すことができるいくつかのメソッド ( など) を実装することに同意しますalertView:clickedButtonAtIndex:
。
デリゲート デザイン パターンとその他のコールバック手法の概要については、この投稿をご覧ください。
参考文献:
この議論を見る
デリゲートを使用すると、イベントが発生したときに、あるオブジェクトから別のオブジェクトにメッセージを送信できます。たとえば、NSURLConnection クラスを使用して Web サイトから非同期にデータをダウンロードしている場合。NSURLConnection には、次の 3 つの一般的なデリゲートがあります。
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
NSURLConnection でエラーが発生したとき、正常に終了したとき、または Web サイトから応答を受信したときに、これらのデリゲートの 1 つ以上が呼び出されます。
デリゲートは設計パターンです。特別な構文や言語サポートはありません。
デリゲートは、特定のことが発生したときに別のオブジェクトがメッセージを送信する単なるオブジェクトであるため、デリゲートは、元のオブジェクトが設計されていないアプリ固有の詳細を処理できます。これは、サブクラス化せずに動作をカスタマイズする方法です。
このウィキペディアの記事が最もよく説明していると思います: http://en.wikipedia.org/wiki/Delegation_pattern
これは、設計パターンの「単なる」実装であり、Objective-C では非常に一般的です。
お願いします!デリゲートがiOSでどのように機能するかを理解するには、以下の簡単なステップバイステップのチュートリアルを確認してください。
2つのViewControllerを作成しました(一方から他方にデータを送信するため)
- FirstViewControllerはデリゲート(データを提供する)を実装します。
- SecondViewControllerはデリゲート(データを受信します)を宣言します。
これがあなたを助けるかもしれないサンプルコードです。
AppDelegate.h
#import <UIKit/UIKit.h>
@class FirstViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) FirstViewController *firstViewController;
@end
AppDelegate.m
#import "AppDelegate.h"
#import "FirstViewController.h"
@implementation AppDelegate
@synthesize firstViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//create instance of FirstViewController
firstViewController = [[FirstViewController alloc] init];
//create UINavigationController instance using firstViewController
UINavigationController *firstView = [[UINavigationController alloc] initWithRootViewController:firstViewController];
//added navigation controller to window as a rootViewController
self.window.rootViewController = firstView;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
FirstViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
@interface FirstViewController : UIViewController<MyDelegate>
@property (nonatomic, retain) NSString *mesasgeData;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UIButton *nextButton;
- (IBAction)buttonPressed:(id)sender;
@property (nonatomic, strong) SecondViewController *secondViewController;
@end
FirstViewController.m
#import "FirstViewController.h"
@interface FirstViewController ()
@end
@implementation FirstViewController
@synthesize mesasgeData;
@synthesize textField;
@synthesize secondViewController;
#pragma mark - View Controller's Life Cycle methods
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Button Click event handling method
- (IBAction)buttonPressed:(id)sender {
//get the input data from text feild and store into string
mesasgeData = textField.text;
//go keypad back when button clicked from textfield
[textField resignFirstResponder];
//crating instance of second view controller
secondViewController = [[SecondViewController alloc]init];
//it says SecondViewController is implementing MyDelegate
secondViewController.myDelegate = self;
//loading new view via navigation controller
[self.navigationController pushViewController:secondViewController animated:YES];
}
#pragma mark - MyDelegate's method implementation
-(NSString *) getMessageString{
return mesasgeData;
}
@end
SecondViewController.h
//declare our own delegate
@protocol MyDelegate <NSObject>
-(NSString *) getMessageString;
@end
#import <UIKit/UIKit.h>
@interface SecondViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
@property (nonatomic, retain) id <MyDelegate> myDelegate;
@end
SecondViewController.m
#import "SecondViewController.h"
@interface SecondViewController ()
@end
@implementation SecondViewController
@synthesize messageLabel;
@synthesize myDelegate;
- (void)viewDidLoad
{
[super viewDidLoad];
messageLabel.text = [myDelegate getMessageString];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
@end
デリゲートを理解すれば、これらすべての答えは非常に理にかなっていると思います。個人的には、私は C/C++ の土地から来て、その前は Fortran などの手続き型言語だったので、C++ パラダイムで同様の類似物を見つけるための私の 2 分間の取り組みを次に示します。
C++/Java プログラマーにデリゲートについて説明する場合、私はこう言います。
デリゲートとは これらは、別のクラス内のクラスへの静的ポインターです。ポインターを割り当てたら、そのクラスの関数/メソッドを呼び出すことができます。したがって、クラスの一部の関数は別のクラスに「委譲」されます (C++ の世界では、クラス オブジェクト ポインターによるポインター)。
プロトコルとは?概念的には、デリゲート クラスとして割り当てるクラスのヘッダー ファイルと同様の目的を果たします。プロトコルは、ポインタがクラス内でデリゲートとして設定されたクラスに実装する必要があるメソッドを定義する明示的な方法です。
C++で同様のことを行うにはどうすればよいですか? C++ でこれを行おうとすると、クラス定義でクラス (オブジェクト) へのポインターを定義し、それらを他のクラスに接続して、基本クラスへのデリゲートとして追加の関数を提供します。しかし、この配線はコード内で維持する必要があり、扱いにくく、エラーが発生しやすくなります。Objective C は、プログラマーがこの規定を維持するのが得意ではないことを前提としており、クリーンな実装を強制するためにコンパイラーの制限を提供しています。
簡単なプログラムで詳しく説明してみます
2つのクラス
Student.h
#import <Foundation/Foundation.h>
@interface Student : NSObject
@property (weak) id delegate;
- (void) studentInfo;
@end
Student.m
#import "Student.h"
@implementation Student
- (void) studentInfo
{
NSString *teacherName;
if ([self.delegate respondsToSelector:@selector(teacherName)]) {
teacherName = [self.delegate performSelector:@selector(teacherName)];
}
NSLog(@"\n Student name is XYZ\n Teacher name is %@",teacherName);
}
@end
先生.h
#import <Foundation/Foundation.h>
#import "Student.h>
@interface Teacher: NSObject
@property (strong,nonatomic) Student *student;
- (NSString *) teacherName;
- (id) initWithStudent:(Student *)student;
@end
Teacher.m
#import "Teacher.h"
@implementation Teacher
- (NSString *) teacherName
{
return @"ABC";
}
- (id) initWithStudent:(Student *)student
{
self = [ super init];
if (self) {
self.student = student;
self.student.delegate = self;
}
return self;
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Teacher.h"
int main ( int argc, const char* argv[])
{
@autoreleasepool {
Student *student = [[Student alloc] init];
Teacher *teacher = [[Teacher alloc] initWithStudent:student];
[student studentInfo];
}
return 0;
}
説明:::
メインメソッドからいつ
initWithStudent:student
実行するか1.1 Teacher のオブジェクトのプロパティ ' student ' には、 Student オブジェクトが割り当てられます。
1.2
self.student.delegate = self
means student object's delegate will points to teacher object
メインメソッドからいつ
[student studentInfo]
呼び出されるか2.1
[self.delegate respondToSelector:@selector(teacherName)]
ここで、デリゲートはすでに教師オブジェクトを指しているため、'teacherName' インスタンス メソッドを呼び出すことができます。2.2なので
[self.delegate performSelector:@selector(teacherName)]
簡単に実行できます。
Teacher オブジェクトがデリゲートを Student オブジェクトに割り当てて、独自のメソッドを呼び出すように見えます。
これは相対的な考え方であり、学生オブジェクトが「teacherName」メソッドと呼ばれていることがわかりますが、基本的には教師オブジェクト自体によって行われます。
デリゲートは、ユーザーのテーピング アクションをキャプチャし、ユーザーのテーピング アクションに従って特定のアクションを実行します。
デリゲートは Objects C の自動イベントを発生させます。デリゲートを Object に設定すると、デリゲート メソッドを介して別のオブジェクトにメッセージが送信されます。
これは、サブクラス化を必要とせずにクラスの動作を変更する方法です。
デリゲート メソッドを持つ各オブジェクト。特定のオブジェクトがユーザー インタラクションとプログラム フロー サイクルに参加すると、これらのデリゲート メソッドが起動します。
簡単に言うと、委譲とは、オブジェクト間に強い相互依存関係を作成することなく、オブジェクトが相互に対話できるようにする方法です。
デリゲートは、そのオブジェクトに代わってメソッドを呼び出すことができるオブジェクトのインスタンスに他なりません。また、そのオブジェクトのrumtimeでメソッドを作成するのに役立ちます。