IOS笔记-内存管理

引言:内存管理是OC中非常重要的一块儿,在实际操作中有许多的细节需要我们去注意。李杰明老师的视频由浅到深的详细讲解了内存这个版块,并且着重强调了内存管理的重要性。在这里我也详细总结了关于内存管理的一些知识。

管理范围:任何继承自NSObject的对象,对基本数据类型无效

一:计数器的基本操作

1>计数器的基本结构:引用计数器4字节

2>引用计数器的作用

当使用alloc(分配存储空间)、new或者copy创建了一个新对象时,新对象的引用计数器默认值就是1。

当计数器为0时,整个程序退出。

当计数器部位0时,占用的内存不能被回收。

3>引用计数器的操作

1.retainCount

 

 1
 2
 3
 4
// 设计一个Person类
Person *p = [[Person alloc]init];
int a = [p retainCount]; // NSUInteger a = [p retainCount];
NSLog(@"计数器:%d",a); // a = 1(默认)
 来自CODE的代码片
retainCount.m

 

retainCount:获取当前计数值

回收:

(1).运行中回收 (比如植物大战僵尸中的子弹,发出去就要回收)

(2).程序退出  (mian函数没有结束,程序不会退出)

2.重写dealloc方法(类似遗言)

当一个对象被回收的时候,就会自动调用这个方法

 

 1
 2
 3
 4
 5
 6
 7
 8
@implementation Person
- (void)dealloc
{
NSLog(@"Person对象被回收")
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end
 来自CODE的代码片
dealloc.m

 

3.retain、release

 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
int main()
{
Person *p = [[Person alloc]init];
[p retain];
// 有retain 就要release
[p release];
// 有alloc 就要release
[p release]; // 运行中回收,调用dealloc
p = nil; // 对象回收,指针也可以回收。
return 0
}
 来自CODE的代码片
retain.m

 

retain:返回对象本身,计数器+1;

release:没有返回值,计数器-1;

注:使用alloc,retain必须使用release

4>僵尸对象
当对象被回收,就是不可用内存,对象叫做僵尸对象,当我们再去访问这一块僵尸对象,就会报错。当对象被回收,指针为野指针。这一错误就称为:野指针错误。
OC不存在空指针错误,给空指针发送消息不报错。
[p release]; //报错
[nil release]; //不报错
二:set方法的内存管理
1>多对象内存管理
1.只要对象还在使用,这个对象就不会回收
只要你使用对象,对象的计数器就+1
不再使用对象,对象的计数器就减1
2.谁创建,谁release
如果通过alloc、new、或copy创建,就需要调用release或autorelease。

如果没有创建,就不用(auto)release。

3.谁retain,谁release

总结:有始有终,有加有减

2>set方法内存管理

例:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
// Book类
@interface Book:NSObject
@end
@implementation Book
- (void)dealloc
{
NSLog(@"Book被回收了")
[super dealloc];
}
@end
 
// Person类
@interface Person:NSObject
{
// Book对象
Book *_book;
}
// book的set方法和get方法
- (void)setBook:(Book *)book;
- (Book *)book;
@end
 
@implementation Person
// book的set方法和get方法
- (void)setBook:(Book *)book
{
_book = [book retain];
}
- (Book *)book
{
return _book;
}
 
- (void)dealloc
{
[_book release]; // 有retain就要release
NSLog(@"Person被回收了")
[super dealloc];
}
@end
int main()
{
Book *b = [[Book alloc] init]; // b = 1
Person *b = [[Person alloc] init]; // p = 1
// p1想占用b这本书
[p1 setBook:b]; // b = 2;
[b release]; // b = 1;
b = nil;
[p1 release]; // p1 = 0, b =0
p1 = nil;
return 0;
}
 来自CODE的代码片
多对象内存管理.m
1.对set方法的完善:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
@implementation Person
- (void)setCar:(Car *)car
{
if(car != car) // 防止重复定义报错
{
// 对当前正在使用的车(旧车)做一次release
[_car release];
// 对新车做一次retain操作
_car = [car retain];
}
}
@end
 来自CODE的代码片
set方法完善.m
2.内存管理代码规范
1.只要调用alloc,必须有release(autorelease)
2.set方法的代码规范:
(1)基本数据类型:直接复制
 1
 2
 3
 4
- (void)setAge:(int)age
{
_age = age;
}
 来自CODE的代码片
基本数据类型.m
(2)OC对象类型
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
@implementation Person
- (void)setCar:(Car *)car
{
if(car != car) // 防止重复定义报错
{
// 对当前正在使用的车(旧车)做一次release
[_car release];
// 对新车做一次retain操作
_car = [car retain];
}
}
@end
 来自CODE的代码片
set方法完善.m
三:@property的内存管理
在@property语法后面加入小括号,可以加入一些参数。例如:@property (retain) Book *book;   //retain生成的set方法里面的作用:release旧值,retain新值。
具体的@property参数有4类
1>内存管理相关参数
retain:release旧值,retain新值
assign:直接赋值(默认为assign,适用于非OC对象类型)
copy:release旧值,copy新值
2>是否要生成set方法
readwrite:同时生成set、get的声明、实现(默认情况)
readonly:只读。(只生成getting)
3>多线程管理
nonatomic:性能高(目前写代码必写)
atomic:性能低(默认情况)
4>setter 和 getter方法的名称
(getter method)  一般用在BOOL类型
(setter method)  这里的method要有冒号
 1
 2
 3
 4
 5
 6
 7
 8
 9
@property (getter = isRich) BOOL rich;
// 当遇到BOOL类型,返回BOOL类型的方法名一般以is开头
// OC对象
// @property (nonatomic,retain) 类名 *属性名
@property (nonatomic,retain) Car *car;
@property (nonatomic,retain) id car; //id类型除外
// 非OC对象类型(int\float\enum\struct)
// @property (nonatomic,assign) 类名 *属性名
@property (nonatomic,assign) int age;
 来自CODE的代码片
BOOLis.m
注:同一类参数不可同时写(除第四类外)。
四:循环retain 和 @class
1>@class的作用:仅仅告诉编译器,某一个名称是一个类
@class Person  // 仅仅告诉编译器,Person是一个类
2>开发中引用一个类的规范
(1)在.h文件中用@class来声明类
(2)在.m文件中用#import来包含类的所有东西
3>两端循环引用解决方案
(1)一端用retain
(2)一端用assign
4>两种方式的区别:
#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息.
例:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
#import <Foundation/Foundation.h>
 
@class Book;
@interface Student
@property (retain) Book *book;
@end
 
#import "Student.h"
#import "Book.h"
@implementation Student
- (void)dealloc {
[_book release];
[super dealloc];
}
@end
 来自CODE的代码片
@class.m
注意问题:为什么用@class更好
第一:解决循环retain问题
第二:提高性能
五:autorelease
1>autorelease的基本用法
(1)会将对象放到一个自动释放池中
(2)当自动释放池被销毁时,会对池子里面的所有对象做一次release操作。
(3)会返回对象本身
(4)调用完autorelease方法后,对象的计数器不变。
2>autorelease的好处
(1)不用再关心对象释放时间
(2)不用再关心什么时候调用release
3>autorelease的使用注意
(1)占用内存较大的对象不要随便使用autorelease
(2)占用内存较小的对象使用release没有太大影响
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
@autoreleasepool
{ // {开始代表创建了释放池
Person *p = [[[Person alloc] init] autorelease];
p.age = 10;
@autoreleasepool
{
Person *p2 = [[[Person alloc] init] autorelease];
p2.age = 12;
}
} // }结束代表释放池销毁
 来自CODE的代码片
autorelease.m
4>自动释放池
(1)在ios程序运行过程中,会创建无数个池子,这些池子都是以栈的结构存在(先进后出)
(2)当一个对象调用autorelease方法时,会将这个对象放在栈顶的释放池。
5>自动释放池的创建方式
(1)iOS 5.0以前
 1
 2
NSAutoreleasepool *pool = [[NSAutoreleasepool alloc] init];
[pool release]; // [pool drain]
 来自CODE的代码片
autoreleasepool.m
(2)5.0之后
@autoreleasepool{
}
实例操作:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
@interface Person:NSObject
+ (id)person;
+ (id)personWithAge;
@end
 
@implementation Person
+ (id)person
{
return [[self alloc] autorelease];
}
+ (id)personWithAge
{
Person *p = [self person];
p.age = age;
return p;
}
- (void)dealloc
{
NSLog(@"Person被回收了");
[super dealloc];
}
@end
 
#import <Foundation/Foundation.h>
int main()
{
@autoreleasepool
{
// 调用简单
Person *p = [Person person];
p2.age = 100;
}
 
return 0;
}
 来自CODE的代码片
实例操作.m
总结:1系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的。
[NSString stringWithFormat:……];
2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象。(注:创建对象时不要直接用类名,一般用self)
posted @ 2015-05-18 13:42  --------  阅读(164)  评论(0编辑  收藏  举报