问题描述
|
好的,这似乎是一个重复的问题,但是如果您支持我并阅读了整个问题,您就会明白我为什么要提出这个问题。
我在网络上和这里都看到了许多不错的示例和说明,但是我无法理解。对我来说,理解为什么和如何操作很重要,因此与其使用文档中的一些示例(顺便说一句,我确实很了解Apple Docs,Im与PHP.net文档一起使用,还有大量示例),因为那时我只是不明白。
我想要两个课,一个gardenClass。它具有一个包含花的数组,每个花都从flowerClass实例化。因此,flowerClass不知道实例化哪种花园。有时候它只是尖叫着喝水。
因此,如果有人可以为我解释这一点,我将不胜感激!
我尝试了一下,这是我根据你们从我那里得到的信息来试一试:
我的花园
#import \"Flower.h\"
@interface MyGarden : NSObject <WateringDelegate>
{
Flower *pinkFlower;
}
@end
我的花园
#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或基金会,因为我现在尝试在这里进行与委托相关的工作...
那么,这是正确的吗?
解决方法
委托是您为应用程序实现自定义行为的地方,该行为会影响另一个类(例如Cocoa框架中的普通对象)的工作方式。
在其他不使用委托模式的语言中,您可以将对象子类化以更改其行为。使用Objective-C也可以做到这一点,但是委托的好处在于,您不必每次都要进行细微更改时都可以继承子类,一个对象可以是多个其他对象的委托。
因此,请考虑一个控制器类,该类拥有一个带有一些控件的窗口,也许是一个信息表,一个工具栏等。您可以将控制器设置为这些控件的委托,以便在控件需要有关其功能的更多信息时他们应该去找您的控制器。您可能想要自定义窗口的大小调整方式,用户在表视图中选择一行时发生的情况,信息的显示方式等等。这些都是控件使用其委托协议中定义的方法对其委托(您的控制器)进行的调用。如果幸运的话,您可以编写所有自定义代码,而无需子类化并将其拆分为多个文件。
另一个好处是您只需要实现您关心的委托方法。如果默认行为很好,则无需执行任何操作。
因此,在您的示例中,flower类将具有某种使用“ waterMe \”方法的委托协议。委托(也许是花园类,或其他所有类)可以根据您的选择来实现此目的,并且只有在花类需要时才调用该委托。值得注意的是,委派在框架中最有用,在框架中,您有一个对象以通用方式工作,可能会被覆盖以完成不同的事情。在您自己的代码中,通常可以直接将自定义行为添加到您自己的对象中,除非您确实打算以通用方式使用它。换句话说,不要试图花时间去创建一个可以正常表现的类,而实际上,您只会使它以一种特定的方式表现。
,如Marc所示,委托模式在某些情况下很有用。问题在于,苹果公司使用它们的时间远远超过了应使用的时间。特别是,Apple尝试(失败的是imo失败了)使用委托来实现基本的事件机制。
这违背了委托模式的目的,该模式将类的行为模块化为组件。事件不代表行为:它们代表(通常是独立的)根据事件发生而发生的动作(即,动作取决于事件,但是效果可能很大程度上独立于引发事件的对象)。
最大的问题是,一个事件只能有一个委托处理程序,而在其他语言中有很多有效的情况,我们可能希望有一个事件的多个独立使用者。例如,在C#中,“ 4”运算符用于将事件处理程序添加到对象的事件中,从而允许事件的观察者数量不受限制。不幸的是,Objective-C没有任何内置的事件机制,Apple的核心框架类也没有采用这种事件模式。
至少可以说使用委托进行事件。此外,由于只有一个消费者,因此消费者与生产者紧密相关。因此,另一个消费者不可能更改生产者的委托(这是可行的,但不是明智的选择)。
Apple如何使用代表进行实际事件的示例是“ 5”方法。那是一件大事。为什么只允许一件事取决于所选择的行? “解决方案”(尽管它更多的是一种解决方法)是让父级使用其子级的伪事件委托方法公开其自身的委托。但这仅意味着更多的工作和更多的出错机会。
Apple如何正确使用委托模型(就模式而言,这尤其如此)的一个示例是“ 6”方法。此方法允许用户卸载和定义tableView的行为,并且提供多个实现是没有意义的。
关于委托模式的一件好事是,它同时支持组合和继承。也就是说,您可以派生一个实现自己的委托方法的控制器类,然后可以实例化该类,或者可以简单地使用通用控件来构成您的类,并自己为该控件提供委托方法。
但是,我也不喜欢将当前(父)对象作为组件(子)对象的代表进行传递,因为这会导致类污染和概念不匹配(整个类现在只为它的组成部分之一,而不是属于类本身的概念)。更好的方法是提供一个特殊的映射对象,该对象实现必要的委托方法。但是,由于这在Objective-C中并不方便,因此不幸的是,前者最常被惯例采用。
,就目前而言,当花要喝水时,它叫
self.delegate giveWaterToFlower
。
default8ѭ默认设置为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
对象