Objective-C 【autorelease基本使用】
———————————————————————————————————————————
NSString中的内存管理问题
由于autoreleasepool的存在,对于内存管理就会很复杂,retainCount 不能作为调试内存时的依据。
所以一般来说NS开头的类(或者说系统自己内部提供的类)基本上不需要我们做太多的内存管理,因为我们很难检测出来。
比如:
NSString *str=[[NSString alloc]initWithString:@"123123"];
NSLog(@"str retainCount=%tu",[str retainCount]);
输出的结果是:str retainCount=18446744073709551615
这里的值不是乱码,而是很大,简单的release一下根本不会使这个值改变(一般一点不会改变),所以我们不要对这种系统中原有的类型进行内存操作。
if(retainCount>0)
{
[str release];
}
这样很容易死循环。
———————————————————————————————————————————
autorelease 基本使用
(1)自动释放池 及 autorelease介绍
自动释放池:
①在iOS程序运行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的
②当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中
(2)自动释放池的创建方式
iOS 5.0 以后
@autoreleasepool
{ //开始代表创建自动释放池
………
} //结束代表销毁自动释放池
(3)autorelease的原理
实际上autorelease只是把对release的调用延迟了,对于每一个autorelease,系统只是把该object放入了当前的autorelease pool中,当该pool释放时,该pool中所有的object会被一起调用release。
代码:
#import <Foundation/Foundation.h>
@interface Car : NSObject
-(void)run;
@end
@implementation Car
-(void)run
{
NSLog(@"Car run!");
}
- (void)dealloc
{
NSLog(@"Car dealloc!");
[super dealloc];
}
@end
int main(int argc, const char * argv[]) {
// 创建一个自动释放池
@autoreleasepool {
Car *car=[[[Car alloc]init]autorelease];//首先要用autorelease,那就一定得将ARC关掉
[car run];
[car run];
[car run];
// 单单是创建对象,如果调用autorelease,那么程序结束的时候会自动释放每一个对象
// 如果是在其中retain了对象,记住,如果retain就要release一下,否则是无法释放内存的。
// [car retain];
// [car release];
}//执行的此处的时候,会对释放池中的每一个对象进行一次release操作
return 0;
}
———————————————————————————————————————————
自动释放池的 使用误区/嵌套/注意事项
#import <Foundation/Foundation.h>
@interface Car : NSObject
-(void)run;
@end
@implementation Car
-(void)run
{
NSLog(@"Car run!");
}
- (void)dealloc
{
NSLog(@"Car dealloc!");
[super dealloc];
}
@end
void test1()
{
Car *car2=[[[Car alloc]init]autorelease];//此时car2不能释放,因为autorelease没有在autorelease的代码块中调用
Car *car3=[[Car alloc]init];
@autoreleasepool {//自动释放池代码块
// 误区①:并不是将对象放到自动释放池代码块内部它就能自动释放的,只有手动调用autorelease方法以后,才能把对象加入到自动释放池
// Car *car1=[[Car alloc]init];
// [car1 run];
// 上面的代码是无法释放car1的
// 误区②:如果调用了autorelease,但是这个调用的语句并没有放到自动释放池代码块中,那么也无法将对象加入到自动释放池
[car3 autorelease];//car3可以被释放
}
}
int main(int argc, const char * argv[]) {
// 自动释放池的嵌套
Car *car1=[[Car alloc]init];
[car1 run];
[car1 retain];//如果要在此处加上retain,让car1的retainCount变为2,那么就要在@autoreleasepool {//自动释放池1
@autoreleasepool {//自动释放池2
@autoreleasepool {//自动释放池3
[car1 autorelease];
}//显然在这里执行了 [p release]; 的操作
// [car1 autorelease];
// 但是有一点 [car1 autorelease]; 不可以过多执行,如果retainCount为0了还执行的话,那么就会出错了~
}
}
return 0;
}
自动释放池嵌套在内存中的实现看下图:
★注意:
①自动释放池不能放占用内存较大的对象,也不要将大量循环放到同一个@autorelease之间,这样会造成内存峰值的上升
②@autorelease {
//如果不写这里的自动释放池代码块,则在ARC机制下无法释放内存
}
所以必须加这句话,不要将编译器自动生成的这句话删掉
③[car1 autorelease]; 之后,就不要再 [car1 release]; 了,也不要 [car1 autorelease]; ,这样都是多余的,会报错,上面也提到了。所以说要么使用自动释放池,要么使用手动内存管理。
———————————————————————————————————————————
autorelease的应用场景——利用autorelease建立一个快速创建对象的方法
首先,快速创建实例对象的方法通常是一个类方法,以小写的类名命名。下面展示两种快速创建实例对象的方法,无参和有参。
声明:
+(instancetype)bigCar; //无参数的
实现:
+(instancetype)bigCar
{
return [[[self alloc]init]autorelease];
}
或者是
声明:
+(instancetype)bigCarWithSpeed:(int)speed; //含参数的
实现:
+(instancetype)bigCarWithSpeed:(int)speed
{
return [[[self alloc]initWithSpeed:speed]autorelease];
}
但是写成上面这样的有参数的快速创建实例对象的格式,需要重写父类的构造方法(自定义构造方法),如下:
-(instancetype)initWithSpeed:(int)speed
{
if(self=[super init])
{
_speed=speed;
}
return self; //提醒一下,return self ; 要写在if大括号的外面~
}
代码:
#import <Foundation/Foundation.h>
@interface Car : NSObject
-(void)run;
+(instancetype)car;
@end
@implementation Car
-(void)run
{
NSLog(@"Car run!");
}
- (void)dealloc
{
NSLog(@"Car dealloc!");
[super dealloc];
}
//方法①
//+(Car *)car
//{
// return [[[Car alloc]init]autorelease];
//}
//方法①是不可取的,因为如果有一个BigCar类继承Car类,我们在main中作了如下操作
//BigCar *bigcar1=[BigCar car];
//[bigcar1 run];
//显然我们方法①中是用Car开辟的内存空间,故创建出来的还是Car的实例对象。所以无法调用BigCar中的run方法,调用的还是Car的(父类的)
//方法②
//+(id)car
//{
// return [[[self alloc]init]autorelease];
//}
//方法②中,我们将调用创建内存空间和初始化的类设置为self,也就是当前类。将返回值类型设置为id类型,这样的话我们就可以利用父类的快速创建实例对象的方法去创建子类的实例对象了。但是还是有些不足,我们再看下面这个例子。
//NSString *str=[BigCar car]; 我们用BigCar类去快速创建了一个实例变量,返回值是BigCar类型的,但是我们是将返回值赋给了str,str明明是NSString类型的,自然会出错。但是!这里在编译的时候检测不出来,也没有警告,所以这里还是不合适,需要改进
//方法③
+(instancetype)car
{
return [[[self alloc]init]autorelease];//这里是self,也就是这里用的是当前类创建实例对象
}
//最后我们完善了最后的方法③,这个方法是将返回值类型设置为instancetype类型,这样相对于方法②而言优点就是能在编译的时候判断两边的类型是否一致,遇到上面的情况,就会在编译的时候发出警告了!
//所以,我们以后快速创建实例对象的时候要用方法③
@end
@interface BigCar : Car
@end
@implementation BigCar
-(void)run
{
NSLog(@"BigCar run!");
}
- (void)dealloc
{
NSLog(@"BigCar dealloc!");
[super dealloc];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 先将ARC关闭
// Car *car1=[[[Car alloc]init]autorelease];
// [car1 run];
// 我们要利用autorelease建立一个快速创建实例对象的方法,就是要代替上面 Car *car1=[[[Car alloc]init]autorelease]; 这句话
BigCar *bigcar1=[BigCar car];
[bigcar1 run];
}
return 0;
}
快速创建实例对象的方法(代码2——这部分对上面的代码做了优化,将 自定义构造方法 和 快速创建实例对象 的方法都做了传值处理,熟练书写的过程)
代码2:
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property NSString *name;
@property int age;
-(instancetype)initWithName:(NSString *)name andWithAge:(int)age;
+(instancetype)person:(int)age;
@end
@implementation Person
-(instancetype)initWithName:(NSString *)name andWithAge:(int)age;
{
if(self=[super init])
{
_name=name;
_age=age;
}
return self;
}
+(instancetype)person:(int)age
{
return [[self alloc]initWithName:@"wang" andWithAge:age];
//name 和 age 接收参数的不同点就是age是传进来的,是我们在main中赋值的,传进来的age直接赋给_age。而name是我们在 快速创建实例对象的方法 中进行赋值的,直接将赋好的 wang 传递给_name,所以说两个赋值的方式只是赋值的位置不同而已。
//不管哪种形式,我们都要知道,我们写的这个快速创建实例对象的方法在内部是调用自定义构造方法的!然后在自定义的构造方法中返回创建好的实例对象。
}
@end
@interface Student : Person
@end
@implementation Student
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p=[Person person:12];
NSLog(@"person.name=%@,person.age=%d",p.name,p.age);
Student *stu=[Student person:12];
NSLog(@"student.name=%@,p.age=%d",stu.name,stu.age);
}
return 0;
}
———————————————————————————————————————————
版权声明:本文为博主原创文章,未经博主允许不得转载。
Objective-C 【autorelease基本使用】的更多相关文章
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- Objective C中的ARC的修饰符的使用---- 学习笔记九
#import <Foundation/Foundation.h> @interface Test : NSObject /** * 默认的就是__strong,这里只是做示范,实际使用时 ...
- 理解autorelease
如果你能够真正的理解autorelease,那么你才是理解了Objective c的内存管理.Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是 ...
- Objective C ARC 使用及原理
手把手教你ARC ,里面介绍了ARC的一些特性, 还有将非ARC工程转换成ARC工程的方法 ARC 苹果官方文档 下面用我自己的话介绍一下ARC,并将看文档过程中的疑问和答案写下来.下面有些是翻译,但 ...
- iOS开发——项目实战总结&带你看看Objective-C的精髓
带你看看Objective-C的精髓 1:接口与实现 @interface...@end @implementation...@end @class 接口(头文件) 实现文件 向前引用 注:类别通过增 ...
- Objective C内存管理之理解autorelease------面试题
Objective C内存管理之理解autorelease Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的A ...
- 【转】对cocos2d 之autorelease\ratain\release的理解
原文链接:http://blog.sina.com.cn/s/blog_4057ab6201018y4y.html Objective C内存管理进阶(二):理解autorelease: http:/ ...
- iOS完全自学手册——[三]Objective-C语言速成,利用Objective-C创建自己的对象
1.前言 上一篇已经介绍了App Delegate.View Controller的基本概念,除此之外,分别利用storyboard和纯代码创建了第一个Xcode的工程,并对不同方式搭建项目进行了比较 ...
- 什么时候应该使用Autorelease Pool
csdn首发:http://blog.csdn.net/guijiewan/article/details/46470285 Objective c使用ARC之后,一般都不需要再手动调用retain, ...
- iOS开发核心语言Objective C —— 全部知识点总结
本分享是面向有意向从事iOS开发的伙伴及苹果产品的发烧友,亦或是已经从事了iOS的开发人员,想进一步提升者.假设您对iOS开发有极高的兴趣,能够与我一起探讨iOS开发.一起学习,共同进步.假设您是零基 ...
随机推荐
- LINUX CACHE IO THREAD
http://www.penglixun.com/tech/system/linux_cache_discovery.html http://my.oschina.net/HardySimpson/b ...
- SVM多分类
http://www.matlabsky.com/thread-9471-1-1.htmlSVM算法最初是为二值分类问题设计的,当处理多类问题时,就需要构造合适的多类分类器.目前,构造SVM多类分类器 ...
- 一款基于jQuery饼状图比例分布数据报表
今天给大家带来一款基于jQuery饼状图比例分布数据报表.这款报表插件适用浏览器:IE8.360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗.效果图如下: 在线预览 ...
- PHP经验——PHPDoc PHP注释的标准文档(翻译自Wiki)
文档注释,无非“//”和“/**/”两种 ,自己写代码,就那么点,适当写几句就好了:但是一个人总有融入团队的一天,团队的交流不是那几句注释和一张嘴能解决的,还需要通用的注释标准. PHPDoc是PHP ...
- uboot 网络不通问题解决一例1
平台:Hi3531 PHY:RTL8211 现象:在uboot中执行ping命令的时候,总是超时. 过程: 使用uboot自带的phy操作命令mii读出的数据全是0xff.这里要介绍一下uboot中的 ...
- Linux下的lds链接脚本基础
转载:http://soft.chinabyte.com/os/104/12255104.shtml 今天在看uboot引导Linux部分,发现要对链接脚本深入了解,才能知道各个目标文件的内存分布 ...
- webrtc学习(二): audio_device之opensles
audio_device是webrtc的音频设备模块. 封装了各个平台的音频设备相关的代码 audio device 在android下封装了两套音频代码. 1. 通过jni调用java的media ...
- BootStrap2学习日记18---提示消息
代码: <div class="alert alert-block" id="alert"> <a href="#" cl ...
- setsockopt
1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BOOL bReuseaddr=TRUE;setsockopt(s,SOL_SOCKET ,SO ...
- Git 暂存区
可以用 git log 查看提交日志(附加的 --stat 参数可以看到每次提交的文件变更统计). $ cd /path/to/my/workspace/demo $ git log --stat 如 ...