如何在 Objective-C 中创建委托?

How do I create delegates in Objective-C?

提问人:Andy Jacobs 提问时间:3/10/2009 最后编辑:Wayne ChenAndy Jacobs 更新时间:1/30/2023 访问量:384131

问:

我知道委托是如何工作的,我也知道如何使用它们。

但是我该如何创建它们呢?

iOS Objective-C Cocoa 回调 委托

评论

2赞 Deepakraj Murugesan 8/3/2015
在 Objective-C 中创建委托的示例

答:

918赞 Jesse Rusak 3/10/2009 #1

Objective-C 委托是已分配给属性另一个对象的对象。若要创建一个,请定义一个实现您感兴趣的委托方法的类,并将该类标记为实现委托协议。delegate

例如,假设您有一个 .如果要实现其委托的 webViewDidStartLoad: 方法,可以创建如下类:UIWebView

@interface MyClass<UIWebViewDelegate>
// ...
@end

@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView { 
    // ... 
}
@end

然后,您可以创建一个 MyClass 的实例,并将其分配为 Web 视图的委托:

MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;

另一方面,它可能具有与此类似的代码,以查看委托是否使用 respondsToSelector: 响应消息,并在适当时发送它。UIWebViewwebViewDidStartLoad:

if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
    [self.delegate webViewDidStartLoad:self];
}

委托属性本身通常声明(在 ARC 中)或(在 ARC 之前)以避免保留循环,因为对象的委托通常包含对该对象的强引用。(例如,视图控制器通常是它所包含的视图的委托。weakassign

为类创建委托

要定义你自己的委托,你必须在某处声明他们的方法,如关于协议的 Apple Docs 中所述。您通常会声明一个正式的协议。从 UIWebView.h 转述的声明如下所示:

@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end

这类似于接口或抽象基类,因为在本例中,它为委托创建特殊类型。委托实现者必须采用以下协议:UIWebViewDelegate

@interface MyClass <UIWebViewDelegate>
// ...
@end

然后实现协议中的方法。对于在协议中声明为(与大多数委托方法一样)的方法,您需要在调用特定方法之前进行检查。@optional-respondsToSelector:

命名

委托方法通常以委托类名称开头命名,并将委托对象作为第一个参数。他们也经常使用遗嘱、应该或确实的形式。因此,例如,(第一个参数是 Web 视图)而不是(不带参数)。webViewDidStartLoad:loadStarted

速度优化

您可以在设置委托时缓存该信息,而不是在每次我们想要向它发送消息时检查委托是否响应选择器。一种非常干净的方法是使用位域,如下所示:

@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end

@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end

@implementation Something {
  struct {
    unsigned int didFinishLoadingItem:1;
    unsigned int didFailWithError:1;
  } delegateRespondsTo;
}
@synthesize delegate;

- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;

    delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
    delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
  }
}
@end

然后,在正文中,我们可以检查我们的委托是否通过访问我们的结构来处理消息,而不是一遍又一遍地发送。delegateRespondsTo-respondsToSelector:

非正式代表

在协议出现之前,通常使用类别 on 来声明委托可以实现的方法。例如,仍然这样做:NSObjectCALayer

@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end

这告诉编译器任何对象都可以实现 .displayLayer:

然后,您将使用与上述相同的方法来调用此方法。委托实现此方法并分配属性,仅此而已(没有声明您符合协议)。这种方法在 Apple 的库中很常见,但新代码应该使用上面更现代的协议方法,因为这种方法会造成污染(这使得自动完成功能不那么有用),并使编译器很难警告您拼写错误和类似错误。-respondsToSelector:delegateNSObject

评论

0赞 Roland 11/25/2013
我认为您需要将类型转换为 is 类型的返回值。unsigned intBOOLdelegate respondsToSelectorBOOL
0赞 4/23/2015
委托可以像在 C++ 中那样用于多态性吗?
0赞 Jesse Rusak 4/24/2015
@Dan 是的,当然。通常,协议用于多态性。
0赞 Hans Knöchel 1/24/2017
@JesseRusak我认为“JSSomethingDelegate”应该是“SomethingDelegate”以实现一致性:)
17赞 Tom Andersen 3/10/2009 #2

也许这更符合你所缺少的东西:

如果你是从类似 C++ 的角度来看的,委托需要一点时间来适应——但基本上“他们只是工作”。

它的工作方式是将编写的某个对象作为委托设置为 NSWindow,但您的对象只有许多可能的委托方法中的一个或几个的实现(方法)。所以发生了一些事情,想要调用你的对象——它只是使用 Objective-c 的方法来确定你的对象是否希望调用该方法,然后调用它。这就是 objective-c 的工作原理 - 按需查找方法。NSWindowrespondsToSelector

用你自己的对象来做这件事是完全微不足道的,没有什么特别的事情发生,例如,你可以有 27 个对象,所有不同类型的对象,只有 18 个,其中一些有方法,其他 9 个没有。因此,要召集所有需要完成的 18 个,如下所示:NSArray-(void)setToBue;setToBlue

for (id anObject in myArray)
{
  if ([anObject respondsToSelector:@selector(@"setToBlue")])
     [anObject setToBlue]; 
}

关于委托的另一件事是它们不会被保留,因此您始终必须在方法中将委托设置为。nilMyClass dealloc

18赞 umop 5/5/2010 #3

当使用正式协议方法创建委托支持时,我发现您可以通过添加如下内容来确保正确的类型检查(尽管是运行时,而不是编译时):

if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
    [NSException raise:@"MyDelegate Exception"
                format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}

在委托访问器 (setDelegate) 代码中。这有助于最大限度地减少错误。

397赞 Tibidabo 9/30/2012 #4

批准的答案很好,但如果您正在寻找 1 分钟的答案,请尝试以下方法:

MyClass.h 文件应如下所示(添加带有注释的委托行!

#import <BlaClass/BlaClass.h>

@class MyClass;             //define class, so protocol can see MyClass
@protocol MyClassDelegate <NSObject>   //define delegate protocol
    - (void) myClassDelegateMethod: (MyClass *) sender;  //define delegate method to be implemented within another class
@end //end protocol

@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //define MyClassDelegate as delegate

@end

MyClass.m 文件应如下所示

#import "MyClass.h"
@implementation MyClass 
@synthesize delegate; //synthesise  MyClassDelegate delegate

- (void) myMethodToDoStuff {
    [self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class    
}

@end

若要在另一个类(在本例中称为 MyVC 的 UIViewController)中使用委托,请执行以下操作:

#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}

我的VC.m:

myClass.delegate = self;          //set its delegate to self somewhere

实现委托方法

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}

评论

4赞 Arno van der Meer 4/25/2013
很高兴将这个答案用作快速参考。但是,为什么 MyClass.h 中的委托属性被标记为“IBOutlet”?
4赞 Tibidabo 4/28/2013
@ArnovanderMeer 好渔获!我不记得为什么了。我在我的项目中需要它,但在此示例中不需要它,我删除了它。感谢
0赞 sudo 3/13/2014
谢谢。尽管公认的答案很好,也很彻底,但我从一些紧凑的示例代码中学到了最好的东西。有两个答案是件好事。
0赞 Charles Robertson 11/27/2016
@Tibidabo 非常出色。我真的希望每个人都能像这样解释编程概念。多年来,我看过数百种关于“代表”的解释,但直到现在才真正掌握这个理论!非常感谢。。。
7赞 Lane Rettig 2/10/2017
MyVC.m 中的实例化在哪里?myClass
16赞 swiftBoy 2/27/2013 #5

请!查看以下简单的分步教程,了解 Delegates 在 iOS 中的工作原理。

iOS 中的委托

我创建了两个ViewController(用于将数据从一个发送到另一个)

  1. FirstViewController 实现委托(提供数据)。
  2. SecondViewController 声明委托(将接收数据)。
11赞 DrBug 6/19/2013 #6

我认为,一旦你理解了代表,所有这些答案都很有意义。就我个人而言,我来自C / C++的土地,在此之前,像Fortran等过程语言,所以这是我在C++范式中寻找类似物的2分钟。

如果我向C++/Java程序员解释委托,我会说

什么是委托? 这些是指向另一个类中的类的静态指针。分配指针后,可以调用该类中的函数/方法。因此,类的某些函数被“委托”到另一个类(在 C++ 世界中 - 由类对象指针指向的指针)。

什么是协议? 从概念上讲,它的作用与作为委托类分配的类的头文件类似。协议是一种显式方式,用于定义需要在类中将指针设置为类中的委托的类中需要实现哪些方法。

如何在 C++ 中做类似的事情? 如果尝试在 C++ 中执行此操作,则可以通过在类定义中定义指向类(对象)的指针,然后将它们连接到其他类,这些类将提供其他函数作为基类的委托。但是这种接线需要在代码中进行,并且会很笨拙且容易出错。目标 C 只是假设程序员不擅长维护这一准则,并提供编译器限制来强制执行干净的实现。

评论

0赞 DrBug 12/23/2014
你说的是语义,而我说的是直觉。你说的是虚拟功能,但仅仅习惯新术语就可能具有挑战性。答案适合那些想在 C++/C 中思考 paralell 的初学者
0赞 DrBug 12/29/2014
你在说什么,我不太清楚。你为什么不写一个新的回复,让我们看看如果更多的人觉得它有用,他们会投票支持它?
10赞 Tibidabo 7/17/2013 #7

好吧,这并不是这个问题的真正答案,但如果你正在寻找如何制作自己的代表,也许更简单的东西对你来说可能是一个更好的答案。

我几乎不执行我的委托,因为我很少需要。对于一个委托对象,我只能有一个委托。因此,如果您希望您的委托进行单向通信/传递数据,那么通知要好得多。

NSNotification 可以将对象传递给多个收件人,并且非常易于使用。 它的工作原理如下:

MyClass.m 文件应如下所示

#import "MyClass.h"
@implementation MyClass 

- (void) myMethodToDoStuff {
//this will post a notification with myClassData (NSArray in this case)  in its userInfo dict and self as an object
[[NSNotificationCenter defaultCenter] postNotificationName:@"myClassUpdatedData"
                                                    object:self
                                                  userInfo:[NSDictionary dictionaryWithObject:selectedLocation[@"myClassData"] forKey:@"myClassData"]];
}
@end

要在其他课程中使用您的通知,请执行以下操作: 将类添加为观察者:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];

实现选择器:

- (void) otherClassUpdatedItsData:(NSNotification *)note {
    NSLog(@"*** Other class updated its data ***");
    MyClass *otherClass = [note object];  //the object itself, you can call back any selector if you want
    NSArray *otherClassData = [note userInfo][@"myClassData"]; //get myClass data object and do whatever you want with it
}

如果出现以下情况,请不要忘记删除作为观察者的类

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
15赞 Jean 8/4/2013 #8

作为 Apple 推荐的良好做法,委托(根据定义,这是一种协议)符合协议是件好事。NSObject

@protocol MyDelegate <NSObject>
    ...
@end

& 要在委托中创建可选方法(即不一定需要实现的方法),您可以使用如下注解:@optional

@protocol MyDelegate <NSObject>
    ...
    ...
      // Declaration for Methods that 'must' be implemented'
    ...
    ...
    @optional
    ...
      // Declaration for Methods that 'need not necessarily' be implemented by the class conforming to your delegate
    ...
@end

因此,当使用指定为可选的方法时,您需要(在类中)检查视图(符合您的委托)是否实际实现了您的可选方法。respondsToSelector

8赞 m.eldehairy 4/8/2015 #9

假设您有一个开发的类,并且想要声明一个委托属性,以便在发生某些事件时能够通知它:

@class myClass;

@protocol myClassDelegate <NSObject>

-(void)myClass:(MyClass*)myObject requiredEventHandlerWithParameter:(ParamType*)param;

@optional
-(void)myClass:(MyClass*)myObject optionalEventHandlerWithParameter:(ParamType*)param;

@end


@interface MyClass : NSObject

@property(nonatomic,weak)id< MyClassDelegate> delegate;

@end

所以你在头文件(或单独的头文件)中声明了一个协议,并声明了你的委托必须/应该实现的必需/可选的事件处理程序,然后在类型()中声明一个属性,这意味着任何符合协议的目标C类,你会注意到委托属性被声明为弱,这对于防止保留周期非常重要(大多数情况下,委托会保留实例,所以如果你声明了委托作为保留,他们俩都会互相保留,他们都不会被释放)。MyClassMyClassid< MyClassDelegate>MyClassDelegateMyClass

您还会注意到,协议方法将实例作为参数传递给委托,这是最佳实践,以防委托想要在实例上调用某些方法,并且当委托声明自己为多个实例时也会有所帮助,例如当您有多个实例并声明自己为所有实例时。MyClassMyClassMyClassDelegateMyClassUITableView'sViewControllerUITableViewDelegate

在你的内部,你用声明的事件通知委托,如下所示:MyClass

if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
     [_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}

首先检查委托是否响应了将要调用的协议方法,以防委托未实现它,然后应用将崩溃(即使需要协议方法)。

7赞 Mahesh 8/3/2015 #10

若要创建自己的委托,首先需要创建一个协议并声明必要的方法,而不实现。然后将此协议实现到要实现委托或委托方法的头类中。

协议必须声明如下:

@protocol ServiceResponceDelegate <NSObject>

- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;

@end

这是应该完成某些任务的服务类。它演示如何定义委托以及如何设置委托。在实现类中,任务完成后,将调用委托的方法。

@interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}

- (void) setDelegate:(id)delegate;
- (void) someTask;

@end

@implementation ServiceClass

- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}

- (void) someTask
{
/*

   perform task

*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:@”task failed”];
}
else
{
[_delegate serviceDidFinishedSucessfully:@”task success”];
}
}
@end

这是主视图类,通过将委托设置为自身,从中调用服务类。并且该协议是在标头类中实现的。

@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}

- (void) go;

@end

@implementation viewController

//
//some methods
//

- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}

就是这样,通过在此类中实现委托方法,一旦操作/任务完成,控制权就会回来。

6赞 soumya 9/29/2015 #11

下面是创建委托的简单方法

在 .h 文件中创建协议。请确保在协议之前使用 @class 后跟 UIViewController 的名称进行定义< As the protocol I am going to use is UIViewController class>.

步骤 : 1 :创建一个名为“YourViewController”的新类 Protocol,它将是 UIViewController 类的子类,并将此类分配给第二个 ViewController。

步骤 : 2 :转到“YourViewController”文件并修改它,如下所示:

#import <UIKit/UIkit.h>
@class YourViewController;

@protocol YourViewController Delegate <NSObject>

 @optional
-(void)defineDelegateMethodName: (YourViewController *) controller;

@required
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller;

  @end
  @interface YourViewController : UIViewController

  //Since the property for the protocol could be of any class, then it will be marked as a type of id.

  @property (nonatomic, weak) id< YourViewController Delegate> delegate;

@end

协议行为中定义的方法可以通过@optional和@required作为协议定义的一部分进行控制。

步骤: 3 : 委托的实现

    #import "delegate.h"

   @interface YourDelegateUser ()
     <YourViewControllerDelegate>
   @end

   @implementation YourDelegateUser

   - (void) variousFoo {
      YourViewController *controller = [[YourViewController alloc] init];
      controller.delegate = self;
   }

   -(void)defineDelegateMethodName: (YourViewController *) controller {
      // handle the delegate being called here
   }

   -(BOOL)delegateMethodReturningBool: (YourViewController *) controller {
      // handle the delegate being called here
      return YES;
   }

   @end

在调用方法之前测试该方法是否已定义

 - (void) someMethodToCallDelegate {
     if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
           [self.delegate delegateMethodName:self]; 
     }
  }
11赞 Suragch 11/6/2015 #12

Swift 版本

委托只是一个为另一个类做一些工作的类。阅读下面的代码,了解一个有点傻(但希望有启发性)的 Playground 示例,该示例展示了如何在 Swift 中完成此操作。

// A protocol is just a list of methods (and/or properties) that must
// be used by any class that adopts the protocol.
protocol OlderSiblingDelegate: class {
    // This protocol only defines one required method
    func getYourNiceOlderSiblingAGlassOfWater() -> String
}

class BossyBigBrother {
    
    // The delegate is the BossyBigBrother's slave. This position can 
    // be assigned later to whoever is available (and conforms to the 
    // protocol).
    weak var delegate: OlderSiblingDelegate?
    
    func tellSomebodyToGetMeSomeWater() -> String? {
        // The delegate is optional because there might not be anyone
        // nearby to boss around.
        return delegate?.getYourNiceOlderSiblingAGlassOfWater()
    }
}

// PoorLittleSister conforms to the OlderSiblingDelegate protocol
class PoorLittleSister: OlderSiblingDelegate {

    // This method is repquired by the protocol, but the protocol said
    // nothing about how it needs to be implemented.
    func getYourNiceOlderSiblingAGlassOfWater() -> String {
        return "Go get it yourself!"
    }
    
}

// initialize the classes
let bigBro = BossyBigBrother()
let lilSis = PoorLittleSister()

// Set the delegate 
// bigBro could boss around anyone who conforms to the 
// OlderSiblingDelegate protocol, but since lilSis is here, 
// she is the unlucky choice.
bigBro.delegate = lilSis

// Because the delegate is set, there is a class to do bigBro's work for him.
// bigBro tells lilSis to get him some water.
if let replyFromLilSis = bigBro.tellSomebodyToGetMeSomeWater() {
    print(replyFromLilSis) // "Go get it yourself!"
}

在实际操作中,委托经常用于以下情况

  1. 当一个类需要将一些信息传达给另一个类时
  2. 当一个类想要允许另一个类自定义它时

除了委托类符合所需的协议外,这些类不需要事先了解彼此的任何信息。

我强烈建议您阅读以下两篇文章。他们帮助我比文档更了解代表。

0赞 Vaibhav Gaikwad 12/8/2016 #13

委托 :- 创建

@protocol addToCartDelegate <NSObject>

-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;

@end

发送并请指派委托人查看您正在发送的数据

[self.delegate addToCartAction:itemsModel isAdded:YES];
2赞 Lal Krishna 12/19/2016 #14

ViewController.h

@protocol NameDelegate <NSObject>

-(void)delegateMEthod: (ArgType) arg;

@end

@property id <NameDelegate> delegate;

ViewController.m的

[self.delegate delegateMEthod: argument];

MainViewController.m

ViewController viewController = [ViewController new];
viewController.delegate = self;

方法:

-(void)delegateMEthod: (ArgType) arg{
}
0赞 Rohit Kashyap 1/3/2017 #15
//1.
//Custom delegate 
@protocol TB_RemovedUserCellTag <NSObject>

-(void)didRemoveCellWithTag:(NSInteger)tag;

@end

//2.
//Create a weak reference in a class where you declared the delegate
@property(weak,nonatomic)id <TB_RemovedUserCellTag> removedCellTagDelegate;

//3. 
// use it in the class
  [self.removedCellTagDelegate didRemoveCellWithTag:self.tag];

//4. import the header file in the class where you want to conform to the protocol
@interface MyClassUsesDelegate ()<TB_RemovedUserCellTag>

@end

5.在类 .m 中实现该方法 -(void)didRemoveCellWithTag:(NSInteger)标签 { NSLog@(“标记 %d”,标记);

}

2赞 User558 2/8/2017 #16

在我看来,为该委托方法创建单独的类,您可以在想要的地方使用。

在我的自定义 DropDownClass.h 中

typedef enum
{
 DDSTATE,
 DDCITY
}DropDownType;

@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString     DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
 BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;

之后,in.m 文件创建带有对象的数组,

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}

if (self.delegate) {
    if (self.dropDownType == DDCITY) {
        cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
    }
    else if (self.dropDownType == DDSTATE) {
        cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
    }
}
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
 [self dismissViewControllerAnimated:YES completion:^{
    if(self.delegate){
        if(self.dropDownType == DDCITY){
            [self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
        }
        else if (self.dropDownType == DDSTATE) {
            [self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
        }
    }
}];
}

这里都设置了自定义委托类。之后,您可以在需要的地方使用此委托方法。例如...

在那之后我的另一个 viewcontroller 导入中

创建用于调用委托方法的操作,如下所示

- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}

之后调用委托方法,如下所示

- (void)dropDownDidSelectItemWithString:(NSString *)itemString DropDownType:(DropDownType)dropDownType {
switch (dropDownType) {
    case DDCITY:{
        if(itemString.length > 0){
            //Here i am printing the selected row
            [self.dropDownBtn1 setTitle:itemString forState:UIControlStateNormal];
        }
    }
        break;
    case DDSTATE: {
        //Here i am printing the selected row
        [self.dropDownBtn2 setTitle:itemString forState:UIControlStateNormal];
    }

    default:
        break;
}
}
5赞 James Rochabrun 4/26/2017 #17

免责声明:这是如何创建 .Swiftdelegate

那么,什么是代表?...在软件开发中,有一些通用的可重用解决方案架构,有助于解决给定上下文中常见的问题,可以说,这些“模板”最广为人知的是设计模式。 委托是一种设计模式,它允许一个对象在特定事件发生时向另一个对象发送消息。 想象一下,一个对象 A 调用一个对象 B 来执行一个动作。一旦动作完成,对象 A 应该知道 B 已经完成了任务并采取必要的行动,这可以在委托的帮助下实现!

为了更好地解释,我将向你展示如何创建一个在类之间传递数据的自定义委托,在一个简单的应用程序中使用 Swift,首先下载或克隆这个入门项目并运行它!

您可以看到一个应用具有两个类,并且 .B 有两个视图,在点击时会改变背景颜色,没什么太复杂的吧?好吧,现在让我们以一种简单的方式思考,当点击 B 类的视图时,也可以更改 A 类的背景颜色。ViewController AViewController BViewController

问题在于,这种观点是 B 类的一部分,对 A 类一无所知,所以我们需要找到一种在这两个类之间进行交流的方法,这就是授权的亮点所在。 我将实现分为 6 个步骤,以便您可以在需要时将其用作备忘单。

第 1 步:在 ClassBVC 文件中查找编译指示标记步骤 1 并添加此

//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}

第一步是创建一个,在这种情况下,我们将在 B 类中创建协议,在协议中,您可以根据实现的要求创建任意数量的函数。在这种情况下,我们只有一个简单的函数,它接受一个可选作为参数。 在命名协议时,最好在类名的末尾添加单词,在本例中为 .protocolUIColordelegateClassBVCDelegate

第 2 步:查找编译指示标记步骤 2 并添加此ClassVBC

//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?

这里我们只为类创建一个委托属性,这个属性必须采用类型,并且应该是可选的。此外,您应该在属性之前添加 weak 关键字,以避免保留周期和潜在的内存泄漏,如果您不知道这意味着什么,请不要担心,只需记住添加此关键字即可。protocol

第 3 步:在句柄内查找编译指示标记第 3 步点击并添加此内容methodClassBVC

//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)

您应该知道的一件事是,运行应用程序并点击任何视图,您不会看到任何新行为,这是正确的,但我想指出的是,当调用委托时,它不会崩溃,这是因为我们将其创建为可选值,这就是为什么即使委托的还不存在,它也不会崩溃。现在让我们去归档并制作它,委托。ClassAVC

第 4 步:在 handleTap 方法中查找编译指示标记步骤 4,并将其添加到您的类类型旁边,如下所示。ClassAVC

//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}

现在 ClassAVC 采用了该协议,你可以看到你的编译器给你一个错误,上面写着“Type 'ClassAVC doesn't conform to protocol 'ClassBVCDelegate',这仅意味着你还没有使用协议的方法,想象一下,当 A 类采用该协议时,就像与 B 类签订合同,这个合约说”任何采用我的类都必须使用我的函数!ClassBVCDelegate

快速说明:如果您来自背景,您可能认为您也可以关闭该错误,使该方法成为可选方法,但令我惊讶的是,可能还有您的语言不支持可选,如果您想这样做,您可以为您的创建一个扩展或在您的实现中使用 @objc 关键字。Objective-CSwiftprotocolsprotocolprotocol

就个人而言,如果我必须使用不同的可选方法创建一个协议,我宁愿将其分解为不同的 ,这样我将遵循为我的对象赋予一个单一责任的概念,但它可能会根据具体实现而有所不同。protocols

这是一篇关于可选方法的好文章。

第 5 步:在 prepare for segue 方法中查找编译指示标记步骤 5 并添加此内容

//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}

在这里,我们只是创建一个实例并将其委托给 self,但这里的 self 是什么?好吧,自我是被委派的!ClassBVCClassAVC

第 6 步:最后,查找编译指示第 6 步,让我们使用 ,开始键入 func changeBackgroundColor,您会看到它正在自动为您完成它。您可以在其中添加任何实现,在此示例中,我们只需更改背景颜色,添加此内容。ClassAVCprotocol

//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}

现在运行应用程序!

Delegates无处不在,你可能在不知不觉中使用它们,如果你创建一个过去你使用委托,围绕它们的许多类作品以及许多其他工作,它们解决了这些主要问题。tableviewUIKITframeworks

  • 避免物体紧密耦合。
  • 修改行为和外观,而无需对对象进行子类化。
  • 允许将任务处理到任意对象。

恭喜你,你刚刚实现了一个自定义委托,我知道你可能在想,就是为了这个而这么麻烦?好吧,委派是一种非常重要的设计模式,如果你想成为一名开发人员,请理解它,并始终记住它们在对象之间有一对一的关系。iOS

您可以在此处查看原始教程

0赞 Ellen 7/14/2017 #18

让我们从一个例子开始,如果我们在网上购买产品,它会经历由不同团队处理的运输/交付等过程。因此,如果运输完成,运输团队应通知交付团队,并且应该是一对一的通信,因为广播此信息对其他人/供应商来说可能是开销,可能只想将此信息传递给所需的人员。

因此,如果我们从我们的应用程序的角度来考虑,一个事件可以是一个在线订单,不同的团队可以像多个视图一样。

下面的代码将 ShippingView 视为运输团队,将 DeliveryView 视为交付团队:

//Declare the protocol with functions having info which needs to be communicated
protocol ShippingDelegate : class {
    func productShipped(productID : String)
}
//shippingView which shows shipping status of products
class ShippingView : UIView
{

    weak var delegate:ShippingDelegate?
    var productID : String

    @IBAction func checkShippingStatus(sender: UIButton)
    {
        // if product is shipped
        delegate?.productShipped(productID: productID)
    }
}
//Delivery view which shows delivery status & tracking info
class DeliveryView: UIView,ShippingDelegate
{
    func productShipped(productID : String)
    {
        // update status on view & perform delivery
    }
}

//Main page on app which has both views & shows updated info on product whole status
class ProductViewController : UIViewController
{
    var shippingView : ShippingView
    var deliveryView : DeliveryView

    override func viewDidLoad() {
        super.viewDidLoad()
        // as we want to update shipping info on delivery view, so assign delegate to delivery object
        // whenever shipping status gets updated it will call productShipped method in DeliveryView & update UI.
        shippingView.delegate = deliveryView
        //
    }
}
5赞 Miras Maratuly 3/16/2018 #19

答案实际上已经回答了,但我想给你一个创建委托的“备忘单”:

DELEGATE SCRIPT

CLASS A - Where delegate is calling function

@protocol <#Protocol Name#> <NSObject>

-(void)delegateMethod;

@end

@interface <#Some ViewController#> : <#UIViewController#> 

@property (nonatomic, assign) id <<#Protocol Name#>> delegate;

@end


@implementation <#Some ViewController#> 

-(void)someMethod {
    [self.delegate methodName];
}

@end




CLASS B - Where delegate is called 

@interface <#Other ViewController#> (<#Delegate Name#>) {}
@end

@implementation <#Other ViewController#> 

-(void)otherMethod {
    CLASSA *classA = [[CLASSA alloc] init];

    [classA setDelegate:self];
}

-delegateMethod() {

}

@end
-1赞 cxwangyi 1/30/2023 #20

一张图片胜过千言万语:-P

cpp-objc

Objective-C 代码函数中的变量称为委托,它只不过是指向实现一类纯虚函数的对象的 C++ 指针。greetermain

评论

0赞 Suraj Rao 1/30/2023
请将代码和数据添加为文本(使用代码格式),而不是图像。图片:A) 不允许我们复制粘贴代码/错误/数据进行测试;B) 不允许根据代码/错误/数据内容进行搜索;还有更多原因。除了代码格式的文本之外,仅当图像添加了仅由文本代码/错误/数据传达的重要内容时,才应使用图像。
0赞 cxwangyi 1/30/2023
你不应该复制粘贴。这个问题是关于一个概念的。你通过推理而不是复制来内化这个概念。
0赞 Suraj Rao 1/30/2023
请查看完整的原因列表