iOS开发系列--Objective-C之协议、代码块、分类
2016-03-17 21:37
549 查看
1、协议protocol
在OC中使用@protocol定义一组方法规范,实现此协议的类必须实现对应的方法。OC中的协议与其它语言中的接口定义类似。
一个简单的例子:
AnimalProtocol.h
Cat.h
Cat.m
说明:
1、一个协议可以扩展自另一个协议,如需要扩展多个协议,中间使用逗号分隔;
2、@required和@optional设置是否为必选方法。(注意OC是弱语法,即使不实现方法编译也不会报错);
3、协议的实现只能放在类的声明上,不能放到类的实现上;
4、协议中不能定义属性、成员变量等,只能定义方法。
事实上在OC中协议等更多作用是用于约束一个类必须实现某种方法,而从面向对象的角度而言这个类跟接口并不一定存在某种自然关系,可能是两个完全不同意义上的事物,这种模式我们称之为代理模式(Delegation)。在Cocoa框架中大量采用这种模式实现数据与UI的分离,而且基本上所有的协议都是以Delegate结尾。
另一个例子:
设计一个按钮,按钮需要点击。在其它语言中通常会引入事件机制,只要使用者订阅了点击事件,那么点击的时候就会触发执行这个事件(这是对象之间解耦的一种方式:代码注入)。但是在OC中没有事件的定义,而是使用代理来处理这个问题。首先在按钮中定义按钮的代理,同时使用协议约束这个代理(事件的触发者)必须实现协议中的某些方法,当按钮处理过程中查看代理是否实现了这个方法,如果实现了则调用这个方法。
CButton.h
CButton.m
MyListener.h
MyListener.m
main.m
注意:
1、id可以表示任何一个OC对象类型,类型后面的“<协议名>”用于约束作为这个属性的对象必须实现该协议(注:使用id定义的对象不需要加“*”)。
2、MyListener作为事件的触发者,它实现了CButtonDelegate代理。
3、在.h文件中如果使用了另一个文件的类或协议我们可以通过@class或者@protocol进行声明,而不必导入这个文件。
4、使用respondsToSelector方法可以判断一个对象是否实现了某个方法。
2、代码块Block
OC中的代码块类似于匿名函数的概念。在block中可以引用或者持有一个局部变量,同时可以通过代码块将操作作为参数传递。
一个简单的例子:
CButton.h
Button.m
main.m
注意:
1、block中可以读取块外定义的变量但是不能修改。如果修改需要在变量前加_block。
3、分类Category
利用分类,可以动态的为现有的类添加新的行为(特别是系统或者框架中的类)。
一个简单的例子:(为字符串去掉前后空格)
NSString+Extend.h
NSString+Extend.m
main.m
注:
去掉字符串中间的空格:
在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:@" "];
相关文章推荐
- 你应该学习哪种编程语言?
- [转]我们需要一种其他人能使用的编程语言
- C#语言主要特性总结
- C语言中static的作用及C语言中使用静态函数有何好处
- PHP检测用户语言的方法
- JavaScipt基本教程之JavaScript语言的基础
- 各种语言、服务器301跳转代码全集
- 查看Java所支持的语言及相应的版本信息
- 使用php判断浏览器的类型和语言的函数代码
- php实现获取及设置用户访问页面语言类
- GO语言类型转换和类型断言实例分析
- php根据用户语言跳转相应网页
- Java基础知识之Java语言概述
- ThinkPHP中的常用查询语言汇总
- go语言中的interface使用实例
- GO 语言学习指南
- 五步让你成为GO 语言高手
- 2025年互联网会变成什么样:10个预言
- C++爱好者博客
- [转]C++强大背后