面向对象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);
0 0
原创粉丝点击