【问题标题】:I need to understand why delegation in Objective-C is so important, what makes it so special?我需要了解为什么 Objective-C 中的委托如此重要,是什么让它如此特别?
【发布时间】:2014-11-07 17:28:12
【问题描述】:

所以我已经阅读了很多关于委托的解释和实践,但我似乎仍然不明白,我有一些具体的问题,我很想得到一些有见地的简单答案。

  1. 为什么使用委托而不是实例方法?在UIAlertView 中,为什么不直接将– alertView:clickedButtonAtIndex: 设置为将在我的UIAlertView 实例上调用的实例方法?

  2. 什么是委托属性?为什么我必须创建委托属性并用奇怪的语法定义它@property (nonatomic, strong) id <ClassesDelegate> delegate

  3. 委托和协议是硬币的两个面吗?

  4. 我什么时候知道应该在我的应用中实现委托而不是直接调用?

  5. 代理在 Swift 中的使用率和重要性一样吗?

  6. 首先调用什么,为什么?类中使自己成为委托的方法?还是在声明它的类中的委托方法本身?

感谢您抽出宝贵的时间阅读本文,我迫切希望为我的问题寻找一个清晰而有用的答案,请随时举例或涵盖一些相关主题!

【问题讨论】:

  • 委托是一种设计模式。它可以用任何语言实现。它不是 Objective-C 特有的。
  • Delegation 真棒,delegate 不应该是strong,应该是weak
  • @maddy 警告历史:虽然在 1993 年左右确实如此,但主要在 Cargile 和 Stroustrup(猜猜谁赢了)之间就两个主要问题就 C++ 的方向进行了辩论。 1. 多重继承 2. 委托。 Cargile 希望它成为 C++ 的一等公民。 Stroustrup 辩称,他从未见过一种既不是玩具,也不是令人费解且难以理解的委托用法。
  • 我来自 Windows PC C++ 背景,所以我想到 Objective-C 的委托就像我想到 Window 的回调一样。两种环境中的底层操作系统有时都需要一种“回电”的方式,并且您需要向操作系统提供有关您希望被回电的位置的信息。尝试以这种方式思考它,看看它是否有帮助。起初我很困惑,因为“代表团”这个词似乎在做一些我没有理解的神秘事情。
  • @Gallymon 我理解这个概念,我不太清楚它的技术实现。

标签: ios objective-c swift delegates delegation


【解决方案1】:

委托的优点是依赖倒置。

通常代码具有与运行时调用依赖相同方向的编译时依赖。如果是这种情况,UITableview 类将在编译时依赖于我们的代码,因为它会调用我们的代码。通过使用委托,这是反转的,我们的代码在编译时依赖于 UITableview 类,但 UITableview 类在运行时调用我们的代码。

这涉及到一个成本:我们需要设置委托,而 UITableview 必须在运行时检查委托方法是否已实现。

注意:当我说UITableview 时,我包括UITableviewDelegateUITableviewDatasource

请参阅:Dependency inversion principleClean Code, Episode 13

【讨论】:

  • 我正在尽我所能掌握你刚才所说的话。
【解决方案2】:

也许一个真实的例子可以更好地描述委托设计模式的不同之处。

假设您开了一家新公司,并且您有一位会计师来处理官僚事务。

场景 #1

你去他的办公室,给他所需的信息:

  • 公司名称
  • 公司编号/id
  • 员工人数
  • 电子邮件地址
  • 街道地址

然后会计师会将数据存储在某个地方,并且可能会告诉您“如果有任何变化,请不要忘记给我打电话”

明天您雇用了一位新员工,但忘记通知您的会计师。他仍会使用您提供给他的原始过时数据。

场景 #2

使用委托模式,您可以去找您的会计师,然后向他提供您的电话号码(委托人),仅此而已。

稍后,他会打电话给你,问:公司名称是什么?

稍后,他会打电话给你,问:你有多少员工?

稍后,他会打电话给你,问:你的公司地址是什么?

雇用新员工后的第二天。

2天后,他会打电话问你:你有多少员工?

在委托模型(场景 #2)中,您会看到您的会计师总是会按需获取最新数据,因为他每次需要数据时都会给您打电话。这就是“不要打电话给我,我会打电话给你”在谈论控制反转时的意思(从会计的角度来看)。

在开发中转换它,例如填充一个表,您有 2 个选项:

  • 实例化一个表格控件,传递所有数据(要显示的项目列表),然后让表格自己呈现
  • 实例化一个表格控件,给它一个指向委托的指针,让它在需要知道的时候调用委托:
    • 表中的行数
    • 要在第 1 行显示的数据。 n
    • 行号的高度。 n 应该有
    • 等。 但也适用于:
    • 行号。 n 已被点击
    • 标题已被点击

【讨论】:

    【解决方案3】:

    首先,如果事情还不清楚,请不要感到难过。这是一个很好的例子,一开始看起来很棘手,但真正点击需要时间。这会在你知道之前发生:-)。我会试着回答你上面的每一个观点:

    1) 这样想——UIAlertView 现在的工作方式,它允许 Apple 将 alertView:clickedButtonAtIndex: 的实现“委托”给你。如果这是 UIAlertView 的一个实例方法,对每个人来说都是相同的实现。然后,要自定义实现将需要子类化——通常过度依赖设计模式。 Apple 在他们的框架中倾向于使用组合而不是继承,这就是一个例子。您可以在此处阅读有关该概念的更多信息:http://en.wikipedia.org/wiki/Composition_over_inheritance

    2) 委托属性是对实现委托方法的对象的引用,它应该用于“委托”这些任务。奇怪的语法只是意味着这一点 - 一个包含对遵守协议的对象的引用的属性。

    3) 不完全——委托利用协议作为其实现的一种手段。在上面的示例中,这是一个协议的名称,可以被视为该类的委托的对象必须遵守该协议的名称。在该协议中定义了该类的委托必须实现的方法。你也可以有可选的协议方法,但这是另一个话题。

    4) 如果我正确理解了这个问题,我认为您可能希望实现委托而不是简单地将实例方法添加到您的对象的一个​​好兆头是,当您认为您可能希望实现这些方法时轻松更换或更换。当这些方法的实现根据您的建筑物的功能使用地点/方式发生显着变化时

    5) 绝对! Objective-C 和 Swift 是编程语言,委托模式是设计模式的一个例子。一般来说,设计模式是跨越编程语言垂直领域的横向概念。

    6) 我不确定我是否完全理解你,但我认为问题中存在一些误解 - 该方法不会被调用两次。在委托协议中声明的方法被调用一次——通常来自包含委托属性的类。该类通过以下方式调用该属性的委托实现:

    [self.delegate someMethodThatMyDelegateImplemented];

    我希望这会有所帮助!

    【讨论】:

    • 感谢您的解释。但是,我仍然不确定我是否得到了委托属性部分,您可以尝试用另一种方式解释吗?
    • 另外,我可以使用没有协议的委托模式吗?那会是什么样子?
    • 为什么我从我的标题中删除了代理并且应用程序仍然可以运行,它只会警告我?为什么我能够使用委托类中的协议方法而不说我符合该委托,并且它有效? Assigning to 'id<ClassesDelegate>' from incompatible type 'ViewController *const __strong'
    【解决方案4】:
    1. 有时您希望您的 UIAlertView 在不同的上下文中以不同的方式工作。如果您将自定义 UIAlertView 设置为自身的委托,则它必须提供所有这些上下文(大量 if/else 语句)。您还可以为每个上下文设置单独的委托。
    2. 这样你就可以告诉你的编译器每个实现协议 ClassesDelegate 的类 (id) 都可以设置为这个属性。附带说明一下,它通常应该是 weak 而不是 strong 以不引入引用循环(A 类持有 B,B 类持有 A)
    3. 协议(其他语言的接口)用于定义应由类实现的方法集。如果类符合协议,您可以在不了解特定类的情况下调用此方法。委托是 A 类将一些工作委托给 B 类的模式(例如,抽象打印机委托他的工作真实打印机)
    4. 当您需要一些取决于上下文的不同行为时(例如,ContactsViewController 需要在下载完成时刷新他的列表,但SingleContactViewController 需要重新加载图像、标签等)
    5. 它是编程中最基本的模式之一,所以是的。
    6. 方法一样

    【讨论】:

    • 注意:“需要的方法” 但并非所有的委托方法都需要在 Apple 的委托模式实现中。
    • 谢谢,有一些不清楚的地方,会继续努力的。
    【解决方案5】:

    你不能只给 UIAlertView 添加一个方法,因为你没有源代码。你必须继承 UIAlertView。但是由于您不止一次使用 UIAlertView,因此您需要几个子类。这很不方便。

    现在假设您使用了一个 UIAlertView 的子类库,提供了更多功能。这很麻烦,因为现在你需要继承这个子类而不是 UIAlertView。

    现在假设库使用不同的 UIAlertview 子类,具体取决于您是在 iOS 7 还是 8 上运行,而 UIAlertview 在 iOS 6 上保持不变。你有麻烦了。您的子类化模式崩溃了。

    相反,您创建一个委托来执行特定于一个 UIAlertview 的所有事情。该代表将与图书馆一起工作得很好。与其继承一个庞大而复杂的类,不如编写一个非常简单的类。很可能使用 UIAlertview 的代码确切地知道委托应该做什么,因此您可以将这些代码放在一起。

    【讨论】:

    • 对不起,我可能说得不好,但我的意思是为什么苹果不让UIAlerView 有实例方法来处理按钮操作等。然后为我应用它,当我决定做一个委托,为什么不通过导入该类并使用实例/类方法和直接调用来做我想做的事情?
    猜你喜欢
    • 1970-01-01
    • 2013-09-07
    • 2019-11-06
    • 1970-01-01
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    • 2016-03-26
    相关资源
    最近更新 更多