【问题标题】:Could someone explain very simple how Objective C delegates work?有人可以非常简单地解释一下 Objective C 委托是如何工作的吗?
【发布时间】:2011-09-02 22:27:34
【问题描述】:

好吧,这似乎是一个愚蠢的问题,但如果你能忍受我并阅读整个问题,你就会明白我为什么要问这个问题。

我在网上和这里也看到了很多很好的例子和解释,但我就是不明白。了解原因和方法对我来说很重要,所以不要使用文档中的一些示例(顺便说一句,在理解 Apple Docs 时我真的很烂,我使用 php.net 文档,有大量示例),因为那时我只是不明白。

我想要两个课程,一个 gardenClass。它有一个花数组,每朵花都是从花类中实例化的。所以,flowerClass 不知道实例化了什么样的花园。它有时只是尖叫着要水。

所以,如果这里有人可以为我解释一下,我将非常感激!

我试过了,根据我从你们那里得到的信息,这是我的尝试:

我的花园.h

#import "Flower.h"

@interface MyGarden : NSObject <WateringDelegate>
{
    Flower *pinkFlower;
}
@end

我的花园.m

#import "MyGarden.h"
#import "Flower.h"

@implementation MyGarden

- (void) giveWaterToFlower
{
    NSLog(@"Watering Flower");
}

- (void)viewDidLoad
{
    pinkFlower = [[Flower alloc] init];
    [pinkFlower setDelegate:self];
    [pinkFlower startToGrow];
}
@end

花.h

@protocol WateringDelegate <NSObject>
@required
- (void) giveWaterToFlower;
@end

@interface Flower : NSObject
{
    id <WateringDelegate> delegate;
}

@property (retain) id delegate;
- (void) startToGrow;
@end

花.m

#import "Flower.h"

@implementation Flower

@synthesize delegate;

- (void) needWater
{
    [[self delegate] giveWaterToFlower];
}

- (void) startToGrow
{
    [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(needWater) userInfo:nil repeats:YES];
}
@end

我还没有导入任何 UIKit 或基础,因为我现在试图在这里做与代表相关的事情...... 那么,这是正确的吗?

【问题讨论】:

  • 不清楚问题是什么;特别是在您的问题/示例中没有提及代表。现在我猜你想看看如何在花卉类上设置一个代表以指向花园,但那是我跳到一个假设,因为这里没有明确要求。
  • 他想了解委托设计模式。对我来说似乎是一个非常简单的问题。
  • 我这里有个解释:stackoverflow.com/questions/1045803/…

标签: objective-c delegates


【解决方案1】:

委托是您为应用实现自定义行为的地方,它会影响另一个类(例如 Cocoa 框架中的普通对象)的工作方式。

在其他不使用委托模式的语言中,您可以对对象进行子类化以更改其行为。 Objective-C 也允许您这样做,但委托的好处是您不必每次想要进行微小更改时都进行子类化,一个对象可以是多个其他对象的委托。

所以考虑一个控制器类,它拥有一个带有一些控件的窗口,可能是一个信息表、一个工具栏等。您可以将控制器设置为这些控件的委托,这样当控件需要更多关于什么的信息时他们应该这样做,他们可以查看您的控制器。您可能希望自定义窗口大小的调整方式、用户在表格视图中选择一行时发生的情况、信息的呈现方式等等。这些都是控件使用其委托协议中定义的方法对其委托(您的控制器)进行的调用。如果幸运的话,您可以编写所有自定义代码,而无需子类化并将其拆分为多个文件。

另一个好处是你只需要实现你关心的委托方法。如果默认行为正常,则无需执行任何操作。

因此,在您的示例中,花类将具有某种带有“waterMe”方法的委托协议。委托(可能是花园类,或其他东西)可以根据您的选择实现这一点,并且只有在花卉类需要时才会调用它。值得注意的是,委托在框架中最有用,在框架中,您有一个以通用方式工作的对象,可能会被覆盖以完成不同的事情。在您自己的代码中,通常更直接地将自定义行为添加到您自己的对象中,除非您真的打算以通用方式使用它。换句话说,不要试图花时间创建一个可以通用行为的类,而实际上您只会让它以一种特定的方式运行。

【讨论】:

  • 很好的答案!我想这是迄今为止我读过的最好的解释。你能不能给我举个例子,教我怎么做花园和花卉课?
  • 好的。我会努力为自己和你们证明我现在真的学到了一些东西。
【解决方案2】:

委托模式在某些情况下很有用,如 Marc 所示。问题在于,Apple 使用它们的用途远远超出了应有的用途。特别是,Apple 已经尝试(并且惨败,imo)使用委托来实现基本的事件机制。

这违背了委托模式的目的,即把一个类的行为模块化成组件。事件不代表行为:它们代表(通常是独立的)动作,这些动作依赖于事件的发生(也就是说,动作依赖于事件,但效果可能在很大程度上独立于发生的对象引发了事件)。

最大的问题是你只能有一个事件的委托处理程序,而在其他语言中有许多有效的情况,我们可能希望有多个独立的事件消费者。例如,在 C# 中,+= 运算符用于将事件处理程序添加到对象的事件中,从而允许无限数量的事件观察者。遗憾的是,Objective-C 没有任何类型的内置事件机制,Apple 的核心框架类也没有采用事件模式。

至少可以说,将委托用于事件是有限的。此外,消费者与生产者紧密绑定,因为只能有一个消费者。因此,另一个消费者无法更改生产者的代表(当然这是可能的,但不明智)。

tableView:didSelectRowAtIndexPath 方法是 Apple 如何将委托用于实际上事件的一个示例。那是一个事件。为什么只允许一件事依赖于选择的行? “解决方案”(尽管它更像是一种解决方法)是让父级使用其自己的伪事件委托方法为其子级公开其自己的委托。但这只是意味着更多的工作和更多的出错机会。

Apple 如何正确使用委托模型的一个示例(就模式而言)是tableView:cellForRowAtIndexPath 方法。这种方法允许 tableView 的 behavior 被消费者卸载和定义,提供多个实现是没有意义的。

委托模式的一个优点是它同样支持组合和继承。也就是说,您可以派生一个实现自己的委托方法的控制器类,然后您可以对其进行实例化,或者您可以简单地使用泛型控件组合您的类并自己为该控件提供委托方法。

但是,我也不喜欢将当前(父)对象作为组件(子)对象的委托传递,因为这会导致类污染和概念不匹配(整个类现在都在提供行为只是它的一个组件,而不是属于类本身的概念)。更好的方法是提供一个特殊的映射对象来实现必要的委托方法。然而,由于这在 Objective-C 中并不方便,不幸的是,前者最常按惯例使用。

【讨论】:

    【解决方案3】:

    就目前而言,当花需要水时,它会调用self.delegate giveWaterToFlowerdelegate默认设置为MyGarden,所以当花要水的时候会调用MyGarden中的giveWaterToFlower方法。如果你实现了一个wateringCan 对象,那么wateringCan 可以做[pinkFlower setDelegate:self]; 然后,当花需要水时,self.delegate giveWaterToFlower 会调用wateringCan 中的giveWaterToFlower 方法,这可能会比默认。同样,您可以实现一个gardenHose 对象,该对象还提供了一个giveWaterToFlower 方法。花园软管可能只能与花园达到一定的距离,因此可能只会覆盖特定花朵中的代表。

    但设计模式是flower委派它是giveWaterToFlower 方法到另一个对象。 flower 对象不知道是谁在提供它的 giveWaterToFlower 方法。您可以在flower 中包含一个默认的giveWaterToFlower 方法,并使用self.delegate = self; 初始化您的flower 对象

    【讨论】:

      猜你喜欢
      • 2013-04-07
      • 1970-01-01
      • 2011-05-06
      • 1970-01-01
      • 1970-01-01
      • 2021-05-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多