iOS精选整理集合

003-类别、类扩展、协议与委托

2017-11-26  本文已影响13人  Yasic

类别、类扩展、协议与委托

类别 Category

类别是为已存在的类添加新的方法,以及将实现代码组织到不同模块中,便于管理和协作开发。

创建与使用类别

在 Xcode 8 中,创建一个类别的方法是新建一个 objective-c 文件,选择文件类型为 category,然后选择一个被扩展的类,并创建该文件。就会生成一个以原类名 + 类别名为名称的代码单元。

然后在单元中加入新的方法。

#import <Foundation/Foundation.h>

@interface NSString (LengthOfStr)
-(NSUInteger)length;
@end

@implementation NSString (LengthOfStr)
-(NSUInteger *)length
{
    NSUInteger *length = [self length];
    return length;
}
@end

这样就可以像调用原生的方法一样调用类别中的方法了,当然前提是引入了正确的类别文件。

int main(int argc, const char * argv[])
{
    NSUInteger *length = [@"hello" length];
    NSLog(@"%u", length);
}

类别的特点

类扩展 Extension

类扩展又称为匿名分类,与 category 显著的区别就在与它不需要命名。类扩展一般放在 .m 文件首部,也可以放在头文件里,或是直接新建一个文件,其主要作用是将部分信息隐藏。

@interface Animal()
@property(retain) NSString *myTest;
@property(retain, readwrite) NSString *age;

-(NSString *)sport;
@end

虽然 Cocoa 没有真正的私有方法和私有属性,也就是说如果预先知道方法的名称,即使方法不是“公开”的,也可以调用这个方法,但是编译器会产生错误提示,而在 iOS 应用程序里调用这类私有变量和方法的行为会被拒绝上架。

协议 Protocol

协议类似于 Java 中的接口,是一种约定,由类显式地采用协议。

协议中可以创建方法和属性。

@protocol ManagerProtocol <NSObject>

@property(nonatomic, strong) NSString *title;

@optional
-(void)printTitle;

@required
-(void)payoff:(NSString *)staffName;
@end

@optional 是可选实现方法,@required 是必须实现方法。对于可选实现方法,如果调用时发现没有实现会报错。

采用协议是在类的声明中用尖括号括起来,可以采用多个协议,然后在定义文件中实现方法和创建属性的存取方法。

@interface Manager : Staff<ManagerProtocol>

@end

#import <Foundation/Foundation.h>
#import "Manager.h"

@implementation Manager

@synthesize title;

-(void)printTitle
{
    NSLog(@"%@", [self title]);
}

-(void)payoff:(NSString *)staffName
{
    NSLog(@"payoff %@", staffName);
}

@end

委托

委托通常与协议一同使用。委托是指某个对象 A 需要借助对象 B 的某个方法来实现功能时,就将对象 B 设置为对象 A 的委托对象,当对象 A 需要执行这一操作时就给对象 B 发送消息。至于如何得知对象 B 可以执行这一功能,则需要协议来约定,即对象 A 设定某一个协议,而对象 B 实现这一个协议,用来说明自己有这一能力,从而可以让 A 安全地设置 B 为委托对象。

如果没有协议进行约定,就需要一个方法来判断委托对象是否有此方法,这里用到了相应选择器 @selector

[manager respondsToSelector: @selector(setTitle:)]

这个表达式可以检测对象 manager 是否含有 setTitle 这个方法,如果有则返回 YES,如果没有则返回 NO。

@interface Boss: NSObject

@property(strong, nonatomic) id<ManagerProtocol> delegateManager;

-(void)payoff:(NSString *)name;

@end



@implementation Boss

-(void)setDelegateManager:(id<ManagerProtocol>)newDelegateManager
{
    _delegateManager = newDelegateManager;
}

-(void)payoff:(NSString *)name
{
    [[self delegateManager] payoff:name];
}

@end

这样当 boss 对象需要调用 payoff 时其实是向委托对象 manager 发送消息。

int main(int argc, const char * argv[])
{
    Boss *boss = [Boss new];
    Manager *manager = [Manager new];
    [boss setDelegateManager:manager];
    [boss payoff:@"Yasic"];
}

这里注意如果复写了 setter 方法,则应该在设置实例变量时用实例变量进行赋值,否则会陷入递归调用中从而崩溃。

非正式协议

创建一个 NSObject 的 category 被称作 “非正式协议”,在类别中定义的方法任何对象都可以选择性实现,从而在委托对象中直接调用,但是这样的非正式协议的方法是可选实现的,必须检测委托对象是否真的会对某个消息进行反应才可以安全地调用。

上一篇下一篇

猜你喜欢

热点阅读