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

但是我如何创建它们呢?


当前回答

//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”标签,标签);

}

其他回答

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

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

@interface MyClass<UIWebViewDelegate>
// ...
@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中关于协议的讨论一样。您通常声明一个正式的协议。这个声明,转述自UIWebView.h,看起来像这样:

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

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

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

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

命名

委托方法通常以委托类名开始命名,并将委托对象作为第一个参数。他们也经常使用will-, should-或did-形式。因此,webViewDidStartLoad:(第一个参数是web视图)而不是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:。

非正式代表

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

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

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

然后使用上面描述的相同的-respondsToSelector:方法来调用该方法。委托实现此方法并分配委托属性,仅此而已(没有声明您符合协议)。这种方法在苹果的库中很常见,但是新的代码应该使用上面的更现代的协议方法,因为这种方法会污染NSObject(这使得自动补全不那么有用),并且很难让编译器警告你打字错误和类似的错误。

在我看来,为委托方法创建单独的类,你可以在任何地方使用。

在我的自定义下拉列表类。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;

然后进去。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];
        }
    }
}];
}

这里所有的都设置为自定义委托类。之后你可以在任何你想要的地方使用这个委派方法。例如……

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

像这样创建调用委托方法的动作

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

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

协议必须声明如下:

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

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

也许这更符合你所错过的:

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

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

对你自己的对象做这个完全是微不足道的,没有什么特别的,例如,你可以有一个包含27个对象的NSArray,所有不同类型的对象,只有18个其中一些有方法-(void)setToBue;其他9个没有。在所有18个需要执行的地方调用setToBlue,就像这样:

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

关于委托的另一件事是它们不会被保留,所以你总是需要在MyClass dealloc方法中将委托设为nil。

斯威夫特版本

委托只是一个为另一个类做一些工作的类。阅读下面的代码,这是一个有点傻(但希望有启发性)的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!"
}

在实际实践中,委托通常用于以下情况

当一个类需要向另一个类传递一些信息时 当一个类希望允许另一个类自定义它时

类之间不需要事先知道彼此的任何信息,除非委托类符合所需的协议。

我强烈推荐阅读以下两篇文章。它们甚至比文档更能帮助我理解委托。

什么是委托?-快速开发人员指南 委托如何工作-一个快速的开发者指南