您的位置:首页 > 移动开发 > Objective-C

iOS开发系列--Objective-C之协议、代码块、分类

2016-03-17 21:37 549 查看
1、协议protocol

在OC中使用@protocol定义一组方法规范,实现此协议的类必须实现对应的方法。OC中的协议与其它语言中的接口定义类似。

一个简单的例子:

AnimalProtocol.h

#import <Foundation/Foundation.h>

@protocol AnimalProtocol <NSObject>

@required

- (void)eat;

@optional

- (void)swim;
- (void)say;
- (void)run;

@end


Cat.h

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

@interface Cat : NSObject<AnimalProtocol>

- (void)eat;

@end


Cat.m

@implementation Cat

- (void)eat {
NSLog(@"eating...");
}

@end


说明:

1、一个协议可以扩展自另一个协议,如需要扩展多个协议,中间使用逗号分隔;

2、@required和@optional设置是否为必选方法。(注意OC是弱语法,即使不实现方法编译也不会报错);

3、协议的实现只能放在类的声明上,不能放到类的实现上;

4、协议中不能定义属性、成员变量等,只能定义方法。

事实上在OC中协议等更多作用是用于约束一个类必须实现某种方法,而从面向对象的角度而言这个类跟接口并不一定存在某种自然关系,可能是两个完全不同意义上的事物,这种模式我们称之为代理模式(Delegation)。在Cocoa框架中大量采用这种模式实现数据与UI的分离,而且基本上所有的协议都是以Delegate结尾。

另一个例子:

设计一个按钮,按钮需要点击。在其它语言中通常会引入事件机制,只要使用者订阅了点击事件,那么点击的时候就会触发执行这个事件(这是对象之间解耦的一种方式:代码注入)。但是在OC中没有事件的定义,而是使用代理来处理这个问题。首先在按钮中定义按钮的代理,同时使用协议约束这个代理(事件的触发者)必须实现协议中的某些方法,当按钮处理过程中查看代理是否实现了这个方法,如果实现了则调用这个方法。

CButton.h

#import <Foundation/Foundation.h>
@class CButton;

//一个协议可以扩展另一个协议,CButtonDelegate扩展了NSObject协议
@protocol CButtonDelegate <NSObject>

@required
- (void)onClick:(CButton *) button;

@optional
- (void)onMouseOver:(CButton *) button;
- (void)onMouseOut:(CButton *) button;

@end

@interface CButton : NSObject

#pragma mark 代理属性,同时约定作为代理的对象必须实现CButtonDelegate协议
@property (nonatomic, retain) id<CButtonDelegate> delegate;

#pragma mark 公共方法
- (void)click;

@end


CButton.m

#import "CButton.h"

@implementation CButton

- (void)click
{
NSLog(@"Invoke CButton's click mothod");
//判断_delegata这个实例是否实现了onClick:这个方法
//避免未实现CButtonDelegate的类也作为CButton的监听
if ([_delegate respondsToSelector:@selector(onClick:)]) {
[_delegate onClick:self];
}
}

@end


MyListener.h

#import <Foundation/Foundation.h>
#import "CButton.h"
@protocol CButtonDelegate;

@interface MyListener : NSObject <CButtonDelegate>
- (void)onClick:(CButton *)button;

@end


MyListener.m

#import "MyListener.h"

@implementation MyListener

- (void)onClick:(CButton *)button {
NSLog(@"Invoke Mylistener's onClick: method. The button is %@ ",button);
}

@end


main.m

#import <Foundation/Foundation.h>
#import "CButton.h"
#import "MyListener.h"

int main(int argc, const char * argv[]) {
@autoreleasepool {
CButton *button = [[CButton alloc] init];
MyListener *listener = [[MyListener alloc] init];

button.delegate = listener;
[button click];
}
return 0;
}


注意:

1、id可以表示任何一个OC对象类型,类型后面的“<协议名>”用于约束作为这个属性的对象必须实现该协议(注:使用id定义的对象不需要加“*”)。

2、MyListener作为事件的触发者,它实现了CButtonDelegate代理。

3、在.h文件中如果使用了另一个文件的类或协议我们可以通过@class或者@protocol进行声明,而不必导入这个文件。

4、使用respondsToSelector方法可以判断一个对象是否实现了某个方法。

2、代码块Block

OC中的代码块类似于匿名函数的概念。在block中可以引用或者持有一个局部变量,同时可以通过代码块将操作作为参数传递。

一个简单的例子:

CButton.h

#import <Foundation/Foundation.h>
@class CButton;
//代码块的typedef定义:typedef 返回值类型 (^类型名称) (参数列表)
typedef void (^CButtonClick) (CButton *);

@interface CButton : NSObject

#pragma mark 点击操作属性
@property (nonatomic, copy) CButtonClick onClick;

//代码块类型定义:返回值类型 (^变量名) (参数列表)
//@property (nonatomic, copy) void (^onClick) (CButton *);

#pragma mark 公共方法
- (void)click;

@end


Button.m

#import "CButton.h"

@implementation CButton

- (void)click {
NSLog(@"Invoke CButton‘s click method.");

if (_onClick) {
_onClick(self);
}
}

@end


main.m

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

int main(int argc, const char * argv[]) {
@autoreleasepool {
CButton *button = [[CButton alloc] init];

//Block的实现:^(参数列表){操作主体}
button.onClick = ^(CButton *but) {
NSLog(@"Invoke onClick method, the button is %@", but);
};
[button click];
}
return 0;
}


注意:

1、block中可以读取块外定义的变量但是不能修改。如果修改需要在变量前加_block。

3、分类Category

利用分类,可以动态的为现有的类添加新的行为(特别是系统或者框架中的类)。

一个简单的例子:(为字符串去掉前后空格)

NSString+Extend.h

#import <Foundation/Foundation.h>
@interface NSString (Extend)

- (NSString *)stringByTrim;

@end


NSString+Extend.m

#import "NSString+Extend.h"

@implementation NSString (Extend)

- (NSString *)stringByTrim {
NSCharacterSet* character = [NSCharacterSet whitespaceCharacterSet];
return [self stringByTrimmingCharactersInSet:character];
}

@end


main.m

#import <Foundation/Foundation.h>
#import "NSString+Extend.h"

int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString* string = [NSString stringWithFormat:@"Cao XueYing    "];
string = [string stringByTrim];
NSLog(@"%@!!!", string);
}
return 0;
}


注:

去掉字符串中间的空格:

NSString *string = @"Lorem    ipsum dolar   sit  amet.";
//去掉首尾空格
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

//在空格处将字符串分割成一个NSArray
NSArray *components = [string componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
//用NSPredicate去掉空格
components = [components filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self <> ''"]];

//用单个空格将数组重新组成字符串
string = [components componentsJoinedByString:@" "];
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  语言