我知道委托是如何工作的,也知道如何使用它们。
但是我如何创建它们呢?
我知道委托是如何工作的,也知道如何使用它们。
但是我如何创建它们呢?
当前回答
当使用形式化协议方法来创建委托支持时,我发现你可以通过添加以下内容来确保正确的类型检查(尽管是运行时,而不是编译时):
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
在你的委托访问器(setDelegate)代码中。这有助于减少错误。
其他回答
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(这使得自动补全不那么有用),并且很难让编译器警告你打字错误和类似的错误。
委托:-创建
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
发送并请指定代表查看您正在发送的数据
[self.delegate addToCartAction:itemsModel isAdded:YES];
也许这更符合你所错过的:
如果你从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。
要创建自己的委托,首先需要创建一个协议并声明必要的方法,而不需要实现。然后在你的头类中实现这个协议在你想要实现委托或委托方法的地方。
协议必须声明如下:
@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];
}
就是这样,通过在这个类中实现委托方法,一旦操作/任务完成,控制就会回来。
当使用形式化协议方法来创建委托支持时,我发现你可以通过添加以下内容来确保正确的类型检查(尽管是运行时,而不是编译时):
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
在你的委托访问器(setDelegate)代码中。这有助于减少错误。