复习一遍OC基础知识,做一个完整笔记
[toc]
OC初步认知
OC是兼容C语言的
OO:面向对象
OOP:面向对象编程
#import和#include的区别
1. #import是OC导入头文件的关键字,#include是C/C++导入头文件的关键字
2. #import会自动导入一次,不会重复导入,#include重复导入会报错
3. #import <>引入系统文件,#import ""导入用户自定义的文件
如何编写类的声明
以@interface开头,以@end结尾,然后在class name对应的地方协商事物名称,也就是类名
注意:
1. 类名首字母必须大写
2. OC声明类中,属性必须写在大括号里面
3. 编写OC属性的时候建议在首字母前面加上_
如何编写类的实现
以@implementation开头,以@end结尾,然后在class name对应的地方写上类名
注意:
1. 类名首字母必须大写
2. OC声明类中,属性必须写在大括号里面
3. 编写OC属性的时候建议在首字母前面加上_
类调用new方法,内部会做三件事
- 为类创建出来的对象分配存储空间
- 初始化对象中的属性
- 返回初始化对象分配的指针地址(使用指针接收地址)
OC类中方法分为: 类方法和对象方法
- 类方法用类名调用,对象方法只能用对象调用
- OC中的类方法用+表示,对象方法用-表示
类方法和对象方法区别
- 对象方法必须用对象调用,类方法只能用类调用
- 对象方法可以直接访问属性,类方法不可以直接访问属性
- 调用类方法的效率比调用对象方法的效率要高
- 类方法和对象方法可以相互调用
类方法的应用场景
如果方法中没有用到属性,就尽量用类方法,类方法的执行效率要比对象方法高,类方法一般用于定义工具方法
面向对象三大特性
- 封装
- 继承
- 多态
实例变量
实例变量修饰符的作用域:从出现的位置到下一个修饰符的出现
默认情况下,都是被保护的@protected
@public 可以在其他类,本类,子类中访问被public修饰的成员变量
@private 不可以在其他类与其子类中进行访问,在本类中可以进行访问
@protected 不可以在其他类中进行访问,在本类与其子类中可以进行访问
@package 介于public和private之间的,
OC中的私有变量/方法
私有成员变量
@implementation Gun {
int _gunNum;
//在implementation中定义的成员变量称为私有成员变量,在implementation中定义的私有成员变量在其他类中无法操作
}
私有方法
只有方法的实现,而没有方法的声明
@property
是一个编译器指令,同时生成成员变量的声明和getter和setter方法的实现
如果想对传入的数据进行过滤,那么我们就必须重写getter/setter方法
如果重写了getter/setter方法,系统默认不会生成’_成员变量’
@interface Gun : NSObject {
int _numberOfGun;
int numberOfGun;
}
//默认生成_numberOfGun的声明和getter/setter的实现
@property int numberOfGun;
@property修饰符
如果给一个属性同时提供getter/setter方法,那么我们称这个属性为可读可写属性
如果给一个属性只提供getter方法,那么我们称这个属性为可读属性
如果给一个属性只提供setter方法,那么我们称这个属性为可写属性
如果给一个属性不提供getter/setter方法,那么我们称这个属性为私有属性
@property(getter=asd) int age;
// 将age的getter方法名称改为asd
@property(setter=asd:) int age;
// 将age的setter方法名称改为asd:
静态类型和动态类型
静态类型
- 将一个指针变量定义为特定类的对象时,使用的是静态类型,在编译的时候就知道这个指针变量所属的类.
- 在编译的时候访问不属于动态数据类型的属性和方法,编译器会报错
动态类型
- 在编译的时候编译器并不知道变量的真实类型,只有在运行的时候才知道他的真实类型
- 在编译的时候访问不属于动态数据类型的属性和方法,编译器不会报错
- 弊端:由于动态数据类型可以调用任意方法,所以有可能会调用到不属于自己的方法,而编译时不会报错,所以可能导致运行时出现错误
id和NSObject *区别
NSObject *是一个静态数据类型,id是动态数据类型
id gun = [Gun new];
if ([gun isKindOfClass:[Gun class]]) {
//isKindOfClass判断指定的对象是否是某一类,或者某一类的子类
//isMemberOfClass判断指定的对象是否是某一类的实例
[gun setNumberOfGun:10];
}
构造方法
重写init方法,在init方法中初始化成员变量
步骤:
- 必须先初始化父类,再初始化子类
- 必须判断父类是否初始化成功,只有父类初始化成功后,才能继续初始化子类
- 返回当前对象地址
- (instancetype)init
{
self = [super init];
if (self) {
<#statements#>
}
return self;
}
内存管理
内存管理涉及的操作
- 分配内存: 比如创建一个对象,就会增加内存
- 清除内存: 比如销毁一个对象,就会减少内存占用
内存管理的管理范围
- 任何继承了NSObject的对象
- 对其他非对象类型无效(Int,char,float,enum)
只有OC对象才需要进行内存管理的本质原因
- OC对象存放于堆里面
- 非OC对象一般放在栈里面(栈内存会被系统自动回收)
堆和栈
- 栈: 由操作系统自动分配释放\存放函数的参数值,局部变量的值.其操作类方式类似于数据结构中的栈(先进后出)
- 堆: 一般由程序员分配释放,若程序员不释放,程序结束时,可能由OS回收,分配方式类似于链表
引用计数器
系统中是根据对象的引用计数器来判断什么时候需要回收一个对象所占的内存
什么是引用计数器
- 每一个OC对象都有自己的引用计数器
- 他是一个整数
- 从字面意思上来说,他可以理解为:对象被引用的次数
- 也可以理解为:有多少人正在使用该对象