ios - 如何在Objective-C里创建委托(delegates)?
天蓬老师
天蓬老师 2017-04-17 12:00:39
0
1
443

我知道委托如何工作,我也知道怎么使用。但是我该怎么创建呢?

原文:

How do I create delegates in Objective-C?

I know how delegates work, and I know how I can use them.
But how do I create them?

这是问题原文链接

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

reply all(1)
小葫芦

1. Answer from @Jesse Rusak:

An Objective-C delegate is an object that has been designated as another delegate. There is no special creation process. You only need to define a class that implements the delegate method you are interested in. (Although delegation uses a formal protocol, you must declare the delegation to execute the protocol, as shown below)
For example, suppose you have an NSWindow. If you want to implement his delegate's windowDidMove: method, you can create a class like this:

@implementation MyClass
- (void)windowDidMove:(NSNotification*)notification { 
    // ... 
}
@end

Then create an instance of MyClass and specify it as the delegate of window:

MyClass *myDelegate = [[MyClass alloc] init];
[window setDelegate: myDelegate];

In terms of NSWindow, there may be code similar to this using respondsToSelector: to see whether the delegate responds to windowDidMove: information, and send it if appropriate.

if([[self delegate] respondsToSelector:@selector(windowDidMove:)]) {
    [[self delegate] windowDidMove:notification];
}

The delegate resource itself is typically declared weak (ARC) or assigned (pre-ARC) to avoid loops, since object delegates often hold strong references to the object (e.g., a view controller usually contains a view delegate)
To define your own delegate, you need to declare the method somewhere. There are two basic methods, discussed in Apple's documentation protocol.

1) An informal agreement

This is similar to NSWindow, implemented in the NSObject category. For example, continuing the example above, this is paraphrased from NSWindow.h::

@interface NSObject(NSWindowNotifications)
- (void)windowDidMove:(NSNotification *)notification;
// ... 其他方法
@end

As described above, when calling this function, you will use -respondsToSelector:, delegate to simply implement this method, and you are done. This method is straightforward and common in Apple libraries, but new code should use the more modern method below.

2) A formal agreement

The new option is to declare a formal agreement. The declaration should look like this:

@protocol NSWindowNotifications <NSObject>
@optional
- (void)windowDidMove:(NSNotification *)notification;
// ...其他方法
@end

This is similar to an interface or abstract base class in that it establishes a special type for the delegate, in this case NSWindowNotifications. Delegate executors should adopt this protocol:

@interface MyDelegate <NSWindowNotifications>
// ...
@end

Then execute the method in the protocol. For methods declared in a protocol such as @optional (like most delegate methods), you still need to check -respondsToSelector: before calling the special method.
Apple recommends this method because it's more precise, won't be confused with NSObject, and provides better tool support.

Optimize speed

Instead of checking whether the delegate responds to the selector, you can store relevant information when setting the delegate. Using bitfield is a very clear method, as follows:

@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 <JSSomethingDelegate>)aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;

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

Then, in the body, you can check delegate processing emails by accessing delegateRespondsTo instead of sending -respondsToSelector: over and over again.


2. By @Tibidabo

The above method is great! But if you want to solve the problem in 1 minute you can try this:
The MyClass.h file should look like this (add delegate lines with comments)

#import <BlaClass/BlaClass.h>

@class MyClass;             //定义类,这样协议可以看到MyClass
@protocol MyClassDelegate   //定义委托协议
- (void) myClassDelegateMethod: (MyClass *) sender;  //定义在另一个类里实现的委托方法
@end //结束协议

@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //定义 MyClassDelegate为委托

@end

MyClass.m file should look like this:

#import "MyClass.h"
@implementation MyClass 
@synthesize delegate; //综合MyClassDelegate 委托

- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //这个会调用在其他类里实现的方法
}

@end

In order to use delegates in other classes (in this case, UIViewController calls MyVC) MyVC.h:

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

MyVC.m:

myClass.delegate = self;          //设置委托至自身的某个地方

Execute delegate method:

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

3. By @umop

When creating delegate support with formal protocol methods, I found that I can ensure proper type checking (albeit at run time, not compile time) by adding code like this:

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

This can minimize errors in your delegate access (setDelegate) code.


4. Answer from @Tom Andersen

Perhaps it’s more about what you are missing.
If you look at it from a C++ perspective, delegates take a little getting used to, but basically "they just work".
The way delegation is implemented is to set the delegate object of NSWindow, but the object is only executed for one or several possible delegate methods. So something happens, NSWindow wants to call the object, it just uses Objective-c's respondsToSelector method to decide if the object is called, and then calls it. This is how Objective-C is implemented - find methods based on requirements.
Implementing this with your own objects is very trivial, nothing special, you can even make an instance of an NSArray with 27 objects, completely different types of objects, only 18 of which have -(void)setToBue; method, the other 9 do not. So at point 18 the call to setToBlue needs to be done, like this:

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

In addition, the delegate is not retained, so you need to set the delegate to nil in the MyClass dealloc method.


5. Answer from @RDC:

Please see the tutorial below for a step-by-step introduction to delegation in iOS.

  • Delegation in iOS

I created two ViewControllers (sending from one to the other)
1. FirstViewController executes the delegate (provides data).
2. SecondViewController declares delegation (receives data).

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template