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开发.一起学习,共同进步.假设您是零基 ...
随机推荐
- [程序猿入行必备]CSS样式之优先级
专业玩家请移步:http://www.w3.org/TR/CSS2/cascade.html 使用CSS控制页面样式时,常常出现设定的样式被"覆盖",不能生效的情况. 浏览器是根据 ...
- 一步步学Mybatis-告别繁琐的配置之Mybatis配置文件生成工具 (7)
今年是2013年的杀青之日,前几天由于比较忙,没有及时更新本篇的最后一篇东西,前六篇中我们主要都是采用手动配置相关的Mybatis映射文件与相应的接口类与实体类.当然如果在真正的使用过程中,由于业务的 ...
- JavaScript模块化开发一瞥
对于那些正在构建大型应用程序,而对JavaScript不甚了解的开发者而言,他们最初必须要面对的挑战之一就是如何着手组织代码.起初只要在标记之间嵌入几百行代码就能跑起来,不过很快代码就会变得一塌糊涂… ...
- POJ 3624 Charm Bracelet
DP 一直是心中痛,不多说了,这个暑假就坑在这上了. 这暑假第一道DP题,01背包问题. 题意是说物品有 重量和价值 ,但你能承受的重量有限,问你能带的最大价值. 这题数组开大点,尽管不知道有啥坑点, ...
- 使用phonegap + appframework2.0框架
1.页面切换动画结束时卡(禁用动画) 2.搜索或导航标签需要固定(标签选择器动态修改高度) 3.pancel容器默认生成的时候内容不放 通过动态的的$("").empty().ht ...
- Jquery实现页面上所有的checkbox只能选中一个
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...
- Linux下的线程
一.线程的优点 与传统进程相比,用线程来实现相同的功能有如下优点: (1)系统资源消耗低. (2)速度快. (3)线程间的数据共享比进程间容易的多. 二.多线程编程简单实例 #include < ...
- Quartz.Net实现定时任务调度
Quartz.Net介绍: Quartz一个开源的作业调度框架,OpenSymphony的开源项目.Quartz.Net 是Quartz的C#移植版本. 它一些很好的特性: 1:支持集群,作业分组,作 ...
- 一款基于jQuery轮播切换焦点图,可播放多张图片
今天给大家分享一款基于jQuery轮播切换焦点图,可播放多张图片,在这个组件中,你可以任意指定8张图片,然后插件就会帮你自动生成缩略图,并且自动开始切换播放图片.当然,你也可以手动切换图片,只要点击缩 ...
- EF——一对一、一对多、多对多关系的配置和级联删除 04(转)
EF里一对一.一对多.多对多关系的配置和级联删除 本章节开始了解EF的各种关系.如果你对EF里实体间的各种关系还不是很熟悉,可以看看我的思路,能帮你更快的理解. I.实体间一对一的关系 添加一个P ...