黑马程序员——内存管理
来源:互联网 发布:软件性能指标有哪些 编辑:程序博客网 时间:2024/05/17 17:56
终于将最难的内存管理看完了,真心觉得内存管理学起来比较抽象,其实内存管理说难也不是很难,只有一个retain和release,只要能够正确的判断什么时候应该retain,什么时候应该release那么就说明已经掌握内存管理的机制了。但是这也是最难的就是如何判断对象什么时候应该release什么时候应该retain。
MJ老师说的一般看见alloc就必须在后面加上一个release,而且操作都要写在relese前面,防止一个很神奇的错误,就是野指针错误。
说到这里又需要讲一下什么是野指针错误。其实就是一个指针指向了一个被释放的回收的对象。那个对象被称为僵尸对象,而且僵尸对象一旦称为僵尸之后就不能再复活了。
不能说你先relese将对象回收完后对象已经变为僵尸对象了你再一个retain对象又可以重新复活,这明显是不行的。
还有每个对象里面都有一个计数器,当计数器为0的时候对象就会被回收,而且计数器是用4个字节来存放的。
方法的基本使用
retain:计数器+1,会返回对象本身
release:计数器-1,没有返回值
retainCount:获取当前的计数器
dealloc
当一个对象要被回收的时候,就会调用
一定要调用[super dealloc],这句调用要放在最后面
概念
僵尸对象 :所占用内存已经被回收的对象,僵尸对象不能再使用
野指针 :指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
#import <Foundation/Foundation.h>#import "Person.h"int main(){ // 1 Person *p = [[Person alloc] init]; //NSUInteger c = [p retainCount]; //NSLog(@"计数器:%ld", c); // 2 retain方法返回的是对象本身 [p retain]; // 1 [p release]; // 0 野指针:指向僵尸对象(不可用内存)的指针 [p release]; [p retain]; // -[Person setAge:]: message sent to deallocated instance 0x100109a10 // 给已经释放的对象发送了一条-setAge:消息: p.age = 10; //[p setAge:10]; // 指针p变成空指针 //p = nil; // EXC_BAD_ACCESS : 访问了一块坏的内存(已经被回收、已经不可用的内存 // 野指针错误 // OC不存在空指针错误,给空指针发送消息,不报错 [p release]; [p release]; [p release]; [p release]; [nil release]; return 0;}
当出现一个对象需要使用另外一个对象的时候,那么就要在这个对象中重写他的delloc方法。
因为当你自己这个对象被销毁回收之后,你使用或者调用的对象如果没被释放那么就会出现野指针错误,因此在delloc方法中就要将调用的对象release下才行
你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)
你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
谁retain,谁release
谁alloc,谁release
还有在调用对象的set方法的时候当传入的参数是一个类的时候就需要将当期使用的类release然后将传入的类retain,因为retain方法功能是将计数器加一并且还有一个返回值就是放回对象本身,所以可以用当前对象来接受
/*内存管理代码规范: 1.只要调用了alloc,必须有release(autorelease) 对象不是通过alloc产生的,就不需要release*/ //2.set方法的代码规范 //1> 基本数据类型:直接复制 - (void)setAge:(int)age { _age = age; } //2> OC对象类型 - (void)setCar:(Car *)car { // 1.先判断是不是新传进来对象 if ( car != _car ) { // 2.对旧对象做一次release [_car release]; // 3.对新对象做一次retain _car = [car retain]; } }
//3.dealloc方法的代码规范 //1> 一定要[super dealloc],而且放到最后面 //2> 对self(当前)所拥有的其他对象做一次release - (void)dealloc { [_car release]; [super dealloc]; }
记得之前在讲set,get方法的时候,讲了一个关键字@property 数据类型 类型名
已这种方式来写的xcode的就会自动为我们生成一个set和get方法
现在要遵循oc的内存管理机制,每次在使用alloc的时候都需要release这样写就很麻烦。
所以我们还是可以用@property这个关键字来对变量名进行声明,但是需要在@property后面加上两个参数 (nonatomic,retain)起中nonatomic是起到一个优化的作用mj老师说的必须加,然后retain参数就是实现一个生成的set方法里面,release旧值,retain新值。
但是在implementation中还是需要重写delloc方法,用来release调用过的对象
Person.h
#import <Foundation/Foundation.h>#import "Book.h"@interface Person : NSObject@property int age;// retain : 生成的set方法里面,release旧值,retain新值@property (nonatomic,retain) Book *book;@property (nonatomic,retain) NSString *name;@end
Person.m
#import "Person.h"@implementation Person- (void)dealloc{ [_book release]; [_name release]; [super dealloc];}@end
set方法内存管理相关的参数
retain : release旧值,retain新值(适用于OC对象类型)
assign : 直接赋值(默认,适用于非OC对象类型)
copy : release旧值,copy新值
是否要生成set方法
readwrite :同时生成setter和getter的声明、实现(默认)
readonly :只会生成getter的声明、实现
多线程管理
nonatomic :性能高 (一般就用这个)
atomic :性能低(默认)
setter和getter方法的名称
setter :决定了set方法的名称,一定要有个冒号 :
getter :决定了get方法的名称(一般用在BOOL类型)
循环引用
循环引用就是两个对象相互调用
such as:学生有一个学号,学号也对应一个学生。那么在对象的相互调用的过程中,如果在声明变量时还是用@property(nonatomic,retain)的话,相互调用那么内存永远不会被释放。
那么解决这个循环引用的方法就是一段用retain一段用assign。
@class的作用:仅仅告诉编译器,某个名称是一个类
@class Person; //仅仅告诉编译器,Person是一个类
开发中引用一个类的规范
在.h文件中用@class来声明类
在.m文件中用#import来包含类的所有东西
两端循环引用解决方案
一端用retain
一端用assign
#import <Foundation/Foundation.h>#import "Card.h"#import "Person.h"int main(){ // p - 1 Person *p = [[Person alloc] init]; // c - 1 Card *c = [[Card alloc] init]; // c - 2 p.card = c; // p - 1 c.person = p; // c - 1 [c release]; // p - 0 c - 0 [p release]; return 0;}
Person.h
#import <Foundation/Foundation.h>#import "Card.h"// @class仅仅是告诉编译器,Card是一个类//@class Card;@interface Person : NSObject@property (nonatomic, retain) Card *card;@end
Person.m
#import "Person.h"#import "Card.h"@implementation Person- (void)dealloc{ NSLog(@"Person被销毁了"); [_card release]; [super dealloc];}@end
card.h
#import <Foundation/Foundation.h>@class Person;@interface Card : NSObject@property (nonatomic, assign) Person *person;@end
最后一个讲的时autorelease
光理解这个单词就能知道这个关键字大概有什么用 自动释放
autorelease其实就是一个类,在IOS 5.0前就是调用的NSAutoreleasePool这个类方法来创建autorelease自动释放池
在IOS 5.0以后就直接使用@autoreleasepool{}中的类需要利用autorelease的就将对象写在里面,在init之后在调用autorelease方法就行了。这样写了之后我们就不用在手动释放内存了,不用在不停的写release retain之类的,大大增加了程序员编写是的效率。
#import <Foundation/Foundation.h>#import "Person.h"int main(){ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Person *pp = [[[Person alloc] init] autorelease]; [pool release]; // [pool drain]; @autoreleasepool { // 1 Person *p = [[[[Person alloc] init] autorelease] autorelease]; // 0 // [p release]; } return 0;}void test(){ @autoreleasepool {// { 开始代表创建了释放池 // autorelease方法会返回对象本身 // 调用完autorelease方法后,对象的计数器不变 // autorelease会将对象放到一个自动释放池中 // 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作 Person *p = [[[Person alloc] init] autorelease]; p.age = 10; @autoreleasepool { // 1 Person *p2 = [[[Person alloc] init] autorelease]; p2.age = 10; } Person *p3 = [[[Person alloc] init] autorelease]; } // } 结束代表销毁释放池}
最后就是oc历史性的功能ARC机制。那么后面再说。。---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
- 黑马程序员——内存管理
- 黑马程序员——内存管理
- 黑马程序员——OC---内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——内存管理
- 黑马程序员——内存管理
- 黑马程序员——【OC】内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——[OC]内存管理
- 黑马程序员——内存管理
- 黑马程序员 — OC(内存管理)
- 黑马程序员—OC内存管理
- 黑马程序员—Objective-C内存管理
- 计算机学院研发------考核之界面
- (CronJob)命令行直接调用CodeIgniter中/controller/action
- 无向图的割顶与桥
- Mac下套件管理器——Homebrew
- 期末前的彷徨
- 黑马程序员——内存管理
- [Leetcode]Gray_code
- serialVersionUID的作用
- hdu3715 二分+2sat+建图
- tomcat直接输入Ip和端口号就可以主动加载一个jsp页面!
- Valid Palindrome
- getopt和getopt_long函数
- UILable的属性介绍
- AMBA、AHB、APB、ASB总线简介