1.OC内存管理的概念:管理OC对象的生命周期
2.内存管理的方法:
(1)alloc new copy会从内存中分配空间,封装malloc,是对象生命周期的起始(alloc new copy是NSObject的方法);
(2)dealloc方法是销毁对象用的,封装了free,是对象生命周期的结束,但是并不是自己调用的;
(3)retain-持有 release-释放 retainCount:引用计数
3.僵尸对象:在内存空间被系统回收之后,那个实例就叫僵尸对象
4.野指针(变量):调用这个僵尸对象的指针就叫野指针
5.内存管理的原则:谁retain,谁release
使用alloc申请内存,那么对象的引用计数为1
MRR(手动内存管理模式)要调用retain方法,才会让p2持有p1,引用计数+1;release 是用引用计数-1;
- (void)setDog:(Dog *)dog {
//判断是否进行自我赋值,如果不是则进行内存管理,如果是则不需要做任何事,避免野指针变量的出现
//这个if判断也更加符合业务逻辑
if(_dog != dog) {
// 旧狗释放
[_dogrelease];
// 新狗retain
_dog = [dog retain];
}
}
@property就是一个代码生成机制
@property(atomic, retain) Car *car;
@property(atomic, retain, readwrite)NSString *name;
@property(nonatomic,assign, getter = aa,setter = bb:) NSInteger age;
1.retain 其他的—包括自己定义的类
2.copy 涉及到NSString NSSet NSArray NSDicitonary这些类(共同点:都有可变的子类),都用copy关键字修饰
3.assign(默认)所以涉及到基本数据类型,都用assign关键字修饰
4.copy与retain的区别:copy是完完整整的复制一遍实例,除了retainCount
1.readonly :代表设置器方法并没有被生成
2.readwrite :设置器方法和返回器方法都被生成
1.atomic: 多线程保护机制,会耗用更多的系统资源
2.nonatomic: 没有多线程保护机制,容易失控,所以自己写多线程,不要使用多线程操作
可以重命名设置器和返回器方法,并且原来的方法还是在的
setter = bb: getter = aa
copy是将实例除了retainCount,在堆区复制了一遍(新的一块内存),并且有一个指针指向这个内存的首地址.
当属性类型为NSString NSSet NSArray NSDicitonary内存管理方式采用copy.
NSMutableString *mStr = [NSMutableStringstringWithString:@"xiaohua"];
p1.name = mStr;
NSLog(@"p1的名字:%@", p1.name);
[mStrappendString:@"gual"];
// 如果使用retain,则名字会被修改,不符合逻辑. 使用copy,则不会,因为是两块内存.
NSLog(@"p1的名字:%@", p1.name);
(1)将对象加入到自动释放池中,就不需要再关注对象的release.
(2)当自动释放池被销毁时,会对里面的对象逐个release.
(1)返回实例对象本身.
(2)调用了autorelease之后,对象本身的引用计数是不变.
程序猿不必再关心对象的释放
占用较大的对象如果使用autorelease,会浪费系统资源
(1)自动释放池以栈结构(先进后出)进行存储,当一个对象调用autorelease方法时,会将这个对象放入到栈顶的自动释放池.
(2)自动释放池,是用一个数组来管理加入的实例,加入的时候实际上是调用 addobject.
int main(int argc, const char * argv[]) {
// 自动释放池,当左边大括号开始的时候,自动释放池就被创建,右边大括号结束的时候,自动释放就被销毁了
@autoreleasepool {
Person *p1 = [[[[Person alloc] init] autorelease] autorelease];
p1.age = 21;
@autoreleasepool {
Person *p2 = [[[Person alloc] init] autorelease];
p2.age = 22;
}
Person *p3 = [[[Person alloc] init] autorelease];
p3.age = 23;
}
ARC是编译器特性,也就是在代码编译之后,编译器自动帮你加上retain release
(1)当没有一个强指针指向实例的时候,实例就要被销毁
(2)不允许 手动调用 retain, release, autorelease, retainCount ,[super dealloc] ,只有copy是可以的
(3)在ARC环境可以把对象添加到自动释放池中
__autoreleasing Person *p1 = [[Person alloc] init]
(1)__strong :修饰的指针变量为强指针变量
(2)__weak :弱指针变量
在@property里使用关键字
strong 就相当于WRR里的retain
weak 就相当于WRR里的assign
copy 和MRR里的copy是一样的
// @property使用关键字strong之后生成的设置器方法
(void)setDog:(__strong Dog *)dog {
if (_dog != dog) {
_dog = dog;
}
}
// @property使用weak关键字后生成的设置器方法
- (void)setPerson:(__weak Person *)person {
if(_person != person) {
_person = person;
}
}
ARC不是万能的,还是会造成循环引用
对象A retain(strong)对象B。同时对象B retain(strong)对象A, 这种情况我们称之为循环引用·循环引用会导致两个对象都无法销毁掉。
解决方法:其中一个对象使用assign(weak).
对于某些我们不希望使用 ARC 的文件,例如第三方库源文件,可以在 Project Settings -> Build Phases 中设置
-fno-objc-arc 标记源代码文件使用MRR
-fobjc-arc 标记源代码文件使用ARC