OC-@property、self及类的本质

时间:2022-09-29 05:41:33

让代码书写更加简便

--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(类)的。

OC-@property、self及类的本质

--3-- SEL类型

3.1 SEL

SEL:全称selector,表示方法的存储位置

方法调用的原理:其实每个类加载到内存中对象的方法都会封装成一系列的SEL列表,SEL会保存着这个方法的信息(当然包括方法的内存地址),当要调用该方法的时候,对象会通过isa指针找到内存中对应的方法的内存地址然后再调用该方法,在找到该方法之后该类对象会把该SEL放入缓存中,以便第二次寻找的时候提高效率

OC-@property、self及类的本质

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 = ; //在这里可以看到,@property生成了一个_age属性
} //类方法
+ (void)test{
NSLog(@"+TEST");
}
@end

调用:

Person *person = [[Person alloc] init]; //创建对象

//此处 _age属性由@property生成
person.age = ; //设置成员属性
NSLog(@"person.age->%d", person.age); //

4.3 @property使用注意事项

在老式的代码中

@property只能写在@interface ...@end之间

@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
}

输出-->

OC-@property、self及类的本质

综上总结:

self要指代谁?具体是要看self写在哪个方法中,

如果self写在对象方法中,则指代的就是当前方法的对象([类 new])

如果self写在类方法中,那么它指代的就是当前的类对象(类 class)

注意这里类对象和对象是两个概念

【写在结尾:】

『想起一首席慕容的诗:

一棵开花的树

如何让你遇见我
在我最美丽的时刻 为这
我已在佛前求了五百年
求佛让我们结一段尘缘
佛於是把我化做一棵树
长在你必经的路旁 阳光下
慎重地开满了花
朵朵都是我前世的盼望 当你走近
请你细听
那颤抖的叶
是我等待的热情 而当你终於无视地走过
在你身後落了一地的
朋友啊
那不是花瓣
那是我凋零的心』