对Objective-C中的委托有点困惑

Posted

技术标签:

【中文标题】对Objective-C中的委托有点困惑【英文标题】:Little confused on Delegates in Objective-C 【发布时间】:2009-08-28 22:34:29 【问题描述】:

我对 Objective-C 有一定的了解,并且正在编写一本 iPhone SDK 书籍(来自一本刚刚编写控制台程序的 Obj-C 书籍)。它试图向代表解释,尽管它很匆忙,并且并不真正理解它试图传达的内容。我对它们是什么以及何时使用它们感到有些困惑。

基本上它说它们是代表另一个对象负责做某些事情的类。

有人愿意详细说明吗?

谢谢!

【问题讨论】:

当我开始研究 Cocoa 时,我遇到了困难。你并不孤单。 【参考方案1】:

将委托视为依赖关系方向的反转。在大多数框架中,客户端会将所需的依赖项注入到实例中,通常是在构造函数中或通过 setter。

可可则相反;而是在需要时请求数据。

委托方法主要有四种类型:

有条件地在之前 - 表示某事即将发生,但委托可能会中止。名称中始终包含“应该”一词。 示例:searchBarShouldEndEditing:无条件之前 - 表示某事即将发生。名称中始终包含 will 这个词。 示例:applicationWillTerminate:无条件之后 - 表示发生了什么事。名称中始终包含 did 这个词。 示例:applicationDidFinishLaunching:定制器 - 请求有关如何运作的信息。名称包括所需的信息。 例如tableView:viewForHeaderInSection:

所有委托方法始终将其发送者作为参数之一。任何委托方法都可能具有改变发送者行为方式的返回值。

【讨论】:

到目前为止这些答案中最好的解释,恕我直言【参考方案2】:

假设您想向用户显示一个警报,并且您希望在用户触摸其中一个按钮时运行一个方法。问题是,当有人触摸按钮时,你怎么知道要调用什么方法、调用哪个对象?

为了让一个类成为一个委托,你必须这样声明它。在上面的示例中,假设您有一个 ApplicationController 对象来控制应用程序的流程。在声明中,我们会说

@interface ApplicationController : NSObject <UIAlertViewDelegate>

这告诉编译器 ApplicationController 将在 UIAlertViewDelegate 协议中实现一些方法。我们在文档中查找该协议,并查看方法列表。当我们想要在按下按钮时做某事时,我们看到:

alertView:clickedButtonAtIndex: - 当用户单击警报视图上的按钮时发送给代理。此方法是可选的。

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

所以,如果我们在 ApplicationController 中实现一个名为 alertView:clickedButtonAtIndex 的方法,创建一个 ApplicationController 对象,然后将该对象设置为我们显示的警报的委托,那么一切都设置好了。只要有人在警报上按下按钮,alertView:clickedButtonAtIndex 方法就会被调用,并传入 alertView 和按下按钮的索引。

这使您可以对这些信息做任何您想做的事情。一个简单的case语句:

if( buttonIndex == 0 ) 
    _myString = @"Pressed the button";
 else 
    _myString = @"Pressed the other button";

Objective-C 参考文档非常非常好,所有的委托协议都非常清楚。

【讨论】:

at 符号是什么意思? 这取决于你指的是哪一个。您可以通过说@“string here”来定义字符串,这是客观的c语法事物。否则,@interface 是一个类声明。许多目标 c 特定的东西都以 @ 开头,因为它从未在 C/C++ 标识符中使用过。它允许目标 c 的开发人员确保不会混淆某些内容是来自 C/C++ 还是目标 c【参考方案3】:

理解代表的一个好方法是通过示例。一个例子是UITableView(或NSTableView,取决于我们说的是iPhone 还是Mac OS)。无论哪种方式,表格视图都有一个delegate 和一个dataSource(两者都充当接收器的辅助对象)。

而不是UITableView 处理事件,例如,当用户点击其中一行时,它会告诉它的delegate“嘿!我已经点击了这一行和这一部分,做什么你会!”。通常delegate 是某种控制器,它实现了正确的方法。因此表视图(在检查delegate 是否确实有该方法的定义之后)发送如下消息:

[delegate tableView:self didSelectRowAtIndexPath:indexPath];

由于您的 Controller 是表的委托,并且它实现了该方法,因此它决定要做什么。当方法完成时(在这种情况下它应该只返回void),然后在表视图上继续执行。

代表是一个概念。这不是 Objective-C 的语言特性。 UITableView 的delegate 成员就像任何其他对象一样。虽然,代表通常保留,而是分配(以避免retain 循环)。

当您掌握它们时,它们非常方便。我建议使用 TableViews 之类的示例进行练习(NSTableView,就像我之前所说的,以类似的方式工作,只是使用不同的方法)。

【讨论】:

所以它们是一个对象在对自己做某事时调用的类。并且根据对自身所做的事情,它会从委托的类中调用某个方法。正确的?它们是创建委托类的正确方法,还是只是具有其他类碰巧调用的方法的另一个普通类? 从技术上讲,委托是一个对象。你可以有五十个实现了一些委托方法的对象实例,但只有被设置为委托的实例才会调用它的方法。创建委托的正确方法是定义一个协议,该协议定义了一组必须/可以实现的方法。 @Avizz:您说得对,委托可以是您想要的任何类型的对象。虽然通常它会是conforms to a protocol。如果一个对象符合给定的协议,它基本上意味着“我保证我已经在给定的协议中实现了我所要求的一切”。这样,当一个对象向委托人发送消息时,他们相信委托人知道该做什么. 另一件事确保我是正确的...当说单击单元格时,它使用委托对象的实例并向其发送消息。委托类有一个方法来处理它收到的内容,并且基于它收到的信息的方法做了什么?对吗? @Avizz:正确。在我的表格示例中,当单元格被选中时,表格会准备一个名为 indexPath 的对象(表示选择了哪一行),然后在上面的方法调用中将其传递给委托。所以delegate,可以像NSObject子类一样简单,实现了上面的方法。当表使用那个 indexPath 调用它时,我们的委托执行该方法,使用 indexPath,做它的事情,并返回 void。委托方法不必返回void,但这个方法可以。有些返回布尔值,有些返回浮点数(例如单元格高度)等。【参考方案4】:

委托(表示代表)是一个类(的对象),它也希望代表(继承自)另一个不相关的类。委托对象能够通过“符合”(具有一些实现)无关类所需的协议方法从其他不相关的类继承,这向外部类表明该对象现在能够适当地截取其最基本的信息。

当您希望相关类共享方法时,您可以使用继承。当您希望不相关类共享方法时,您可以使用委托。委托方法允许一个类中的对象从其他不相关的类中继承方法。 “委托对象”或“代表对象”是从外部类继承的对象;它被指定为该远程类的代表,委托,因此当您将对象作为委托分配给某个类时,您也授予它代表该类的权限,即使它通常不从该类继承. (如果它从类继承,那么您不需要将其设置为该类的委托;它已经可以访问该类的方法。但是您希望这个不相关的对象从该类继承一些方法,表示类,并将一些信息返回给它的发送者类,所以即使它继承自一组不同的类,你也让它成为该类的代表代表。)这实质上允许一个不相关的类从另一个不相关的类继承,但具有其基本继承线的并发症最少。

当您希望对象执行来自单独类的代码时,您可以使用委托系统。例如,as described here,当您在文本字段中按 Enter 时,文本字段并不真正知道如何处理该信息。它所做的是查看其委托对象的类(例如文档的窗口控制器或文档)并使用该类的相关方法,该方法符合在其文本字段委托协议中找到的文本字段的相应方法,例如 textFieldShouldReturn。因此,在这种情况下,您将窗口控制器或文档设置为文本字段的委托,因为文本字段需要该类来表示它所提供的信息。

A 类需要 B 类的方法,但 A 类没有从 B 类继承。首先告诉编译器 A 类符合 B 类协议:

@interface ClassA : NSObject <ClassBDelegateProtocol>

在 Apple 文档中,每个类引用显示在顶部,“继承自”和“符合”。例如,NSDocumentController 继承自 NSObject 并符合 NSUserInterfaceValidationsNSCodingNSObject(NSObject)NSCoding 的一致性来自 NSDocumentController.h 中的接口声明

@interface NSDocumentController : NSObject <NSCoding>

从 NSDocumentController.h 中的方法声明到 NSUserInterfaceValidations

-(BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item;

连同#import

#import <AppKit/NSUserInterfaceValidation.h>

所以虽然NSDocumentController 继承自NSObject它还需要来自NSCodingNSUserInterfaceValidation 的一些帮助。它通过符合它们的协议方法将自己定义为符合那些方法以及导入任何必要的头文件来使用这些方法来从这些外部类中获得帮助

【讨论】:

【参考方案5】:

在此处查看我关于委托设计模式的教程:http://www.jonmsterling.com/blog/?p=74。我希望这会有所帮助。

【讨论】:

【参考方案6】:

你并不孤单,我自己也在学习这个。我认为最好用文字而不是代码来解释它。有一个协议包含您想要完成的特定方法或操作。委托从协议中获取方法,因此能够使用它来促进操作或方法。我发现这篇文章很有帮助 http://rypress.com/tutorials/objective-c/protocols。希望这可以帮助。

【讨论】:

以上是关于对Objective-C中的委托有点困惑的主要内容,如果未能解决你的问题,请参考以下文章

从另一个类调用委托方法

Objective-C 中的委托

原谈谈对Objective-C中代理模式的误解

分配给委托的通用方法

Objective-C 中的“中继”委托协议是不好的做法吗?

C# 委托?这篇文章让你困惑全摆脱!