关键词:局部变量放在栈中,自动释放 开辟空间 释放空间
C中:char c[10]; char * p = (char *) malloc(10); // 开辟的空间长度是10; p[0] = 'A'; ….. p[9] = 'G'; p[10] = 'H'; 最终的字符串p中仍包含H这个字符。开辟的虽然是10个字节的空间,但之后被定义的字符仍能输出。
C中有重复释放的问题,有多个指针指向同一块内存空间,但只需释放一次。而在OC中有内存计数,可以释放多次,有几个指针指向同一空间就可以释放几次。
ARC:Automatic Reference Counting 自动释放
MRC:手动释放
内存释放之后对象还可以调用方法. 缓冲、野指针的问题
内存管理的方式:不需要时刻关注内存管理的引用计数。
谁创建[alloc(+1)]谁释放[release(-1)]。谁retain(+1)谁release(-1)。
深拷贝、浅拷贝 可变空间、不可变空间
copy可以深拷贝(对可变字符串)也可以是浅拷贝(对不可变字符串),mutableCopy只能是深拷贝。copy得到的是不可变空间,mutableCopy得到的可变空间。 copy用NSString接收,mutableCopy用NSMutableString接收。
当copy对不可变字符串进行拷贝的时候是浅拷贝,内存空间不变,当对可变字符串进行拷贝的时候是深拷贝,内存空间可变。
析构函数:释放成员变量 在对象释放之前。(在MRC中使用)
@property展开之后的三个东西:1.set方法 2.get方法 3.自动生成一个带下划线的成员变量。如:
@property (nonatomic, copy) NSString * name;
等效于:
-(void)setName:(NSString *)name{
_name = name;
}
-(NSString *)name{
return _name;
}
调用dealloc方法销毁内存。
MRC中property的使用:
析构函数dealloc是用来释放成员变量的,当成员变量是用copy、retain修饰的时候都要进行释放。
// 析构函数 释放成员变量
-(void)dealloc{
self.name = nil;
self.subjectsArr = nil;
[super dealloc];
}
self.name = nil;有两个功能:1.释放内存 2.设置成空指针,防止野指针的出现。
在MRC中,只要用到alloc开辟空间,就要进行一次释放。且是谁创建谁释放。
Student * xiaoming = [[Student alloc] init];
[xiaoming studying];
// 有alloc进行释放
[xiaoming release];
在不采用retain计数的时候,哪怕是两个指针指向同一块内存,只需进行一次release即可。没有成员变量不必重写析构函数。(本人刚开始时的记忆方式)
ARC和MRC的混编:
ARC和MRC的文件可以建在同一个工程中,只不过要做一些处理。 // 如何ARC和MRC混编 步骤:
// 选中工程 -> Targets ->Build Phases -> Compile Sources
// 找到此文件 在右侧Compile Flags (将内容改为 -fno-objc-arc)
自动释放池:autoreleasepool(在MRC中)
有两种写法:1.@autoreleasepool{} 2. NSAutoreleasePool * pool = [NSAutoreleasePool alloc] init; [pool release]; 两种写法的效果是一样的。
在自动释放池中有一个方法叫自动释放autorelease,它不同于release这个方法,release被调用后,引用计数会立马减1,而autorelease没有立马这么快,它有一个延迟(同样有用),在未来(自动释放池释放后)某个时间对计数器做减1的操作。当自动释放池释放的时候,释放池内部的所有对象所占的内存才被释放。这是因为:自动释放池内部有一个特殊的数组,这个数组专门用来存储池子内部autorelease对象。当自动释放池释放的时候,会遍历这个数组,将里面的对象全部销毁。
MRC中有一个特殊的东西,那就是数组。
当将用alloc开辟空间创建的对象放入数组后,再对这些对象用release释放后,这些对象的计数器仍不为零。只有当数组销毁的时候,这些对象的计数器才会为零。这是因为往数组中添加对象的时候,数组对这些对象做了retain操作,再数组释放的时候,数组又对这些对象做了release的操作。不过这些操作也全是再内部进行操作,并不需要我们去操作。我们只要记得使用黄金法则进行内存管理就可以了。
(感觉用了ARC之后可以完全不去理会MRC了,ARC已经帮助我们全部完成了)
回忆前面讲到的单例:
static Math * myMath = nil;
@implementation Math
// 创建对象的另外一种使用:单例的形式
+(Math *)createMath
{
if(myMath == nil){
myMath = [[Math alloc] init];
}
return myMath;
}
单例是类方法的特殊使用。
现在实现上方定义一个静态变量:
static Phone * phone = nil;
// 单例
+(Phone *)sharedPhone
{
if(phone == nil){
phone = [[Phone alloc] init];
}
return phone;
}
// 单例的使用
Phone * sanxing = [Phone sharedPhone];
NSLog(@"sanxing %p", sanxing); // 直接输出的是对象的地址
单例可以防止多处被实例化。即不能用alloc来开辟空间存储对象。(感觉还不是很明白)