OC基础复习(五)之点语法

1.

点语法的陷阱:

  1)如果想使用点语法,必须保证类中有set和get方法

  2)点语法注意:  点语法的本质是方法的调用,而不是访问成员变量,当使用点语法时,编译器会自动展开成相应的方法。

   切记点语法的本质是转换成相应的set和get方法。如果没有set和get方法,则不能使用点语法。

注意一个小知识点,容易理解跑偏:

我们知道在x-code4.4以后出现了一个叫@synthesize 的东西,这个东西最直观的理解是:简化了set和get方法的实现

但其实不只是简单的这样,

类中实例变量

     .h

    {

         int _speed;

         int speed;

    }

    @property int speed;

 

    .m

    @synthesize speed;

 

    此时: @property 类型 xxxx;  + @synthesize  xxxx; 搭配使用

    1,先看类中有没有定义一个 xxxx的实例变量,如果有,set和get方法,都将操作这个实例变量.

    2,如果没有, 它会自动帮我们创建一个xxxx,然后set和get方法操作这个实例变量

    3,如果帮我们生成了一个实例变量,注意这个实例变量是私有的

如下代码所示:当我们用到@property和@synthesize配合使用的时候如果实例变量中没有定义speed,那么神奇的是会自动帮我们生成一个speed实例变量,

而且set和get方法中操作的就是自动帮我们生成 的实例变量speed,即set和get方法如下所示:

-----------

set方法:
- (void)setSpeed:(int)speed{
    
     speed = speed;

}


get方法:
- (int)speed{
   
   return speed;

}

也就是把_speed屏蔽了,包括点语法也都是作用于speed而不是_speed,这一点容易产生理解错误,这是个特性,要特别记忆.

-----------

 

car.h

#import <Foundation/Foundation.h> @interface Car : NSObject { int _speed; // int speed; } @property int speed; //定义了 speed实例变量了吗? 没有,会不会给我们自动生成? 会 -(void)run; @end
car.m

#import "Car.h" @implementation Car @synthesize speed; -(void)run{ NSLog(@"speed = %d,_speed = %d",speed,_speed); // 0 200 // 200 0 对 } @end

 

 

 

2.重点:重写构造方法:

3.重难点解析:

1>  各种关系

依赖关系:对象作为方法的参数去传递

关联关系(组合关系):对象作为另一个对象的成员变量来使用

oc三大特性:封装、继承、多态

封装:将实现细节进行隐藏,将属性私有化,通过公共的方法访问私有的属性,这个过程就是对对象的封装

继承: 有两个类A类与B类,如果说A类继承了B类,就说A类拥有了B类的所有属性和方法

多态:没有继承就没有多态,父类类型的指针指向子类对象

 

2>  self和supper的解答

特点:self关键字最大的作用是让类中的一个方法访问该类的另一个方法或成员变量

supper,就是调用父类的方法。

  1. 声明方法接口
  2. self是谁?其实我们一点都不确定,要确定self是谁。只有先确定了那个方法是谁在调用,我们才能知道self是谁。它总是代表了当前类的对象;因此,当这里work方法是对象p在调用的时候,self就代表了对象p。self才在这里起了一个方法中调另一个方法的作用。这就是它最大的作用之一。
  3. main中实现调用

 

---------------------------------------------第一步声明---------------------------------

 

---------------------------------------------第二步实现---------------------------------

 

---------------------------------------------第三步调用---------------------------------

 

 

3>  Person *person =[ [Person alloc] init]; 细解

思路分析:Person是个类,[Person alloc] 是类在调方法,顾名思义alloc就是一个对象方法,那么alloc是哪里来的呢?因为所有类都继承自NSObjcet,所以alloc是从NSObject里面来的,同理init也是来自NSObject,可以跳到NSObject这个头文件去看

完整的创建对象有两步[Person new]中的new创建的对象太死板,里面直接做了alloc 和init这两步

  1. 分配了存储空间  ([Person alloc]其实是Person调用了它的类方法,当调用alloc的时候,此时,马上会返回一个有存储空间的对象给你,分配的这块存储空间里面全部是0,这个是不能用的,为什么?因为没有初始化,这就是需要引用到init的作用。)
  2. 初始化   (上面说了init的由来,所以所有的类都有一个默认的初始化方法init, 当调用了init之后就把这块空间给初始化了,这个对象就可以用了,但是它是最基本的初始化,里面还仍然全部是0)。因此,这也是我们为什么有时候要重写init构造方法的原因,就是在创建好对象之后,让这个区域里面不是0;

 

4>  init构造方法由来

构造方法:用来初始化对象的方法,是个对象方法 –开头。我们重写构造方法的目的,上面3>.2已经说了,为了让对象创建出来,成员变量就会有一些固定的值。

重写构造方法注意点:1.先调用父类的构造方法[super init]   2.再进行子类内部成员变量的初始化

思路分析:因为student区域里面包含了父类的其他成员变量,所以self =[super init],我们在初始化student的时候,要先调用[super init]进行一个初始化,才能保证student这块区域全部被初始化。 这也就是图片中1的由来。Self = [super init];  当确保super初始化完毕之后,并且赋值给了self,那么我们就可以对self进行一个判断了。Self != nil 的时候才执行里面的语句, nil的值为空,self!= 0可以省略写成self

 

注意:这里有个小问题就是重写构造方法的时候 为什么我们要先初始化父类即先调用父类的构造方法[super init]呢?

答:由继承关系可以知道,子类继承父类便拥有了父类的所有成员属性和方法,那么我们对子类新添加的成员变量初始化的时候其实子类中还含有父类的成员变量,我们并没有对父类的成员变量进行初始化,其实父类的成员变量也已经归属于子类了,那么就造成了一个问题,就是我们申请了内存空间但没有对自己的所有的成员变量初始化,那么这部分空间是不能够使用的,所以必须先初始化一下子类中含有的父类成员变量.

 

         

 

继承关系分部图

 

 

 

5>  类的本质

类的本质

类也是对象,我们平时用类来产生对象。是个Class类型的对象  类对象就是类。其他的用类来创建的对象是实例对象

先利用Class 创建  Person类对象

利用Person类对象  创建Person类型的对象

 

 

6>  SEL

SEL(数据类型)代表方法,一个SEL数据代表一个方法 方法是存在类中还是对象中? 类中

这个涉及到oc中的运行时机制   这种类型的数据就代表着方法

person *p = [person alloc] init];  这行代码过后  首先会分配存储空间给这个person这个类  在类里面每个方法都有一个跟它相对应的sel数据 sel s1 = - (void)test  s1是个数据来着,其实你可以把它当对象也可以。 每个对象里面都有一个isa指针指向它的类。 【p test】 找方法怎么找的。首先是把我们的test方法包装成sel类型的数据,然后通过isa找到我们的类里面,看下我们的sel 里面对应的是哪一个方法。根据sel就可以找到那个方法,其实sel里面对应的严格来说是我们的方法地址。  就是说  先把test方法包装成sel,再拿着sel去我们的类里面找,看我们的sel对应的是哪个方法。有了方法地址就可以调用我们的方法了。所以sel做什么事情的呢,就是我们方法的包装数据类型。而且这个操作是有缓存的,当第一次拿着sel去找方法的时候,它会挨个找一下sel对应哪一个东西,一个一个找,非常耗性能。当找过之后呢,以后去找的时候,它就会立刻使用上一次的查询结果。

sel有什么价值呢?

sel就是selector  我们调用某个方法给它发消息其实就是发送 sel类型的数据,根据sel类型的数据去内存中找对应的方法。其实发消息发送的就是sel,你把方法名包装成一个sel类型的消息,发送给我们到这里(类里面),发送到这里之后,就根据sel去找对应的方法

怎么来创建sel类型数据呢? SEL  s = @selector(test);  是代表利用@selector(test)这个指令创建出test这个方法对应是sel数据。那么有了这个数据,我们通过间接一传,那么就可以调用这个方法

 

总结:SEL其实就是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址,找到方法地址就可以调用方法。

这其实就是我们的消息机制,所以传说中的发消息,就是发送一个sel类型的数据。根据发送的sel去内存中找到方法

 

7>  Id == NSObjcet *

 

 

 

8>  动态绑定

所谓动态绑定就是,oc将会跟踪对象所属的类,它会在运行时判断该对象所属的类,并在运行时确定需要动态调用的方法,而不是在编译时确定要调用的方法

1.动态类型:运行的时候确定的类型

2.动态绑定:动态绑定是基于动态类型的;基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。动态绑定所做的,即是在实例所属类确定后,将某些属性和相应的方法绑定到实例上。

3.动态加载

动态创建class,动态添加class成员变量与成员函数,动态变量赋值与取值,动态函数调用等;

// 
Animal *ani = [Animal new]; // Animal  静态类型

/ 
Animal *ani2 = [Dog new];

NSObject *obj = [Dog new];


[(Dog *)obj run];

 

9>  id和instancetype的区别

id 和 instancetype 都可以用来作为方法的返回值

id可以用来定义类型,instancetype不能用来定义类型

id obj; // 容许

instancetype  obj2  // 错误

instancetype可以精确返回值类型

 

10>          

 

让学生继承人类,要求学生对象初始化之后,年龄是10,学号是1,怎么办?

 

现在有20个特种兵,特种兵随时随地都拥有一把枪,都可以开火

类: Soldier   [ˈsoʊldʒə(r)]

属性 :枪

行为:开枪

fire / faɪr/ 火  by  gun

类 Gun

属性: 子弹

行为:射击

 

给Person类定义一个构造方法,默认姓名为”匿名” 年龄:18

给Person类定义一个构造方法,默认姓名为”匿名” 年龄:18  学号为100

 

posted @ 2016-10-16 20:03  忆缘晨风  阅读(148)  评论(0编辑  收藏  举报