Objective-C的内存基本管理

在OC中每一个变量都保存着引用计数器,当这个对象的引用计数器为0的时候该对象会被回收。当使用alloc、new或者copy创建一个对象的时候,对象的引用计数器被置为1.

给对象发送一条retain消息,能够使引用计数器+1.

给对象发送一条release消息,能够使引用计数器-1.

当OC被销毁的时候会发送一条dealloc消息(不要直接调用,由系统调用),能够重写dealloc方法。在该方法中释放相关资源。

能够给对象发送retainCount消息获取对象的当前引用计数器。

首先我们新建一个project

接下来将project的设置里面将ARC禁掉

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGF3YW5nYW5iYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

Book.h文件

#import <Foundation/Foundation.h>

@interface Book : NSObject

@property float price;

- (id)initBook:(float)price;

@end

Book.m文件

#import "Book.h"

@implementation Book

@synthesize price = _price;

//构造函数
- (id)initBook:(float)price {
if(self = [super init]){
_price = price;
}
NSLog(@"价格是%f的书购买了", _price);
return self;
} //析构函数
- (void)dealloc {
NSLog(@"价格为%f的书被释放了", _price);
[super dealloc];
} @end

Student.h文件

#import <Foundation/Foundation.h>
#import "Book.h" @interface Student : NSObject @property int age;
@property Book *book; - (void)setBook:(Book *)book; - (id)initStudent:(int)age; @end

Student.m文件

#import "Student.h"
#import "Book.h" @implementation Student @synthesize age = _age;
@synthesize book = _book; - (void)setBook:(Book *)book {
if(_book != book){
//先对原来的书计数器减一
//假设之前为nil不会出错(和java中的空指针不同)
[_book release];
[book retain];
_book = book;
}
} //构造函数
- (id)initStudent:(int)age {
if(self = [super init]) {
_age = age;
}
NSLog(@"年龄为%d的学生被创建了", _age);
return self;
} //析构函数
- (void)dealloc{
[_book release];
NSLog(@"年龄为%d的学生被释放了", _age);
[super dealloc];
} @end

main.m文件

#import <Foundation/Foundation.h>
#import "Student.h"
#import "Book.h" void buyBook(Student *stu) {
Book *book1 = [[Book alloc] initBook:101.5]; //谁创建谁释放
stu.book = book1;
[book1 release];
Book *book2 = [[Book alloc] initBook:98.5];
stu.book = book2;
[book2 release];
} void readBook(Student *stu) {
NSLog(@"年龄是%i的学生在读价格为%f的书", stu.age, stu.book.price);
} int main(int argc, const char * argv[]) {
@autoreleasepool {
//计数器为1
Student *stu = [[Student alloc] initStudent:21];
//买书
buyBook(stu);
//看书
readBook(stu);
//计数器清0,释放内存
[stu release];
}
return 0;
}

输出结果:

2014-11-13 23:11:19.510 内存管理[698:46519] 年龄为21的学生被创建了

2014-11-13 23:11:19.512 内存管理[698:46519] 价格是101.500000的书购买了

2014-11-13 23:11:19.512 内存管理[698:46519] 价格是98.500000的书购买了

2014-11-13 23:11:19.512 内存管理[698:46519] 价格为101.500000的书被释放了

2014-11-13 23:11:19.512 内存管理[698:46519] 年龄是21的学生在读价格为98.500000的书

2014-11-13 23:11:19.512 内存管理[698:46519] 价格为98.500000的书被释放了

2014-11-13 23:11:19.512 内存管理[698:46519] 年龄为21的学生被释放了

@classkeyword

通常引用一个类有两种方法。一种是通过#import,还有一种是通过@class.

#import 的方式会将头文件里的全部信息引入。

@class 的方式仅仅是说明它是一个类(假如仅仅是声明一个类就不用使用#import).

#import <Foundation/Foundation.h>

@class Book; //声明Book是一个类

@interface Student : NSObject {
Book *_book;
} @property int age;
@property Book *book; - (void)setBook:(Book *)book; - (id)initStudent:(int)age; @end

另外。Student.m中的析构函数我们能够做例如以下改动

//析构函数
- (void)dealloc{
self.book = nil; //调用setter方法
[_book release];
NSLog(@"年龄为%d的学生被释放了", _age);
[super dealloc];
}

self.book = nil; 会调用setter方法。释放对象并将当前类Student的属性_book设为nil.

@property的參数

@property的參数格式: @property (參数1, 參数2,...) 类型 名字;

參数主要分为4类:

读写属性:readwrite / readonly (是否生成get和set方法)

setter处理: assign / retain / copy  (和内存管理相关)

原子性:atomic / nonatomic   (这两个和多线程相关)

set和get方法名称相关參数:setter(设置生成的set方法名称)/ getter(设置生成的get方法名称)

改变set和get名称,多是用于BOOL类型的变量

@property (nonatomic, assign, setter = abc:) int height;  设置set方法名称为 abc:

说明:

readonly代表仅仅生成getter方法,默认是readwrite

assing默认(set方法直接赋值),copy是setter方法release旧值,再copy新值

retain 要生成符合内存管理原则的set方法(应用于对象类型)(注意:在dealloc方法中释放属性对象)

atomic(默认),保证getter和setter的原子性。提供多线程安全訪问,nonatomic性能高。所以通常是选择nonatomic.

#import <Foundation/Foundation.h>

@class Book; //声明Book是一个类

@interface Student : NSObject
//assign參数代表set方法直接赋值(默认的)
//getter方法是指定getter方法的名字
@property (nonatomic, assign, getter=getStudentAge) int age;
//这里的retain代表:release旧值,retain新值
//(注意,基本数据类型不能写retain參数)
@property (nonatomic, retain) Book *book; - (void)setBook:(Book *)book; - (id)initStudent:(int)age; @end
#import "Student.h"
#import "Book.h" @implementation Student //构造函数
- (id)initStudent:(int)age {
if(self = [super init]) {
_age = age;
}
NSLog(@"年龄为%d的学生被创建了", _age);
return self;
} //析构函数
- (void)dealloc{
self.book = nil; //调用setter方法
[_book release];
NSLog(@"年龄为%d的学生被释放了", _age);
[super dealloc];
} @end

自己主动释放池

自己主动释放池是OC里面的一种内存自己主动回收机制,一般能够将一些暂时变量加入到自己主动释放池中。统一回收释放。当自己主动释放池销毁时。池里的全部对象都会调用一次release方法。OC对象仅仅须要发送一条autorelease消息。就会把这个对象加入到近期的自己主动释放池中(栈顶的释放池)。

autorelease实际上仅仅是把release的调用延迟了,对于每一次autorelease,系统仅仅是把该对象放入当前的autorelease pool中,当该pool被释放时,该pool中的全部对象会调用一次release方法。

#import "Student.h"
#import "Book.h" @implementation Student //创建静态方法构造对象
+ (id)student {
Student *stu = [[[Student alloc] init] autorelease];
return stu;
} //创建带參数的静态方法构造对象
+ (id)studentWithAge:(int)age {
Student *stu = [self student];
stu.age = age;
return stu;
} //构造函数
- (id)initStudent:(int)age {
if(self = [super init]) {
_age = age;
}
NSLog(@"年龄为%d的学生被创建了", _age);
return self;
} //析构函数
- (void)dealloc{
self.book = nil; //调用setter方法
[_book release];
NSLog(@"年龄为%d的学生被释放了", _age);
[super dealloc];
} @end
int main(int argc, const char * argv[]) {
//代表创建一个自己主动释放池
@autoreleasepool {
//第一种写法
Student *stu = [[[Student alloc] initStudent:21] autorelease];
Student *stu1 = [[[Student alloc] initStudent:21] autorelease]; } //当括号结束后,池子将被销毁
//假设自己主动释放池被销毁。池里面的全部对象都会调用release方法
@autoreleasepool {
//另外一种写法
Student *stu2 = [[Student alloc] initStudent:21]; [stu2 autorelease];
}
@autoreleasepool {
//第三种写法(推荐)
//不用手动释放
Student *stu3 = [Student student];
}
return 0;
}

注意:

1、假设某个对象调用了多次autorelease方法,则在自己主动释放池销毁的时候会调用多次release方法进行释放。

例如以下:

    @autoreleasepool {
Person *p = [[Person alloc] init]; [p autorelease]; [p autorelease];
}

p对象会被释放两次。

2、假设嵌套autoreleasepool。那么对象将在调用了autorelease(加入到池子)的每层自己主动释放池结束的时候调用一次autorelease,例如以下:

    Person *p = [[Person alloc] init];

    @autoreleasepool {

        @autoreleasepool {
[p autorelease];
} }

对象将在第7行被释放,而以下的情况会出现野指针异常

    Person *p = [[Person alloc] init];

    @autoreleasepool {
[p autorelease]; @autoreleasepool {
[p autorelease];
} }

Objective-C基础笔记(3)OC的内存管理的更多相关文章

  1. 12.Object-C--浅谈OC的内存管理机制

    昨天学习了OC的内存管理机制,今天想总结一下,所以接下来我要在这里bibi一下:OC的内存管理. 首先我要说的是,内存管理的作用范围. 内存管理的作用范围: 任何继承了NSObject的对象,对其他基 ...

  2. 黑马程序员——OC的内存管理学习小结

    内存管理在Objective-C中的重要性就像指针在C语言中的重要程序一样. 虽然作为一门高级语言,但OC却没有内存回收机制.这就需要开发者来对动态内存进行管理.OC中内存管理的范围是:任何继承了NS ...

  3. OC:内存管理、dealloc方法、copy知识点

    属性的声明:使⽤@property声明属性
 例如:@property NSString *name: 相当于@interface中声明了两个⽅法(setter.getter): 属性的实现:使⽤@s ...

  4. OC的内存管理机制

    总的来说OC有三种内存管理机制,下面将分别对这三种机制做简要的概述. 1.手动引用计数(Mannul Reference Counting-MRC) mannul:用手的,手工的. 引用计数:reta ...

  5. OC的内存管理(一)

    在OC中当一个APP使用的内存超过20M,则系统会向该APP发送 Memory Warning消息,收到此消息后,需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等,否则程序会 ...

  6. 《objective-c基础教程》学习笔记(十)—— 内存管理

    本篇博文,将给大家介绍下再Objective-C中如何使用内存管理.一个程序运行的时候,如果不及时的释放没有用的空间内存.那么,程序会越来越臃肿,内存占用量会不断升高.我们在使用的时候,就会感觉很卡, ...

  7. OC的内存管理

    摘自:http://blog.csdn.net/hahahacff/article/details/39839571 OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有 ...

  8. 「OC」内存管理

    一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空 ...

  9. OC的内存管理(二)ARC

    指针: 指向内存的地址指针变量 存放地址的变量指针变量值 变量中存放的值(地址值)指针变量指向的内存单元值 内存地址指向的值1):强指针:默认的情况下,所有的指针都是强指针,关键字strong ):弱 ...

随机推荐

  1. hdu2688 Rotate(树状数组)

    题目链接:pid=2688">点击打开链接 题意描写叙述:对一个长度为2<=n<=3000000的数组,求数组中有序对(i<j而且F[i]<F[j])的数量?其 ...

  2. 并行编程(1) - sum.msic.Unsafe 一

    相信看过java源代码的同学.对 sum.msic.Unsafe 这个类并不陌生,特别是在java.util.concurrent包有非常多的使用. sum.msic.Unsafe源代码:      ...

  3. 指针,c语言的灵魂

    指针是一个值为内存地址的变量. 变量是一块内存空间,指针是变量,是用来存储内存地址的变量. #include <stdio.h> #include <stdlib.h> int ...

  4. 参照实验室这边案例做一个简单的maven webapp项目

    流程 : 首先写出一个简单的前端页面. 之后写配置文件.dao.domain等等,注意这里可以使用generator进行自动配置 实验室这边配置文件如下: 其实主要的配置文件就分为6“个”. appl ...

  5. HD-ACM算法专攻系列(19)——Leftmost Digit

    问题描述: AC源码: 解题关键是,数据很大,不能强算,需要使用技巧,这里使用科学计算法,令N^N=a*10^n ,取对数后变为 N*log10(N)=log10(a)+n,令x = log10(a) ...

  6. 初探MVC路由

    文章目录: 1.认识理解URL,以及简单的路由 2.特性路由.传统路由.区域路由 3.路由生成URL&&绑定到操作&&路由约束 1.认识理解URL,以及简单的路由  默 ...

  7. 关于QueryRunner数据查询以及常用方法

    QueryRunner数据查询操作调用QueryRunner类方法query(Connection con,String sql,ResultSetHandler r, Object.params)R ...

  8. VB入门在线视频教程大全学习

    课程目录 9分钟47秒 课时1第一课:怎么编写程序 14分钟1秒 课时1第十七课第1节:文件读写的几种方式 14分钟14秒 课时2第二课:什么是变量和变量类型 19分钟24秒 课时3第三课:变量的声明 ...

  9. HTML大纲

  10. thinkphp5-----模板中函数的使用

    1.在模板中使用php函数 在thinkphp的html中,我们经常会遇到一些变量难以直接从php控制端直接处理,这些变量只有在模板中循环输出的时候处理比较合适,这个时候,我们就要在模板中使用函数 1 ...