当前位置:  开发笔记 > IOS > 正文

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

如何解决《如何在Objective-C中创建委托?》经验,为你挑选了12个好方法。

我知道代表们的工作方式,我知道如何使用它们.

但是我该如何创建呢?



1> Jesse Rusak..:

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

例如,假设你有一个UIWebView.如果你想实现它的委托webViewDidStartLoad:方法,你可以创建一个这样的类:

@interface MyClass
// ...
@end

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

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

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

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

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

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

为您的类创建代表

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

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

这类似于接口或抽象基类,因为它为您的委托创建了一种特殊类型,UIWebViewDelegate在本例中.代表实施者必须采用该协议:

@interface MyClass 
// ...
@end

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

命名

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

速度优化

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

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

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

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

- (void)setDelegate:(id )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仍然这样做:

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

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

然后,您将使用与上述相同的-respondsToSelector:方法来调用此方法.代理只需实现此方法并分配delegate属性,就是它(没有声明您符合协议).这种方法在Apple的库中很常见,但是新代码应该使用上面更现代的协议方法,因为这种方法会污染NSObject(这使得自动完成功能不那么有用)并且使编译器很难警告你有关拼写错误和类似错误的信息.



2> Tibidabo..:

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

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

#import 

@class MyClass;             //define class, so protocol can see MyClass
@protocol MyClassDelegate    //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  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)MyVC.h:

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

MyVC.m:

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

实现委托方法

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


在MyVC.m中实例化`myClass`在哪里?
很高兴使用这个答案作为快速参考.但是为什么MyClass.h中的委托属性标记为"IBOutlet"?
@ArnovanderMeer好抓!我不记得为什么.我需要在我的项目中,但不是在这个例子中,我删除了它.谢谢

3> umop..:

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

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

在您的委托访问器(setDelegate)代码中.这有助于减少错误.



4> Tom Andersen..:

也许这更像是你所缺少的:

如果你来自C++这样的观点,代表们会习惯一点 - 但基本上"他们只是工作".

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

用你自己的对象来做这件事是完全无关紧要的,没有什么特别的事情,例如你可以拥有NSArray27个对象,所有不同类型的对象,其中只有18个有方法-(void)setToBue;,其他9个没有.因此,要求setToBlue所有18个需要它完成的东西,如下所示:

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

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



5> swiftBoy..:

请!查看以下简单的分步教程,了解Delegates如何在iOS中工作.

在iOS中代表

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

    FirstViewController实现委托(提供数据).

    SecondViewController声明委托(将接收数据).



6> Jean..:

作为Apple推荐的一种良好实践,代表(根据定义,这是一种协议)符合NSObject协议是有益的.

@protocol MyDelegate 
    ...
@end

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

@protocol MyDelegate 
    ...
    ...
      // 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视图(符合您的委托)是否实际实现了可选方法.



7> DrBug..:

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

如果我要向C++/Java程序员解释代表,我会说

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

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

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



8> Suragch..:
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!"
}

在实际操作中,代表经常在以下情况下使用

    当一个类需要将一些信息传递给另一个类时

    当一个类想要允许另一个类来自定义它时

除了委托类符合所需的协议之外,这些类不需要事先了解彼此.

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

什么是代表团? - Swift开发人员指南

代表团的工作方式 - Swift开发人员指南



9> Tibidabo..:

好吧,这不是问题的真正答案,但是如果你正在查找如何制作自己的代表,那么更简单的东西可能是更好的答案.

我很难实现我的代表,因为我很少需要.我只能拥有一个委托对象的委托.因此,如果您希望您的代表以单向方式进行通信/传递数据,而不是通过通知更好.

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];
}



10> m.eldehairy..:

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

@class myClass;

@protocol myClassDelegate 

-(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头文件(或一个单独的头文件)中声明一个协议,并声明你的委托必须/应该实现的必需/​​可选事件处理程序,然后声明一个MyClasstype(id< MyClassDelegate>)属性,这意味着任何符合的目标c类在协议中MyClassDelegate,您会注意到委托属性被声明为弱,这对于防止保留循环非常重要(通常委托保留MyClass实例,因此如果您将委托声明为保留,则它们将保留彼此,并且都不会他们将被释放).

您还会注意到协议方法将MyClass实例作为参数传递给委托,这是最好的做法,以防委托想要在MyClass实例上调用某些方法,并且当委托MyClassDelegate对多个MyClass实例声明自己时也有帮助,例如当您有多个实例时UITableView's在你的实例中,ViewController并将其自身声明为UITableViewDelegate所有实例.

并在您的内部MyClass通过声明的事件通知委托,如下所示:

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

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



11> soumya..:

这是一个创建委托的简单方法

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

步骤1:创建一个名为"YourViewController"的新类协议,它将是UIViewController类的子类,并将此类分配给第二个ViewController.

步骤2:转到"YourViewController"文件并按如下所示进行修改:

#import 
@class YourViewController;

@protocol YourViewController Delegate 

 @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 ()
     
   @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]; 
     }
  }



12> 小智..:

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

协议必须声明如下:

@protocol ServiceResponceDelegate 

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

@end

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

@interface ServiceClass : NSObject
{
id  _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 
{
ServiceClass* _service;
}

- (void) go;

@end

@implementation viewController

//
//some methods
//

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

就是这样,通过在这个类中实现委托方法,控制将在操作/任务完成后返回.

推荐阅读
围脖上的博博_771
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有