面向对象6
来源:互联网 发布:linux中的which 编辑:程序博客网 时间:2024/05/17 07:48
类别与扩展
类别
类别可以对已有类添加方法,类别中通常指定义方法,一般接口文件名为 已有类+类别名.h
@interface 已有类 (类别名)//定义方法@end@implementation 已有类 (类别名)//实现方法@end
通过类别为指定类添加新方法后,其子类也会获取新添加的方法
可对一个指定类添加多个类别
通过类别调用私有方法
私有方法:没有在接口部分中定义,只在实现部分中定义了的方法,由于不能直接被类或实例调用,相当于私有方法
私有方法可用 performSelector: 来执行调用,但这样完全避开了编译器的语法检查,不是一种好的方法,这里也可以通过类别在接口部分定义私有方法,这样即可正常调用私有方法
扩展
相当于匿名类别,可额外增加实例变量,也可用 @property、@snythesize 来合成 setter、getter 方法,但定义类的列表是,则不允许额外定义实例变量。
协议(protocol)与委托
使用类别实现非正式协议
通过对 NSObject 创建类别新增方法,这样当某个类实现 NSObject 的该类别时就需要实现该类别下的所有方法,这种基于 NSObject 的类别即可认为是非正式协议。
//基于 NSObject 定义类别 Eatable@interface NSObject (Eatable)- (void) taste;@end//定义接口部分@interface MyApple: NSObject@end//定义实现部分@implementation MyApple- (void) taste{ NSLog(@"苹果好吃!");}@end//main()部分MyApple* apple = [[MyApple alloc] init];[apple taste]; //输出:苹果好吃!
正式协议的定义与实现
@protocol 协议名 <父协议1, 父协议2...>{ //零到多个方法定义}@interface 类名: 父类 <协议名a, 协议名b...>{ //实现协议}
定义协议时只需定义方法即可,实现是在定义类接口部分中
使用协议定义变量时:
- NSObject<协议1, 协议2…>* 变量名;
- id<协议1, 协议2…>* 变量名;
使用协议定义变量的话,那么这些变量就只能调用协议中的变量(参考多态)
// MyOutput 为协议名,out 为协议变量,MyPrinter 为实现了 MyOutput 协议的类,所以这个 out 变量可编译成功,但只能调用 MyOutput 中定义并且在 MyPrinter 实现部分中定义的方法,不能调用 MyPrinter 中其他的方法id<MyOutput> out = [[MyPrinter alloc] init];
使用 @try 处理异常
int main(){ @autoreleasepool { @try { MyApple* app = [[NyApple alloc] init]; [app taste]; } @cathch(NSException* ex) { NSLog(@"--捕捉异常--"); NSLog(@"Exception name:%@,exception reason:%@。", ex.name, ex.reason); } @finally { NSLog(@"资源回收"); } NSLog(@"程序结束"); }}
@try用来包含可能出现exception的代码
@catch用来捕获exception,可设置多个@catch块,出现exception时,会依次寻找@catch块,当exception对象与某@catch对象后的exception类或其子类匹配上之后,则会用该@catch块来处理exception,所以对于NSException类(所有异常类均继承于此)对应的@catch块应该放在最后,以符合先子类,后父类的原则
exception对象包含name、reason、userInfo(返回用户附加信息,返回值是一个NSDictionary对象)三个常用方法。
@finally用来回收资源,位与@try和@catch块之后,且@finally块总是会执行的,所以@finally块中最好不要有return或@throw语句,否则会导致@try块中的return、@throw语句失效
抛出异常与自定义异常类
//自定义异常类以及MyDog类@interface MyException: NSException@end@interface MyDog: NSObject@property (nonatomic, assign) int age;@end//实现部分@implementation MyException@end@implementation MyDog@snythesize age = _age;- (void) setAge:(int) age{ if(age > 50 || age < 0) { @throw [[MyException alloc] initWithName:@"UkkegakArgymentException" reason:@"dog's age need to be controlled between 0 and 50!" userInfo:nil]; } _age = age;}
OC反射机制
获得Class
//通过字符串用 Class NSClassFromString(NSString* className) 函数获取ClassClass clazz1 = NSClassFromString(@"NSDate");NSLog(@"%@", clazz1); //输出结果为 NSDate//用clazz1来创建对象id date = [[clazz1 alloc] init];NSLog(@"%@", date); //输出结果是当下时间NSLog(@"%@", [clazz1 class]); //通过对象的class方法来获取Class并输出,输出结果为 _NSDateNSLog(@"%@", clazz1 == NSDate.class); //通过类的class方法来获取Class并比较,输出结果为 1
PS: 关于 [date class] 的结果为 _NSDate 而非 NSDate 的原因,是因为 NSDate 只是类簇的前端,初始化创建对象时实际返回的是 NSDate 得子类(_NSDate)实例,而不是 NSDate 的实例。
检查继承关系
- isKindOfClass: 传入class参数判断是否为该类及其子类的实例
- isMemberOfClass: 传入class参数判断是否为该类的实例
- conformsToProtocol: 传入protocol参数判断是否为该类及其子类的实例
获取Protocol参数方法:
- @protocol指令
- Protocol NSProtocolFromString(NSString name) 方法
MyApple* app = [[MyApple alloc] init];NSLog(@"The class app belong to is: %@", [app class]);NSLog(@"Does app belong to MyApple Class: %d", [app isMemberOfClass: MyApple.class]);NSLog(@"Does app belong to NSObject Class: %d", [app isMemberOfClass: NSClassFromString(@"NSObject"));NSLog(@"Does app belong to MyApple Class or its Child Class: %d", [app isKindOfClass: NSClassFromString(@"MyApple")]);NSLog(@"Does app belong to NSObject Class or its Child Class: %d", [app isKindOfClass: NSObject.class]);NSLog(@"1.Does app implement MyEatable protocol:%d", [app conformsToProtocol: @protocol(MyEatable)]);NSLog(@"2.Does app implement MyEatable protocolL %d", [app conformsToProtocol: *NSProtocolFromString(@"MyEatable")]);
动态调用方法
- 通过 performSelector: 方法方法实现动态调用方法,需要传入 SEL 对象,若需要参数则可通过 withObject: 传入参数
- 通过 objc_mshSend(receiver, selector, …),第一个参数为调用者,第二个参数为方法,之后为调用方法所需的参数
PS: 使用 objc_msgSend() 应该 #import < objc/message.h > ,另外还有两个版本,即objc_msgSend_fpret()和objc_msgSend_stret(),前者用于返回浮点数,后者用于返回结构体。
获取 selector 参数;
- 使用 @selector指令来获取当前类中指定的方法,该指令需要完整的方法签名关键字作为参数,仅有方法名是不够的。
- 使用 SEL NSSelectorFromString(NSString* SelectorName)
id car = [[NyCar alloc] init];//使用 performSelector: 方法来动态调用方法[car performSelector:@selector(addSpeed:) withObject:3.4];//使用 objc_msgSend() 函数动态调用方法objc_msgSend(car, NSSelectorFromString(@"addSpeed:"), 3.4);//定义函数指针变量double (*addSpeed)(id, SEL, double);//获取 car 对象的 addSpeed: 方法,病赋值给 addSpeed 函数指针变量addSpeed = (double(*)(id, SEL, double))[car methodForSelector:@selector(addSpeed:)];//通过 addSpeed 函数指针变量来调用 car 对象的方法double speed = addSpeed(car, @selector(addSpeed:),m 3.4);//输出调用方法的返回值NSLog(@"speed is: %g", speed);
- 面向对象基础6
- php面向对象6
- php面向对象6
- Chapter 6面向对象
- java面向对象6
- 6、面向对象
- 面向对象6
- 面向对象6
- 面向对象(6)
- 面向对象6
- 6-Python-面向对象
- 面向对象6---抽象
- 6、面向对象之封装
- php 面向对象 013.7.6
- 6-面向对象的理解
- 面向对象6大原则
- 学习笔记6-面向对象
- 6、面向对象之封装
- ActivityManager--获取栈顶Activity及其所属进程,activitymanager
- Git忽略规则及.gitignore规则不生效的解决办法
- TGB首次上台讲课经历——博客交流
- Android开发-优秀博客参考
- 多态的概述和讲解
- 面向对象6
- 当POST没有建名时如何获取POST的数据(APP发送字符串)(仅供自己笔记)
- CoAP协议及开源实现
- char*
- NSURLSession下载的断点续传以及实…
- iOS面试题 AFN和ASI框架的区别
- iOS面试题 AFN和ASI框架的区别
- iOS9下更新项目遇到的问题
- 运行时的理解