内存管理必须遵守的原则 :
(1) 使用者必须保证在他使用的周期内是安全的, 保证在不使用的时候消失
(2) 谁让引用计数+1, 谁要负责引用计数-1
1. 堆区内存有系统去管理(出生命周期被自动释放掉)
int a = 10; a在栈区 (所有的变量都在栈区, 除了静态static,和全局变量)
2. People *p = [[People alloc]init];
p 在栈区 指向 People产生的对象(堆区)
3. 堆区的每一块内存不能起名字, 栈区的变量指向堆区
(堆区 p -> 栈区 对象)
4. (1) p 释放掉 , 对象没有释放 -> 内存泄露
(2) 对象释放掉, p没有释放掉 -> 野指针异常
5. 局部变量 和 成员变量的最大区别在于 变量名的生命周期
(1)局部变量只是在方法内部定义的变量!
(2)成员变量 作用于整个类的使用
空对象: 指针指向的地址是nil
9. (1)如果在类中声明了成员变量, 那么成员变量的创建必须在init中且必须保证引用计数为1, 并在dealloc中释放
(2)如果在类中声明了属性, 那么对属性赋值的时候必须通过点语法来进 行赋值(为了保证引用计数为1且避免内存泄 露),且必须在dealloc中释放
#import <Foundation/Foundation.h>
@class Student;
@interface Car : NSObject
{
//成员变量
@public
NSMutableArray *_array;
}
@property(nonatomic, retain)NSMutableArray *arr;
//把其他类写成属性
@property(nonatomic, retain)Student *stu;
//setter 方法
-(void)setArray:(NSMutableArray *)arr;
//getter 方法
-(NSMutableArray *)array;
//便利构造器
+(Car *)car;
@end
Car.m
#import "Car.h"
#import "Student.h"
@implementation Car
- (void)dealloc
{
//不管是成员变量还是属性, 都需要在dealloc 写释放
[_array release];
[_arr release];
[super dealloc];
}
//便利构造器
+(Car *)car
{
Car *c = [[Car alloc]init];
return [c autorelease];
}
// setter 方法
-(void)setArray:(NSMutableArray *)arr
{
//防止 内存泄露
if (_array != arr) {
[_array release];
_array = [arr retain];
}
}
// getter 方法
-(NSMutableArray *)array
{
[_array retain];
return [_array autorelease];
}
//初始化 (重写父类方法)
- (instancetype)init
{
self = [super init];
if (self) {
// 1. 成员变量
// 两种写法 引用计数 + 1
// 类的开始在init , 结束在dealloc 中, 成员变量在类中保持平衡
_array = [[NSMutableArray alloc]init];
_array = [[NSMutableArray array]retain];
// 2. 属性 (引用计数保持平衡)(点方法会调用setter方法, 引用计数加1, 所以不能用alloc的初始化方法)
self.arr = [NSMutableArray array];
// 3. 如果把其他类写成属性 (引用计数保持平衡)
self.stu =[[[Student alloc]init]autorelease];
self.stu = [Student student]; // (便利构造器)
}
return self;
}
10. cope : 所有遵循于NSCopying协议的类, 都可以使用copy
比如: [NSString , NSArray, NSDictionary, NSNumber, NSValue] (NSString 特殊, 不可变也可以写copy)
11. 在系统类里面对不可变类型使用copy 那么其效果类似于 retain;
不可变 : 使用copy, 会在原有基础上 + 1 = > 2
NSArray *arr = [NSArray arrayWithObjects:@"1", @"2", nil];
NSArray *arr1 = [arr copy];
NSLog(@"arr= %p, arr1 = %p", arr, arr1);
NSLog(@"retainCount: arr = %ld, arr1 = %ld", [arr retainCount], [arr1 retainCount]);
打印结果:
arr= 0x10010eb10, arr1 = 0x10010eb10
retainCount: arr = 2, arr1 = 2
// 由打印结果可以看出: 地址没有变化, 引用计数 + 1 变成 2
12. 可变对象使用copy得到的是不可变对象;
可变 : 使用copy, 会在结果上引用计数 + 1 = > 1
NSMutableArray *mArr = [NSMutableArray arrayWithObjects:@"1", @"2", nil];
NSMutableArray *mArr1 = [mArr copy];
NSLog(@"mArr= %p, mArr1 = %p", mArr, mArr1);
NSLog(@"retainCount: mArr = %ld, mArr1 = %ld", [mArr retainCount], [mArr1 retainCount]);
打印结果:
mArr= 0x10010ed30, mArr1 = 0x10010eee0
retainCount: mArr = 1, mArr1 = 1
// 由打印结果可以看出: 地址改变, 引用计数会在结果上的(mArr)引用计数 + 1 变成 1
13. 可变对象可以使用mutableCopy得到可变对象;
NSMutableArray *mArr2 = [mArr mutableCopy];
[mArr2 addObject:str];
14. 将属性写成 copy类型
建立Person类
.h
@property(nonatomic, copy)NSMutableArray *array;
.m
// 系统的写法 写的还是copy
-(void)setArray:(NSMutableArray *)array
{
if (_array != array) {
[_array release];
_array = [array copy]; // 变成不可变数组
}
}
main.m
People *p = [[People alloc]init];
[p.array addObject:@"1"]; //不可变数组添加不了元素
// 运行一下, 就会crash, 需要将系统的setter方法进行改写
.m
// 重新写系统的方法, 把copy改成retain
-(void)setArray:(NSMutableArray *)array
{
if (_array != array) {
[_array release];
_array = [array retain];
}
}
main.m
People *p = [[People alloc]init];
[p.array addObject:@"1"];
NSLog(@"p.array = %@", p.array);
NSLog(@"retainCount = %ld", [p retainCount]);
打印结果:
p.array = (
1
)
retainCount = 1
15. (1)如果在数组或字典(无论可变不可变)中添加一个元素,那么这个元素的引用计数+1(保证数组或字典在使用元素时安全)
(2)如果在数组或字典(无论可变不可变)中移除一个元素,那么这个元素的引用计数-1,数组或字典释放时,其中的元素也一一释放掉
//加入不可变数组
Person *p1 = [[Person alloc ] init];
NSLog(@"p1.retainCount = %ld", [p1 retainCount]);
NSArray *array = [NSArray arrayWithObjects:p1, nil];
NSLog(@"数组添加元素p1.retainCount = %ld", [p1 retainCount]);
//加入可变数组
Person *p2 = [[Person alloc ] init];
NSLog(@"p2.retainCount = %ld", [p2 retainCount]);
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:
p2, nil];
NSLog(@"数组添加元素p2.retainCount = %ld", [p2 retainCount]);
[mArray removeObject:p2];
NSLog(@"数组移除元素p2.retainCount = %ld", [p2 retainCount]);
打印结果:
p1.retainCount = 1
数组添加元素p1.retainCount = 2
p2.retainCount = 1
数组添加元素p2.retainCount = 2
数组移除元素p2.retainCount = 1
16. assign : 不引起引用计数的改变 (只有简单类型才写成assign类型)
Person类
.h
@property (nonatomic, assign) NSMutableDictionary *mDic;
.m
// 系统的写法
- (void)setMDic:(NSMutableDictionary *)mDic
{
_mDic = mDic;
}
nonatomic : 非属性安全, 没有做冲突处理