让代码书写更加简便
--1-- 设置器和访问器 1.1 setter 1.2 getter --2-- 类的本质 2.1 类类型的对象 2.2 类的本质 2.3 如何获取类对象 2.4 类对象的使用 2.5 类对象的存储 --3-- SEL类型 3.1 SEL --4-- @property关键字 4.1 基本概念 4.2 @property用法 4.3 @property使用注意事项 --5-- @synthesize关键字 5.1 @synthesize用法 5.2 @synthesize使用注意 5.3 @synthesize指定实例变量赋值 --6-- self关键字 6.1 介绍 6.2 在对象方法中使用self 6.3 用在类方法中使用self【写在开头】
『在面向对象的编程中,封装是其一个重要的特性。封装将一个可供外部使用的接口暴露出来,隐藏了复杂的代码逻辑实现。
不可被外部任意存储是面向对象设计的本质,降低了数据被无用的可能性。
外部就可以通过设置器setter和访问器getter来对对象的属性进行设置和访问,而不是直接访问对象的属性->
在开发过程中,考虑到安全性要求,一般不再成员变量名前面使用@public、@protected等关键字修饰,而是使用Set方法来为对象提供成员变量的值,在set方法的内部也可以对一些不合理的赋值进行筛选过滤。』
--1-- 设置器和访问器
1.1 setter
setter方法(设置器):在set方法的内部可以对一些不合理的数据过滤筛选。set方法作用:为提供一个设置成员变量值的方法。
命名规范:
1)方法名必须以set开头
2)set后面跟上成员变量的名称,首字母大写
3)返回值一定是void
4)一定要接受一个参数,而且参数类型需要和成员变量的类型一致
5)形参名不能和变量名一样(成员变量名以_线开头,苹果官方推荐成员变量名前加_以示区分)
好处:
1)不让数据暴露在外,保证了数据的安全性
2)对设置的数据进行过滤
{ //成员属性 NSString *_name; int _age; }
setter
//setter - (void)setName:(NSString *)name; - (void)setAage:(int)age;
1.2 getter
作用:为调用者返回对象内部的成员变量
命名规范:
1)一定有返回值,返回值的类型和成员变量的类型一致
2)方法名和去掉下划线的成员变量名一样(此处与Java等语言不一样)
3)不需要接收任何参数
//getter - (NSString *)name; - (int)age;
--2-- 类的本质
2.1 类类型的对象
类的本质其实也是对象,只不过是class类型的对象,也叫做类对象
2.2 类对象
类对象
* 类对象在程序运行时一直存在
* 类对象是一种数据结构,存储类的基本信息:类大小,类名,类的版本以及消息与函数的映射表等
* 类对象所保存的信息是在程序编译时确定,在第一次使用该类的时候被加载到内存中
* 类对象代表类,class代表类对象,类方法属于类对象
* 如果消息的接收者是类名,则类名代表类对象
* 运行时,所有类的实例都由类对象生成,类对象会把实例的isa的值修改成自己的地址,每个实例的isa都指向该实例的类对象
* 从类对象里可以知道父类的信息、可以响应的方法等
* 类对象只能使用类方法,不能使用实例方法
2.3 如何获取类对象
1)通过实例对象获取
Person *person = [[Person alloc] init]; //创建对象 //通过实例对象获取类对象Dog Class c1 = [person class]; //Class类型的是一个结构体指针 Class c2 = [person class]; NSLog(@"c1->%p", c1); //0x1000011d8 NSLog(@"c2->%p", c2); //0x1000011d8
2)通过类名获取(类名其实就是类对象)
//通过类名获取类对象 Class c3 = [Person class]; NSLog(@"c3->%p", c3); //0x1000011d8
发现通过类名和实例获取对象,所获得的对象是同一个
实际上,都是获得了类对象Person class
2.4 类对象的使用
1)用类对象创建对象
两个测试方法:
//对象方法 - (void)test; //类方法 + (void)test;
使用
//用类对象来创建对象 Person *person2 = [[c1 alloc] init]; [person2 test]; //调用对象方法的test -test
2)用类对象来调用类方法
//用类对象来调用类方法 [c1 test]; //调用类方法 +test
2.5 类对象的存储
isa指针
- 每一个对象都包含一个isa指针.这个指针指向当前对象所属的类。
- [p eat];表示给p所指向的对象发送一条eat消息,调用对象的eat方法,此时对象会顺着内部的isa指针找到存 储于类中的方法,执行。
- isa是对象中的隐藏指针,指向创建这个对象的类。
- 通过isa指针我们可以在运行的时候知道当前对象是属于那个Class(类)的。
--3-- SEL类型
3.1 SEL
SEL:全称selector,表示方法的存储位置
方法调用的原理:其实每个类加载到内存中对象的方法都会封装成一系列的SEL列表,SEL会保存着这个方法的信息(当然包括方法的内存地址),当要调用该方法的时候,对象会通过isa指针找到内存中对应的方法的内存地址然后再调用该方法,在找到该方法之后该类对象会把该SEL放入缓存中,以便第二次寻找的时候提高效率
Person *p = [[Person alloc] init];
[p test];
寻找方法的过程
1)首先把test这个方法名包装成SEL类型的数据
2)根据SEL数据找到对应的方法地址
3)根据方法地址调用相应的方法
4)注意:在这个操作过程中有缓存,第一次找的时候是一个一个的找,非常耗性能,之后再用到的时候就直接使用了
--4-- @property关键字
4.1 基本概念
@property是编译器的指令。(编译器指令是由编译器完成的)
好处是免去我们手工书写成员属性getter和setter方法繁琐的代码。
4.2 @property用法
格式:
@property 类型名 方法名
如:
@property int age;
相当于完成了age属性的set和get方法的声明和实现
- (void)setAge:(int)age;
- (void)age;
注意:
1、在Xcode4.4之前,用于帮我们实现get/set方法的声明
2、在Xcode4.4之后,有增强功能,连实现也自动完成了
Person.h->
/* 省略了方法的声明 相当于是替换了下面的这两句声明 - (void)setAge:(int)age; - (int)age; 同时,还自动生成了对应的成员属性 _age,但是这个属性是私有的,外部只能通过setter/getter访问 */ @property int age;
Person类中没有自定义 _age属性,但是@property自动生成了该属性:
@implementation Person //对象方法 - (void)test{ NSLog(@"-TEST"); self->_age = 3; //在这里可以看到,@property生成了一个_age属性 } //类方法 + (void)test{ NSLog(@"+TEST"); } @end
调用:
Person *person = [[Person alloc] init]; //创建对象 //此处 _age属性由@property生成 person.age = 3; //设置成员属性 NSLog(@"person.age->%d", person.age); //3
4.3 @property使用注意事项
在老式的代码中
@property只能写在@interface [email protected]之间
@property用来自动生成成员变量get/set方法的声明(Xcode4.4之前)
告诉@property要生成的get/set方法声明的成员变量类型是声明
告诉@property要生成的get/set方法是哪个属性的,属性名去掉下划线
--5-- @synthesize关键字
5.1 @synthesize用法
@synthesize age;
写在.m文件中,表示对生成.h中变量age的get和set方法的实现
格式:
@synthesize 方法名
注意:
如果使用@synthesize则变量名要先在.h文件中声明
.h
@property int age;
.m
@synthesize age;
展开形式如下:
@synthesize age; //展开 - (void)setAge:(int)age{ self->age = age; //注意这里不是对Person原来的成员变量_age赋值,而是生成了一个变量age,然后对其进行赋值 //(如果这里写self,那么这个变量age也就相当于是个成员变量了) //所以使用@synthesize时,下面只打印了age和name的值,没有对_age和_name进行操作 //NSLog(@"age = %d, name = %@", age, name); //NSLog(@"_age = %d, _name = %@", _age, _name); }
5.2 @synthesize使用注意
Xcode4.4之前@property和@synthesize搭配使用,用于简化set和get方法的定义和实现
5.3 @synthesize指定实例变量赋值
声明
@property int a;
实现
@sythesize a = _b; //表示用a的get和set方法,修改属性b的值
相当于下面的代码:
- (void) setA:(int)a{
_b = a;
}
- (int)a{
reurn _b;
}
@interface Person : NSObject @property NSString *name; //如果两个实例变量的类型一致,如:age和weight,@property可以用逗号隔开变量,在一行上定义 @property int age, weight; //测试方法 - (void)test; @end @implementation Person //用age的getter和setter方法,修改属性_age的值 @synthesize age = _age, name = _name, weight = _weight; @end
--6-- self关键字
6.1 介绍
OC语言中的self,就相当于C++、Java中的this指针。
学会使用self,首先要搞清楚属性这一概念。
以及理解getter(访问器)和setter(设置器)方法,它到底有什么用?
设置器与访问器,提供外界操作 类内部属性的一个通道。
假如,没有这个方法,外界怎么操作类的内部属性。
假如不提供这两个方法,那么这个属性的值,就不能为外界所改变。
因为类的属性,默认是@protect(受保护类型)。
self的应用场景
1)用在类方法中
2)用在对象方法中
3)访问成员变量
4)self在OC的内存管理特殊使用
6.2 在对象方法中使用self
//学生学习对象方法 - (void)study{ //此时self指代学生对象 NSLog(@"- self->%p", self); //0x1002001b0 }
6.3 用在类方法中使用self
//学生信息类方法 + (void)info{ //此时self指代学生类 NSLog(@"+ self->%p", self); //0x1000013d0 }
查看:
@autoreleasepool { Student *stu = [[Student alloc] init]; //学生对象地址 NSLog(@"stu->%p", stu); //0x1002001b0 //学生类地址 NSLog(@"Student-%p", [Student class]); //0x1000013d0 //发送study和info消息 [Student info]; //0x1000013d0 [stu study]; //0x1002001b0 }
输出-->
综上总结:
self要指代谁?具体是要看self写在哪个方法中,
如果self写在对象方法中,则指代的就是当前方法的对象([类 new])
如果self写在类方法中,那么它指代的就是当前的类对象(类 class)
注意这里类对象和对象是两个概念
【写在结尾:】
『想起一首席慕容的诗:
一棵开花的树 如何让你遇见我 在我最美丽的时刻 为这 我已在佛前求了五百年 求佛让我们结一段尘缘 佛於是把我化做一棵树 长在你必经的路旁 阳光下 慎重地开满了花 朵朵都是我前世的盼望 当你走近 请你细听 那颤抖的叶 是我等待的热情 而当你终於无视地走过 在你身後落了一地的 朋友啊 那不是花瓣 那是我凋零的心』