Objective C的iPhone开发中,“delegate”是什么?

69

在Objective-C的iPhone开发中,“delegate”是什么意思?


这似乎是 https://dev59.com/WXM_5IYBdhLWcg3wgja2 和可能的 https://dev59.com/GHI-5IYBdhLWcg3wkJQA 的重复。 - Brad Larson
参见:https://dev59.com/m3RB5IYBdhLWcg3wXmNI,https://dev59.com/nXRB5IYBdhLWcg3wbGtB,https://dev59.com/AHNA5IYBdhLWcg3wUL9Y和http://stackoverflow.com/questions/1408774/can-someone-explain-what-a-delegate-is-with-an-example。 - Brad Larson
10个回答

80

委托是一个指向一组方法的对象的指针,委托持有者知道如何调用这些方法。换句话说,它是一种使后创建的对象能够进行特定回调的机制。

一个很好的例子是UIAlertView。您可以创建一个UIAlertView对象来向用户显示一个短消息框,可能还会提供两个按钮“确定”和“取消”的选择。 UIAlertView需要一种方式来回调您,但它不知道要回调哪个对象以及调用哪个方法。

为解决这个问题,您可以将 self 指针作为委托对象发送到 UIAlertView 中,并且通过在对象的头文件中声明 UIAlertViewDelegate 来实现一些方法,以便UIAlertView可以调用,例如alertView:clickedButtonAtIndex:

请查看此帖子,了解有关委托设计模式和其他回调技术的快速高级介绍。

参考文献:


56

请看这个讨论

委托模式允许一个对象在事件发生时向另一个对象发送消息。例如,如果您使用NSURLConnection类异步地从网站下载数据,则可以使用代理模式来监听下载进度。NSURLConnection有三个常见的代理:

 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

这些代理中的一个或多个将在NSURLConnection遇到故障、成功完成或从网站收到响应时被调用。


5
这是不是类似于 Android 中的 Listener? - Jordan Hochstetler
@JordanHochstetler 看起来代表正是监听器。 - David T.

21

委托是一种设计模式;没有特殊的语法或语言支持。

委托只是另一个对象在发生某些事情时发送消息的对象,以便委托可以处理原始对象未设计的应用程序特定细节。这是一种避免子类化的自定义行为的方式。


2
那么基本上这就是实现回调的面向对象方式? - Daniel Sloof
@DanielSloof 我也是这么想的... - Paranoid Android

5

3

我将通过一个简单的程序来详细说明它

两个类

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

Teacher.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;
}

解释 :::


  1. From main method when initWithStudent:student will execute

    1.1 Teacher's object's property 'student' will be assigned with student object.

    1.2 self.student.delegate = self

        means student object's delegate will points to teacher object
    
  2. From main method when [student studentInfo] will be called

    2.1 [self.delegate respondToSelector:@selector(teacherName)] Here delegate already points to teacher object so it can invoke 'teacherName' instance method.

    2.2 so [self.delegate performSelector:@selector(teacherName)] will execute easily.

Great! What language do you need me to translate from and to?

3
我认为这些答案在理解委托之后都很有道理。就我个人而言,我来自C / C ++的世界,以前是Fortran等过程性语言,所以以下是我对在C ++范例中找到类似模拟的方法的简述。
如果我要向C ++ / Java程序员解释委托,我会说:
什么是委托?这些是指向另一个类中类的静态指针。一旦分配了指针,您就可以调用该类中的函数/方法。因此,你的类的某些函数被“委托”(在C ++的世界中 - 由类对象指针指向)到另一个类中。
什么是协议?概念上,它的作用类似于您正在分配为委托类的头文件。协议是显式定义需要在将指针设置为类中的委托类时实现的方法的方法。
如何在C ++中实现类似的功能?如果您尝试在C ++中执行此操作,则需要在类定义中定义指向类(对象)的指针,然后将它们连接到提供额外函数作为基类委托的其他类中。但是,这种连接需要在代码中维护,并且将笨拙和容易出错。Objective-C只是假定程序员并不擅长保持这种规矩,并提供编译器限制以强制执行干净的实现。

3
请查看以下简单的逐步教程,了解iOS中委托如何工作。

iOS中的委托

我创建了两个视图控制器(用于从一个视图控制器向另一个视图控制器发送数据)。
  1. FirstViewController实现委托(提供数据)。
  2. 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

你好RDC,这段代码不起作用了,你能否在你那边试一下。 - Amit Thakur

1

委托在C对象中触发自动事件。如果将委托设置为对象,则通过委托方法将消息发送到另一个对象。

这是一种在不需要子类化的情况下修改类行为的方式。

每个对象都有委托方法。当特定对象参与用户交互和程序流程周期时,这些委托方法会触发。

简单地说:委托是一种允许对象相互交互而不创建强依赖关系的方式。


1
代理捕获用户的点击操作,并根据用户的点击动作执行特定的操作。

0

委托是一个对象的实例,我们可以代表该对象调用方法。它还有助于在对象运行时创建方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接