OC学习笔记之006面向对象包装类,协议

1.包装类NSValue和NSNumber

NSValue是NSNumber的父类,NSNumber是更具体的包装类,包装各种数值类型,主要有三类方法
+numberWithXXX:类方法,直接将特定类型的值包装成NSNumber对象。
-initWithXXX:实例方法,先创建一个NSNUMber对象,再用一个基本类型的值来初始化NSNumber
-XXXValue:实例方法,返回该NSNumber对象包装的基本类型的值

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSNumber* mynumber1=[NSNumber numberWithInt:50];
    NSLog(@"%d",[mynumber1 intValue]);
    NSNumber* double1=[NSNumber numberWithDouble:10.254];
    NSLog(@"%f",[double1 doubleValue]);
    
    NSNumber* mynumber2=[[NSNumber alloc]initWithInt:432];
    NSLog(@"%d",[mynumber2 intValue]);
    NSNumber* mychar=[[NSNumber alloc]initWithChar:'A'];
    NSLog(@"%d",[mychar charValue]);


  }
}

输出:
2020-05-20 16:01:19.222537+0800 EX003[2385:133404] 50
2020-05-20 16:01:19.222907+0800 EX003[2385:133404] 10.254000
2020-05-20 16:01:19.222945+0800 EX003[2385:133404] 432
2020-05-20 16:01:19.222968+0800 EX003[2385:133404] 65

2.重写对象的description方法
#import <Foundation/Foundation.h>
@interface Apple:NSObject
@property(nonatomic,copy)NSString* color;
@property(nonatomic,assign) int weight;
-(id)initWith:(NSString*)color andWidth:(int) weight;

@end


@implementation Apple

-(id)initWith:(NSString*)color andWidth:(int) weight{
  if (self=[super init]) {
    self.color=color;
    self.weight=weight;
  }
  return self;
}

-(NSString*)description{
  return [NSString stringWithFormat:@"my apple is %@ and weight is %d",self.color,self.weight ];
}

@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    Apple* myapple=[[Apple alloc]initWith:@"red" andWidth:3];
    NSLog(@"%@",myapple);
  }
}

输出:
2020-05-20 16:22:01.275196+0800 EX003[2477:140684] my apple is red and weight is 3

3.category类别

类别为现有的类添加新方法,并且不需要创建子类,不需要访问原有类的源代码

@interface 已有类 (类别名)
//方法定义
@end

ps:一定要加上圆括号及类别名
类别还必须要要有实现部分

@implmentation
已有类 (类别名)
//方法实现
@end

ps:
当引入这个类别的时候使用如下格式

import 已有类名+类别名.h
@interface NSNumber (fr)
-(NSNumber*)jia:(double) mynumber;
-(NSNumber*)jian:(double) mynumber;
-(NSNumber*)cheng:(double) mynumber;
-(NSNumber*)chu:(double) mynumber;

@end

@implementation NSNumber (fr)
-(NSNumber*)jia:(double) mynumber{ return [NSNumber numberWithDouble:([self doubleValue]+mynumber)];}
-(NSNumber*)jian:(double) mynumber{return [NSNumber numberWithDouble:([self doubleValue]-mynumber)];}
-(NSNumber*)cheng:(double) mynumber{return [NSNumber numberWithDouble:([self doubleValue]*mynumber)];}
-(NSNumber*)chu:(double) mynumber{return [NSNumber numberWithDouble:([self doubleValue]/mynumber)];}

@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSNumber* mynumber=[[NSNumber alloc]initWithDouble:5.20];
    NSLog(@"%@",[mynumber jia:3.12]) ;
    NSLog(@"%@",[mynumber jian:3.12]) ;
    NSLog(@"%@",[mynumber cheng:3.12]) ;
    NSLog(@"%@",[mynumber chu:3.12]) ;
  }
}

输出
2020-05-20 17:01:24.163879+0800 EX003[2579:152136] 8.32
2020-05-20 17:01:24.164318+0800 EX003[2579:152136] 2.08
2020-05-20 17:01:24.164366+0800 EX003[2579:152136] 16.224
2020-05-20 17:01:24.164392+0800 EX003[2579:152136] 1.666666666666667

PS:

  • 通过类别为指定类添加新方法之后,这个新方法不仅会影响NSNumber类,还会影响NSNumber的所有子类,每个子类都会获取类别扩展的方法
  • 可根据需要为一个类定义多个类别,不同的类别都可对原有类增加方法定义。

类别的重要作用

  • 利用类别对类进行模块化设计
  • 使用类别来调用私有方法
  • 使用类别来实现非正式协议
4.利用类别对类进行模块化设计

类如果过大,可以动过类别进行扩展,一个类别实际上就是一个模块

5.利用类别调用私有方法

在类实现部分定义的方法为实质意义上的私有方法,但可以通过NSObjective的performSelector:方法来执行动态调用。但这种方法未必很好,因此
可以使用类别来定义向前引用,从而对私有方法进行调用
步骤如下:
1.定义一个正常的类的接口和实现
2.在类实现部分定义私有方法
3.通过类别将类实现部分的私有方法暴露出来

#import <Foundation/Foundation.h>
@interface Goods:NSObject
@property(nonatomic,assign) double price;
-(void)showInfo;
@end

@implementation Goods
@synthesize price;
-(void)showInfo{
  NSLog(@"这是一个普通的方法");
}
//这是个被隐藏的方法,但实际上可以被访问
-(double)calDiscount:(double)discount{
  return price*discount;
}
@end
//通过类别将隐藏的私有方法暴露出来
@interface Goods (fr)
-(double)calDiscount:(double)discount;
@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    Goods* good=[Goods new];
    good.price=100;
    [good showInfo];
    double realprice=[good calDiscount:0.95];//隐藏的方法无法实际执行
    NSLog(@"最后实际价格为:%g",realprice);
  }
}

输出:
2020-05-20 18:20:04.738915+0800 EX003[2951:178921] 这是一个普通的方法
2020-05-20 18:20:04.739268+0800 EX003[2951:178921] 最后实际价格为:95

6.扩展(extension)

扩展相当于匿名类,用于对每个类的临时扩展,由于类别不能额外定义实例 变量,也不能@property合成属性

@interface 已有类()
{
实例变量
}
//方法定义
@end

一般性步骤
1.创建一个类接口和类实现
2.创建类扩展
3.使用类扩展

@interface Car:NSObject
@property (nonatomic,copy)NSString* brand;
@property (nonatomic,copy)NSString* model;
-(void)drive;

@end
//定义类扩展
@interface Car()
@property(nonatomic,copy)NSString* color;
-(void)drive:(NSString*) owner;
@end
@implementation Car
-(void)drive{
  NSLog(@"we drive a %@ car with %@ style",self.brand,self.model);
}
-(void)drive:(NSString*) owner{
  NSLog(@"%@ drive a %@ car with %@ style and %@ color",owner,self.brand,self.model,self.color);
}

@end


int main(int argc, const char * argv[]) {
  @autoreleasepool {
    Car* car=[Car new];
    car.brand=@"特斯拉";
    car.model=@"modelS";
    [car drive];
    car.color=@"红色";
    [car drive:@"张三"];
    
  }
}

输出:
2020-05-20 18:52:44.380332+0800 EX003[3059:189089] we drive a 特斯拉 car with modelS style
2020-05-20 18:52:44.380729+0800 EX003[3059:189089] 张三 drive a 特斯拉 car with modelS style and 红色 color

7.正式协议(protocol)

@protocl 协议名 <父协议1,父协议2>
{
零到多个方法定义…
}
一个协议可以有多个父协议,但协议只能继承协议,不能继承类
协议定义的方法只有方法签名,没有方法实现,既可以是类方法,也可以是实例方法

#import <Foundation/Foundation.h>

@interface Communicate:NSObject
-(void)communicateEachOther;
@end
//父类没有实现,则会导致出状况
@implementation Communicate

-(void)communicateEachOther{
  NSLog(@"父类的沟通方式");
}
@end

@protocol Phone
-(void)waiwaiwai;
@end


@protocol Mail
-(void)typeContent;
@end

@protocol SmartPhone <Phone,Mail>
-(void)playGame;
@end

@interface Cellphone:Communicate <SmartPhone>
-(void)call;
@end

@implementation Cellphone
 
-(void)communicateEachOther{
  NSLog(@"我们一起联系联系");
}


-(void)waiwaiwai{
  NSLog(@"歪歪歪,你是谁");
}

-(void)typeContent{
  NSLog(@"发个邮件,写封信");
}

-(void)playGame{
  NSLog(@"玩个智能手机还能打打游戏");
}

-(void)call{
  NSLog(@"我就想自己打个手机电话");
}


@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
  Cellphone* cellphone =[[Cellphone alloc]init];
    [cellphone communicateEachOther];
    [cellphone waiwaiwai];
    [cellphone typeContent];
    [cellphone playGame];
    [cellphone call];
    //使用协议来定义变量
    NSObject<Phone>* myphone=[Cellphone new];//类似于向上转型
    [myphone waiwaiwai];
    
    id<Mail> mymail=[Cellphone new];
    [mymail typeContent];
    
  }
}

输出:
2020-05-20 22:49:06.365638+0800 EX003[3701:254507] 我们一起联系联系
2020-05-20 22:49:06.365956+0800 EX003[3701:254507] 歪歪歪,你是谁
2020-05-20 22:49:06.365989+0800 EX003[3701:254507] 发个邮件,写封信
2020-05-20 22:49:06.366012+0800 EX003[3701:254507] 玩个智能手机还能打打游戏
2020-05-20 22:49:06.366033+0800 EX003[3701:254507] 我就想自己打个手机电话
2020-05-20 22:49:06.366055+0800 EX003[3701:254507] 歪歪歪,你是谁
2020-05-20 22:49:06.366074+0800 EX003[3701:254507] 发个邮件,写封信

可以使用@optional 和@required来修饰两个关键字,
@optional是可选
@required是必选的方法

8.@try–@catch–@finally访问异常信息

@try {
NSNumber * mu=[NSNumber init];
} @catch (NSException *exception) {
NSLog(@"%@,%@",exception.name,exception.reason);
} @finally {
NSLog(@“资源回收”);
}

9.反射机制—获得Class

三种方式获得class

  • 使用Class NSClassFromString(NSString*
    aClassName)函数来获取Class,该函数需要传入字符串参数,该字符串参数的值时某个类的类名。
  • 调用某个类的class方法来获取该类对应的Class。[类名 class]将会返回该类对应的Class。推荐方法
  • 调用某个对象的class方法,该方法是NSObject类中的实例方法,该方法将会返回该对象所属类对应的Class。
int main(int argc, const char * argv[]) {
  @autoreleasepool {
  //通过字符串获得Class类
    Class clazz=NSClassFromString(@"NSDate");
    //使用class来创建对象
    id date=[clazz new];
    NSLog(@"%@",date);
    //通过对象来获得Class
    NSLog(@"%@",[date class]);
    //通过类来获得Class类
    NSLog(@"%d",clazz==NSDate.class);
  }
}

输出:
2020-05-21 00:19:24.806620+0800 EX003[3859:278728] Thu May 21 00:19:24 2020
2020-05-21 00:19:24.806795+0800 EX003[3859:278728] __NSTaggedDate
2020-05-21 00:19:24.806829+0800 EX003[3859:278728] 1

10.反射机制—检查继承关系

三个方法

  • isKindOfClass需要传入一个class参数,用于判断对象是否为该类及其子类的实例
  • isMemberOfClass:需要传入一个class参数,用于判断该对象是否为该类的实例
  • conformsToProtocol:需要传入一个class参数,用于判断该对象是否实现了该协议
#import <Foundation/Foundation.h>
@protocol goodApple
-(void)doAbeautifulApple;
@end

@interface Apple : NSObject<goodApple>
-(void)loveapple;

@end

@implementation Apple

-(void)doAbeautifulApple{
  NSLog(@"做一个有颜值的苹果");
}

-(void)loveapple{
  NSLog(@"爱上了苹果,平平安安");
}

@end
int main(int argc, const char * argv[]) {
  @autoreleasepool {
    Apple* apple=[[Apple alloc]init];
    //通过对象来判断该对象的class
    NSLog(@"%@",[apple class]);
    //判断对象是否为某各类的实例
    NSLog(@"apple 是否为APPle类的实例:%d",[apple isMemberOfClass:Apple.class]);
    //判断对象是否为NSObject类的实例
    NSLog(@"apple 是否为NSObject类的实例:%d",[apple isMemberOfClass:NSObject.class]);
    //判断对象是否为其类及子类的实例
    NSLog(@"apple 是否为APPle类及其子类的实例:%d",[apple isKindOfClass:Apple.class]);
    //判断对象是否为NSObject类及子类的实例
    NSLog(@"apple 是否为NSObject类及其子类的实例:%d",[apple isKindOfClass:NSObject.class]);
    //判断对象是否为实现了某种协议
    NSLog(@"apple 是否实现了goodApple协议:%d",[apple conformsToProtocol:@protocol(goodApple) ]);

  }
}

输出
2020-05-21 16:15:09.459839+0800 EX003[953:30770] Apple
2020-05-21 16:15:09.460164+0800 EX003[953:30770] apple 是否为APPle类的实例:1
2020-05-21 16:15:09.460213+0800 EX003[953:30770] apple 是否为NSObject类的实例:0
2020-05-21 16:15:09.460244+0800 EX003[953:30770] apple 是否为APPle类及其子类的实例:1
2020-05-21 16:15:09.460267+0800 EX003[953:30770] apple 是否为NSObject类及其子类的实例:1
2020-05-21 16:15:09.460290+0800 EX003[953:30770] apple 是否实现了goodApple协议:1

11.反射机制—动态调用方法

在程序中动态获取SEL对象,oc提供了如下方法

  • 使用@使用selector指令来获取当前类中指定的方法。概指令需要用完整的方法签名关键字作为参数,仅有方法名不够
  • 使用sel nsslectorFromString(nsstring *
    aselectName)函数根据方法签名官架子的字符串获取对应的方法。

在程序中调用对象的普通方法,则可通过如下两种方法来实现

  • 通过NSObject提供的系列performSelector:方法来实现,该方法的第一个参数需要传入一个sel对象。如果调用方法需要传入参数,则还可以通过withObject标签来传入参数
  • 使用objc-msgSend(receiver,selector,…)函数来调用。概函数的第一个参数是方法调用者,第二个参数代表调用的方法,接下来的参数将作为调用方法的参数。
12.手动内存管理(现在已是自动内存管理了)

改变对象引用计数的方式入如下
增加计数的
程序调用alloc,new,copy,mutableCopy开头的方法来创建对象时,对象引用计数+1
程序调用retain时

减少计数的
程序调用对象的release方法
autorelease:不改变该对象的引用计数的值,只是将对象添加到自动释放池中
retainCount:返回该对象的引用计数的值

retain方法返回调用该方法的对象本身,这样使对象在调用retain方法后,可以直接再次调用其他方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值