———————————————————————————————————————————

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基本使用】的更多相关文章

  1. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  2. Objective C中的ARC的修饰符的使用---- 学习笔记九

    #import <Foundation/Foundation.h> @interface Test : NSObject /** * 默认的就是__strong,这里只是做示范,实际使用时 ...

  3. 理解autorelease

    如果你能够真正的理解autorelease,那么你才是理解了Objective c的内存管理.Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是 ...

  4. Objective C ARC 使用及原理

    手把手教你ARC ,里面介绍了ARC的一些特性, 还有将非ARC工程转换成ARC工程的方法 ARC 苹果官方文档 下面用我自己的话介绍一下ARC,并将看文档过程中的疑问和答案写下来.下面有些是翻译,但 ...

  5. iOS开发——项目实战总结&带你看看Objective-C的精髓

    带你看看Objective-C的精髓 1:接口与实现 @interface...@end @implementation...@end @class 接口(头文件) 实现文件 向前引用 注:类别通过增 ...

  6. Objective C内存管理之理解autorelease------面试题

    Objective C内存管理之理解autorelease   Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的A ...

  7. 【转】对cocos2d 之autorelease\ratain\release的理解

    原文链接:http://blog.sina.com.cn/s/blog_4057ab6201018y4y.html Objective C内存管理进阶(二):理解autorelease: http:/ ...

  8. iOS完全自学手册——[三]Objective-C语言速成,利用Objective-C创建自己的对象

    1.前言 上一篇已经介绍了App Delegate.View Controller的基本概念,除此之外,分别利用storyboard和纯代码创建了第一个Xcode的工程,并对不同方式搭建项目进行了比较 ...

  9. 什么时候应该使用Autorelease Pool

    csdn首发:http://blog.csdn.net/guijiewan/article/details/46470285 Objective c使用ARC之后,一般都不需要再手动调用retain, ...

  10. iOS开发核心语言Objective C —— 全部知识点总结

    本分享是面向有意向从事iOS开发的伙伴及苹果产品的发烧友,亦或是已经从事了iOS的开发人员,想进一步提升者.假设您对iOS开发有极高的兴趣,能够与我一起探讨iOS开发.一起学习,共同进步.假设您是零基 ...

随机推荐

  1. hdu 4597 Play Game 区间dp

    Play Game Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=459 ...

  2. 【JavaScript】JavaScript回调函数

    什么是Javascript 回调函数? 函数和其他数据一样可以被赋值,删除,拷贝等,所以也可以把函数作为参数传入到另一个函数中. 这个函数就是所谓的回调函数   举例: //不带参数的case fun ...

  3. mybatis 报错:Caused by: java.lang.NumberFormatException: For input string

    mybatis的if标签之前总是使用是否为空,今天要用到字符串比较的时候遇到了困难,倒腾半天,才在一个论坛上找到解决方法.笔记一下,如下: 转自:https://code.google.com/p/m ...

  4. iOS 原生地图(MapKit、MKMapView)轨迹渐变

    WechatIMG2.png 项目已接入高德地图,并且大部分功能已经实现好,但BOSS觉得iOS自带的地图效果更好...本着面向老板编程的思想,换之.还好,高德地图是在MapKit上封装的,大部分ap ...

  5. mysql 数据库性能追踪与分析

    http://bbs.linuxtone.org/thread-20601-1-1.html

  6. Android实现数据存储技术

    转载:Android实现数据存储技术 本文介绍Android中的5种数据存储方式. 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用Shar ...

  7. Java再学习——CopyOnWrite容器

    一,定义 CopyOnWrite容器即写时复制的容器.通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完 ...

  8. 完美的.net泛型也有特定的性能黑点?追根问底并且改善这个性能问题

    完美的.net真泛型真的完美吗 码C#多年,不求甚解觉得泛型就是传说中那么完美,性能也是超级好,不错,在绝大部分场景下泛型表现简直可以用完美来形容,不过随着前一阵重做IOC时,才发现与自己预想中不一样 ...

  9. 1.7.4 Query Syntax and Parsing

    1. 查询语法和解析 这部分主要说明了如何指定被使用的查询解析器.同样描述了主查询解析器的支持的语法和功能.同时还描述了在特定环境下使用的其他查询解析器.这里有一些普通查询解析器都能使用的参数,将会在 ...

  10. java 输入输出 函数对象构造

    /*********************输入输出*******************/   //输入字符串 不包括最后的换行符'\n'     import java.io.BufferedRe ...