关于iOS:如何在Objective-C中创建代表delegates?

How do I create delegates in Objective-C?

我知道代表是如何工作的,我也知道如何使用他们。

但我如何创建它们呢?


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

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

1
2
3
4
5
6
7
8
9
@interface MyClass<UIWebViewDelegate>
// ...
@end

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

然后,您可以创建MyClass的实例并将其指定为Web视图的委托:

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

UIWebView端,它可能具有与此类似的代码,以查看代理是否使用respondsToSelector:响应webViewDidStartLoad:消息,并在适当时发送该消息。

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

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

为你的班级做代表

要定义自己的委托,您必须在某个地方声明它们的方法,如Apple文档中关于协议的讨论。您通常声明一个正式的协议。从uiwebview.h解释的声明如下:

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

这类似于一个接口或抽象基类,因为它为委托(在本例中为UIWebViewDelegate创建了一个特殊类型)。委托实施者必须采用该协议:

1
2
3
@interface MyClass <UIWebViewDelegate>
// ...
@end

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

命名

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

速度优化

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@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:来处理消息。

非正式代表

在协议存在之前,通常使用NSObject上的一个类别来声明委托可以实现的方法。例如,CALayer仍然这样做:

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

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

然后,您将使用上述相同的-respondsToSelector:方法来调用此方法。委托只需实现此方法并分配delegate属性,就这样(没有声明您符合协议)。这种方法在苹果的库中很常见,但是新的代码应该使用上面更现代的协议方法,因为这种方法污染了NSObject,使自动完成功能变得不那么有用,并且使编译器很难警告您输入错误和类似的错误。


批准的答案很好,但如果您要寻找1分钟的答案,请尝试以下操作:

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

1
2
3
4
5
6
7
8
9
10
11
12
#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文件应该如下所示

1
2
3
4
5
6
7
8
9
#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)myvc.h中使用委托,请执行以下操作:

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

MYVC。M:

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

实现委托方法

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


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

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

在委托访问器(setdelegate)代码中。这有助于减少错误。


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

如果你来自C++的观点,代表们有点习惯-但基本上他们只是工作。

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

用你自己的对象来做这件事是很平常的,没有什么特别的事情发生,比如你可以有一个由27个对象组成的NSArray,各种各样的对象,其中只有18个对象有-(void)setToBue;的方法,而另外9个对象没有。所以在所有需要它做的18个对象上都称为setToBlue,就像这样:

1
2
3
4
5
for (id anObject in myArray)
{
  if ([anObject respondsToSelector:@selector(@"setToBlue")])
     [anObject setToBlue];
}

关于委托的另一件事是它们没有被保留,所以您总是必须在您的MyClass dealloc方法中将委托设置为nil


拜托!请查看下面的简单分步教程,了解代理如何在iOS中工作。

Delegate in iOS

我创建了两个视图控制器(用于将数据从一个发送到另一个)

  • FirstViewController实现委托(提供数据)。
  • secondViewController声明委托(将接收数据)。

  • 作为苹果公司推荐的一个好做法,它有利于代表(根据定义,这是一个协议)遵守NSObject协议。

    1
    2
    3
    @protocol MyDelegate <NSObject>
        ...
    @end

    &;要在委托中创建可选方法(即不必实现的方法),可以使用这样的@optional注释:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @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是否视图(符合您的委托)实际实现了您的可选方法。


    我认为,一旦你理解了代表们的意思,所有这些答案都很有意义。就我个人而言,我来自C/C++的领域,之前的程序语言如Fortran等,所以这是我在C++范例中找到类似的类比的2分钟。

    如果我要解释一个C++程序员的委托,我会说

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

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

    如何在C++中做类似的事情?如果您试图在C++中实现这一点,您将通过定义类定义中的类(对象)指针,然后将它们连接到其他类,这些类将作为委托给基类提供附加功能。但是,这种接线需要在代码中维护,并且将是笨拙和容易出错的。目标C只是假设程序员不擅长维护这个分解,并提供编译器限制来强制执行干净的实现。


    斯威夫特版本

    委托只是为另一个类做一些工作的类。阅读下面的代码,了解一个有点愚蠢(但希望有启发性)的游乐场示例,它展示了如何用swift完成这项工作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    // 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
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @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

    因此,您在MyClass头文件(或单独的头文件)中声明一个协议,并声明您的委托必须/应该实现的必需/可选事件处理程序,然后在MyClass中声明类型为(id< MyClassDelegate>的属性,这意味着任何符合MyClassDelegate协议的目标C类,您将注意到gate属性被声明为弱属性,这对于防止保留周期非常重要(通常代理保留MyClass实例,因此如果您声明代理为保留,则两个代理都将彼此保留,并且都不会被释放)。

    您还将注意到协议方法将MyClass实例作为参数传递给委托,这是在委托希望调用MyClass实例上的某些方法时的最佳实践,并且在委托声明自己为MyClassDelegate到多个MyClass实例时也有帮助,例如当您有多个@optional实例时。2〕在你的ViewController中的实例,并向所有人声明自己是UITableViewDelegate中的一个。

    在您的MyClass中,您将宣布的事件通知代表如下:

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

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


    好吧,这不是问题的真正答案,但是如果你正在寻找如何使自己的代表更简单的方法,也许对你来说是更好的答案。

    我很少执行我的代表,因为我很少需要。一个委托对象只能有一个委托。因此,如果您希望将代理用于单向通信/传递数据,而不是通知。

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

    myclass.m文件应该如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #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

    要在其他类中使用通知:添加类作为观察者:

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

    执行选择器:

    1
    2
    3
    4
    5
    - (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
    }

    如果

    1
    2
    3
    4
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }

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

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

    步骤:1:创建一个名为"yourviewcontroller"的新类协议,它将成为uiviewcontroller类的子类,并将该类分配给第二个viewcontroller。

    步骤:2:转到"yourviewcontroller"文件并按以下方式修改:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #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:代表的执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
        #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

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

    1
    2
    3
    4
    5
     - (void) someMethodToCallDelegate {
         if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
               [self.delegate delegateMethodName:self];
         }
      }


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

    协议必须声明如下:

    1
    2
    3
    4
    5
    6
    @protocol ServiceResponceDelegate <NSObject>

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

    @end

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    @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

    这是主视图类,通过将委托设置为其自身,从中调用服务类。协议也在header类中实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @interface viewController: UIViewController <ServiceResponceDelegate>
    {
    ServiceClass* _service;
    }

    - (void) go;

    @end

    @implementation viewController

    //
    //some methods
    //

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

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


    免责声明:这是如何创建delegateSwift版本。好的。

    那么,代表是什么?…在软件开发中,有一些通用的可重用解决方案体系结构可以帮助解决给定环境中常见的问题,这些"模板"可以说是最有名的设计模式。委托是一种设计模式,允许一个对象在发生特定事件时向另一个对象发送消息。假设一个对象A调用一个对象B来执行一个操作。一旦行动完成,目标A应该知道B已经完成任务并采取必要的行动,这可以在代表的帮助下实现!好的。

    为了得到更好的解释,我将向您展示如何创建一个自定义委托,该委托在类之间传递数据,在一个简单的应用程序中使用swift,从下载或克隆这个启动程序项目开始,然后运行它!好的。

    你可以看到一个应用程序有两个类,ViewController AViewController B。B有两种观点,即点击改变ViewController的背景色,没有什么太复杂的,对吗?现在让我们用一种简单的方法来考虑,当点击B类的视图时,也可以改变A类的背景色。好的。

    问题是,这种观点是B类的一部分,不了解A类,所以我们需要找到一种方法来在这两个类之间进行交流,这就是代表团的闪光之处。我将实现分为6个步骤,以便在需要时将其用作备忘表。好的。

    步骤1:在ClassBVC文件中查找pragma mark步骤1并添加此好的。

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

    第一步是创建一个protocol,在这种情况下,我们将在类B中创建协议,在协议内部,您可以根据您的实现需求创建任意多的函数。在这种情况下,我们只有一个简单的函数接受可选的UIColor作为参数。在类名的末尾添加单词delegate是命名协议的一个很好的实践,在本例中是ClassBVCDelegate。好的。

    步骤2:在ClassVBC中查找pragma mark step 2并添加此好的。

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

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

    步骤3:在ClassBVC中查找handletap method中的pragma mark step 3并添加此好的。

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

    你应该知道的一点是,运行应用程序并点击任何视图,你不会看到任何新的行为,这是正确的,但我想指出的是,当调用委托时,应用程序不会崩溃,这是因为我们创建它作为可选值,这就是为什么它不会崩溃,即使委托还不存在的原因。现在我们去ClassAVC文件,把它做成委托文件。好的。

    第4步:在ClassAVC中查找handletap方法中的pragma mark step 4,并将其添加到类类型旁边,如下所示。好的。

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

    现在classavc采用了ClassBVCDelegate协议,你可以看到你的编译器给了你一个错误,说"classavc类型不符合协议classbvcdelegate",这只意味着你还没有使用协议的方法,想象一下,当class a采用协议时,就像与class b签订合同一样,并且合同上说"任何采用我的课程都必须使用我的功能!"好的。

    简要说明:如果您来自Objective-C背景,您可能会认为您也可以关闭该错误,使该方法成为可选的,但让我吃惊的是,可能是您的,Swift语言不支持可选protocols,如果您想这样做,您可以为protocol创建一个扩展,或者使用@objc keyw你的protocol实施中的ORD。好的。

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

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

    步骤5:在Prepare for Segue方法中查找pragma mark步骤5并添加此好的。

    1
    2
    3
    4
    //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
    }

    这里我们只是创建一个ClassBVC的实例,并将其委托给self,但是self在这里是什么?好吧,Self就是委托给他的ClassAVC!好的。

    第6步:最后,在ClassAVC中查找pragma step 6,让我们使用protocol的函数,开始键入func changebackgroundcolor,您将看到它是自动完成的。您可以在其中添加任何实现,在本例中,我们只需更改背景颜色,添加这个。好的。

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

    现在运行应用程序!好的。

    Delegates无处不在,你可能在没有事先通知的情况下使用它们,如果你创建了一个tableview,在过去你使用了委托,UIKIT的许多类围绕它们工作,而其他frameworks类也解决了这些主要问题。好的。

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

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

    您可以在这里看到原始教程好的。好啊。


    答案实际上是被回答的,但我想给你一份创建代表的"备忘表":

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    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

    视图控制器.h

    1
    2
    3
    4
    5
    6
    7
    @protocol NameDelegate <NSObject>

    -(void)delegateMEthod: (ArgType) arg;

    @end

    @property id <NameDelegate> delegate;

    视图控制器.m

    1
    [self.delegate delegateMEthod: argument];

    主视图控制器.m

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

    方法:

    1
    2
    -(void)delegateMEthod: (ArgType) arg{
    }

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

    在我定制的DropDownClass.h中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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;

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     - (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];
            }
        }
    }];
    }

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

    在我的另一个视图控制器中,在此之后导入

    创建用于调用此类委托方法的操作

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

    之后,像这样的调用委托方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    - (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;
    }
    }


    委托:-创建

    1
    2
    3
    4
    5
    @protocol addToCartDelegate <NSObject>

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

    @end

    发送并请指派代表查看正在发送的数据

    1
    [self.delegate addToCartAction:itemsModel isAdded:YES];

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //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-(无效)didremovcellwithtag:(nsinteger)tag{nslog@("标记%d",标记);

    }


    让我们从一个例子开始,如果我们在线购买一个产品,它会经历不同团队处理的发货/交付等过程。因此,如果发货完成,发货团队应该通知发货团队,它应该是一对一的通信,因为广播此信息会增加其他人/供应商可能想要传递此信息的开销。只向需要的人提供信息。

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

    下面是代码,将ShippingView视为发货团队&deliveryView视为发货团队:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    //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
            //
        }
    }