1.5 万能指针 id
一. id
id是一种数据类型,并且是一种动态数据类型
数据类型的用途:
1. 定义变量
2. 作为函数的参数
3. 作为函数的返回值
默认情况下所有的数据类型都是静态数据类型
静态数据类型的特点:
在编译时就知道变量的类型,知道变量中有哪些属性和方法
在编译的时候就可以访问这些属性和方法
并且如果是通过静态数据类型定义变量,如果访问了不属于静态数据类型的属性和方法,那么编译器就会报错
应用场景:多态,可以减少代码量,避免调用了子类特有的方法需要强制类型转换
id obj1 =[[Person alloc] init];
[obj1 sleep];
[obj1 test];// Person类的私有方法
id obj2 =[[Person alloc] init];
[obj2 eat];
[obj2 test];// Person类的私有方法
为了避免动态数据类型引发的运行时的错误,一般情况下如果使用动态数据类型定义一个变量,在调用这个对象的方法之前会 进行一次判断,判断当前对象是否能够调用这个方法
1. 判断指定的对象是否是某一个类,或者是某一个类的子类
id obj =[[Student alloc] init];
if(obj isKindOfClass:[Studentclass]){
// 如果obj对象是Student类创建出来的或者是Student的子类创建出来的对象调用父类的eat方法
[obj eat];
}
2. 判断指定的对象是否是当前指定的类的实例
id obj =[[Student alloc] init];
if(obj isMemberOfClass:[Studentclass]){
// 判断对象obj是否是Student类创建出来的对象,如果是调用类的对象方法
[obj eat];
}
二. new的实现原理
1. 创建对象new做了三件事情:
1>. 开辟存储空间 + alloc 方法;
2>. 初始化所有的属性(成员变量) - init 方法;
3>. 返回对象的地址
2. + alloc做了什么事情
1>. 开辟存储空间;
2>. 将所有的属性设置为0;
3>. 返回当前实例对象的地址
Person*p1 =[Person alloc];
3. - init做了什么事情
1>. 初始化成员变量,但默认情况下init的实现是什么都没有做;
2>. 返回初始化后的实例对象的地址
Person*p2 =[p1 init];
三. 构造方法
在OC中init开头的方法,我们称之为构造方法
构造方法的用途: 用于初始化一个对象,让某个对象一创建出来就拥有某些属性和值
1. 重写init方法,在init 方法中初始化成员变量
1>. 必须先初始化父类,再初始化子类
2>. 必须判断父类是否初始化成功,只有父类初始化成功才能继续初始化子类
3>. 返回当前对象的地址
- instancetype init
{
if(self =[super init]){
_age =10;
}
return self;
}
2. instancetyp和id的区别
instancetype == id == 万能指针 == 指向一个对象
id 在编译的时候不能判断对象的真实类型
instancetype 在编译的时候可以判断对象的真实类型
1>. id和instancetype除了一个在编译时不知道真实类型,一个在编译时知道真实类型
2>. id可以用来定义变量,可以作为返回值,可以作为形参,instancetype只能作为返回值
注:以后但凡自定义构造方法,返回值尽量使用instancetype,不要使用id
3. 自定义构造方法 (init自定义构造只用初始化自己的成员变量,父类的父类来处理)
-(instacetype)initWithAge:(int)age andName:(NSString*)name
{
if(self =[super init]){
_age = age;
_name = name;
}
return self;
}
-(NSString*)description
{
return[NSString stringWithFormat:@"age = %i, name = %@", _age, _name];
}
4. 自定义类工厂方法
1> 类构造方法:initWith.....
-(instancetype)initWithAge:(int)age andName:(NSString*)name
{
if(self =[super init]){
_age = age;
_name = name;
}
return self;
}
+(instancetype)personWithAge:(int)age
{
Person*p =[[self alloc] init];
p.age = age;
return p;
}
五.SEL类型
1.创建一个人对象
Person*p =[[Person alloc] init];
2.将age的setter方法封装成SEL
BOOL b =[p respondsToSelector:sel];
NSLog(@"%i", b);
3.判断Person对象方法中中是否存在 - 号开头的setAge:方法
BOOL b =[p respondsToSelector:sel];
NSLog(@"%i", b);
b =[Person respondsToSelector:sel];
NSLog(@"%i", b);
5.通过performSelector调用有参数的方法, 那么参数必须是对象类型
SEL sel1 =@selector(setName:);
[p performSelector:sel1 withObject:@"jack"];
NSLog(@"name = %@", p.name);