1.5 万能指针 id

一. id

id是一种数据类型,并且是一种动态数据类型

数据类型的用途:

1. 定义变量

2. 作为函数的参数

3. 作为函数的返回值

默认情况下所有的数据类型都是静态数据类型

静态数据类型的特点:

在编译时就知道变量的类型,知道变量中有哪些属性和方法

在编译的时候就可以访问这些属性和方法

并且如果是通过静态数据类型定义变量,如果访问了不属于静态数据类型的属性和方法,那么编译器就会报错

应用场景:多态,可以减少代码量,避免调用了子类特有的方法需要强制类型转换

  1. id obj1 =[[Person alloc] init];
  2. [obj1 sleep];
  3. [obj1 test];// Person类的私有方法
  4. id obj2 =[[Person alloc] init];
  5. [obj2 eat];
  6. [obj2 test];// Person类的私有方法

为了避免动态数据类型引发的运行时的错误,一般情况下如果使用动态数据类型定义一个变量,在调用这个对象的方法之前会 进行一次判断,判断当前对象是否能够调用这个方法

1. 判断指定的对象是否是某一个类,或者是某一个类的子类

  1. id obj =[[Student alloc] init];
  2. if(obj isKindOfClass:[Studentclass]){
  3. // 如果obj对象是Student类创建出来的或者是Student的子类创建出来的对象调用父类的eat方法
  4.   [obj eat];
  5. }

2. 判断指定的对象是否是当前指定的类的实例

  1. id obj =[[Student alloc] init];
  2. if(obj isMemberOfClass:[Studentclass]){  
  3.   // 判断对象obj是否是Student类创建出来的对象,如果是调用类的对象方法    
  4.   [obj eat];
  5. }

二. new的实现原理

1. 创建对象new做了三件事情:

1>. 开辟存储空间  + alloc 方法;

2>. 初始化所有的属性(成员变量) - init 方法;

3>. 返回对象的地址

2. + alloc做了什么事情

1>. 开辟存储空间;

2>. 将所有的属性设置为0;

3>. 返回当前实例对象的地址

  1. Person*p1 =[Person alloc];

3. - init做了什么事情

1>. 初始化成员变量,但默认情况下init的实现是什么都没有做;

2>. 返回初始化后的实例对象的地址

  1. Person*p2 =[p1 init];
注: + alloc 和 - init 返回的实例对象的地址是同一个地址

三. 构造方法

在OC中init开头的方法,我们称之为构造方法

构造方法的用途: 用于初始化一个对象,让某个对象一创建出来就拥有某些属性和值

1. 重写init方法,在init 方法中初始化成员变量

1>. 必须先初始化父类,再初始化子类

2>. 必须判断父类是否初始化成功,只有父类初始化成功才能继续初始化子类

3>. 返回当前对象的地址

  1. - instancetype init
  2. {
  3.   if(self =[super init]){
  4.       _age =10;
  5.   }
  6.   return self;
  7. }

2. instancetyp和id的区别

instancetype == id == 万能指针 == 指向一个对象

id 在编译的时候不能判断对象的真实类型

instancetype 在编译的时候可以判断对象的真实类型

1>. id和instancetype除了一个在编译时不知道真实类型,一个在编译时知道真实类型

2>. id可以用来定义变量,可以作为返回值,可以作为形参,instancetype只能作为返回值

注:以后但凡自定义构造方法,返回值尽量使用instancetype,不要使用id

3. 自定义构造方法 (init自定义构造只用初始化自己的成员变量,父类的父类来处理)

  1. -(instacetype)initWithAge:(int)age andName:(NSString*)name
  2. {
  3.   if(self =[super init]){
  4.     _age = age;
  5.     _name = name;
  6.   }
  7.   return self;
  8. }
  // NSLog输出%@ 最好重写 - (NSString *)description;
  1. -(NSString*)description
  2. {
  3.   return[NSString stringWithFormat:@"age = %i, name = %@", _age, _name];
  4. }

4. 自定义类工厂方法

1> 类构造方法:initWith.....

  1. -(instancetype)initWithAge:(int)age andName:(NSString*)name
  2. {
  3.   if(self =[super init]){
  4.     _age = age;
  5.     _name = name;
  6.   }
  7.   return self;
  8. }
2> 类工厂方法:类名开头.....
  1. +(instancetype)personWithAge:(int)age
  2. {
  3.    Person*p =[[self alloc] init];
  4.    p.age = age;
  5.    return p;
  6. }
四. 类的本质

五.SEL类型

1.创建一个人对象

  1. Person*p =[[Person alloc] init];

2.agesetter方法封装成SEL

  1. BOOL b =[p respondsToSelector:sel];
  2. NSLog(@"%i", b);

3.判断Person对象方法中中是否存在 - 号开头的setAge:方法

 

  1. BOOL b =[p respondsToSelector:sel];
  2. NSLog(@"%i", b);
4.判断Person类方法中是否存在 + 号开头的setAge:方法
  1. b =[Person respondsToSelector:sel];
  2. NSLog(@"%i", b);

5.通过performSelector调用有参数的方法, 那么参数必须是对象类型

  1. SEL sel1 =@selector(setName:);
  2.        
  3. [p performSelector:sel1 withObject:@"jack"];
  4. NSLog(@"name = %@", p.name);
 





原文地址:https://www.cnblogs.com/Xfsrn/p/4780784.html