必威-必威-欢迎您

必威,必威官网企业自成立以来,以策略先行,经营致胜,管理为本的商,业推广理念,一步一个脚印发展成为同类企业中经营范围最广,在行业内颇具影响力的企业。

这篇纯粹是笔记,指向对象的指针也被回收

2019-09-16 00:01 来源:未知
set方法的内存管理
- setCar:car{ if(car!= _car) { // 对当前正在使用的车做一次release [_car release]; // 对新车做一次retain操作 _car=[car retain]; }}

「OC」内存管理,「oc」

注意事项:
  • 如果一个对象有一个strong类型的指针指向着,这个对象就不会被释放。如果一个指针指向超出了它的作用域,就会被指向nil。如果一个指针被指向nil,那么它原来指向的对象就被释放了。当一个视图控制器释放时,它内部的全局指针会被指向nil。
  • 局部变量:出了作用域,指针会被置为nil。
  • 方法内部创建对象,外部使用需要添加autorelease。
  • Xib连线的时候,用weak修饰。
  • 代理MRC使用assign修饰,ARC使用weak修饰。
  • block使用copy修饰。
  • block中为了避免循环引用(常见self持有的block)问题,使用__weak方式。
  • 声明属性时,不要以new开头。如果非要以new开头命名属性的名字,需要自己定制get方法名,如:
    @property(getter = theString) NSString *newString;
  • 如果要使用自动释放池,用@autoreleasepool{} 。
  • ARC只能管理Foundation框架的变量,如果程序中把Foundation中的变量强制换成COre Foundation中的变量需要交换管理权。
  • 在非ARC工程中采用ARC去编译某些类:-fobjc-arc。
  • 在ARC下的工程采用非ARC去编译某些类:-fno-fobjc-arc。

野指针错误:访问了一块坏的内存(已经被回收的,不可用的内存)。

(2)当自动释放池被销毁时,会对池子里的所有对象做一次release

所谓内存管理,就是对内存进行管理,涉及的操作有:

分配内存 :比如创建一个对象,会增加内存占用清除内存 :比如销毁一个对象,能减小内存占用

(二)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];

      }

    }

MRC内存管理测试:
Student类:
@interface Student : NSObject {  
    int age;  
}  
@property int age;  
@end 

@implementation Student  
@synthesize age;  
//重写dealloc方法,当引用计数器(auto reference count)为零的时候调用。  
- (void)dealloc {  
    NSLog(@"%@被销毁了",self);  
    [super dealloc]; 
}  
@end  

Controller类:
Student *stu = [[Student alloc]init];// alloc一次,引用计数器为1  
// Student *stu = [[[Studnet alloc]init] autorelease];// 这样写的话系统会在适当的地方对stu的内存进行自动回收,就不用自己写release回收了
// z代表无符号  
NSLog(@"count:%zi", [stu retainCount]);  
[stu retain];// 引用计数器变为2  
NSLog(@"count:%zi", [stu retainCount]);  
[stu release];// 引用计数器变为1  
NSLog(@"count:%zi", [stu retainCount]);          
[stu release];// release一次,引用计数器减1,变为0然后会调用dealloc方法

运行结果:
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] count:2
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] <Student: 0x100109a80>被销毁了

------随笔

(1)不需要再关心对象释放的时间

有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1.

需要注意的是: release并不代表销毁回收对象,仅仅是计数器-1。

一、基本原理

基本原则:

MRC:

  • 内存管理遵循“谁创建,谁释放,谁引用,谁管理”的机制,当通过alloc、new或者(mutable)copy来创建一个对象,必须调用release或autorelease(autorelease是延迟释放内存,不用你自己去手动释放,系统会知道在什么时候该去释放掉它。),当通过retain引用一个对象的时候,需要调用release。当对象引用计数为0时,系统将释放该对象,这是OC的手动管理内存机制。

ARC:

  • iOS 5.0之后引用自动管理机制——自动引用计数,管理机制与手动机制一样,只是不再需要调用retain、release、autorelease;它编译时的特性,当你使用ARC时,在适当位置插入release和autorelease;它引用strong和weak关键字,strong修饰的指针变量指向对象时,当指针指向新值或者指针不复存在,相关联的对象就会自动释放,而weak修饰的指针变量指向对象,当对象的拥有者指向新值或者不存在时weak修饰的指针会自动置为nil。
  • 如果使用alloc、copy(mutableCopy)或者retian一个对象时,你就有义务,向它发送一条release或者autorelease消息。其他方法创建的对象,不需要由你来管理内存。
  • 向一个对象发送一条autorelease消息,这个对象并不会立即销毁,而是将这个对象放入了自动释放池,待池子释放时,它会向池中每一个对象发送一条release消息,以此来释放对象。
  • 向一个对象发送release消息,并不意味着这个对象被销毁了,而是当这个对象的引用计数为0时,系统才会调用dealloc方法,释放该对象和对象本身它所拥有的实例。

当你不想使用这个对象时,应该让对象的引用计数器-1;

@autoreleasepool

引用计数器的常见操作

给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)给对象发送一条release消息,可以使引用计数器值-1给对象发送retainCount消息,可以获得当前的引用计数器值

(一)原则

  只要还有人在使用某个对象,那么这个对象就不会被回收;

  只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;

  当你不想使用这个对象时,应该让对象的引用计数器-1;

原理:
  • 每个对象内部都保存了一个与之相关联的整数,称为引用计数器(auto reference count)
  • 每当使用alloc、new或者copy创建一个对象时,对象的引用计数器被设置为1
  • 给对象发送一条retain消息(即调用retain方法),可以使引用计数器值+1
  • 给对象发送一条release消息,可以使引用计数器值-1
  • 当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收,OC也会自动向对象发送一条dealloc消息。一般会重写dealloc方法,在这里释放相关资源。一定不要直接调用dealloc方法。
  • 可以给对象发送retainCount消息获得当前的引用计数器值。

当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就像是对象的“临终遗言”。一旦重写了dealloc方法就必须调用[super dealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。

[_car release];//若没有旧对象,则没有影响

内存管理

堆:需要手动释放。栈:系统自动管理。

三、内存管理原则

图片 1

 

内存管理的管理范围

任何继承了NSObject的对象对其他非对象类型无效(int、char、float、double、struct、enum等)

(三)谁retain,谁release

  只要你调用了retain,无论这个对象时如何生成的,你都要调用release

(四)错误写法

Assign:适用于非OC对象类型(基础类型)

Xcode开启僵尸对象的监控

图片 2截图1.png

(三)dealloc方法的代码规范

  (1)一定要[super dealloc],而且要放到最后

  (2)对self(当前)所拥有的的其他对象做一次release操作

    -(void)dealloc

    {

      [_car release];

      [super dealloc];

    }

(一)ARC的判断准则:

只要没有强指针指向对象,对象就会被释放。

nil Nil NULL NSNull 之间的区别

nil 是对objective c id 对象赋空值Nil: 表示对类进行赋空值NULL: 用于对非对象指针赋空值,比如C指针NSNull 对于像NSArray这样的类型,nil或NULL不能做为加到其中的Object,如果定义了一个NSArray,为其分配了内存,又想设置其中的内容为空,则可以用[NSNULL null】返回的对象来初始化NSArray中的内容

(3)多线程管理(苹果在一定程度上屏蔽了多线程操作)

  nonatomic:高性能,一般使用这个

  atomic:低性能

_ _weak Person *p;

(二)谁创建,谁release

这篇纯粹是笔记。

(五)自动释放池

  (1)在ios程序运行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的。

  (2)当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中

(1)@class的作用:声明一个类,告诉编译器某个名称是一个类

-(void)dealloc

delloc方法注意细节

当一个对象的引用计数器值为0时这个对象即将被销毁,其占用的内存被系统回收系统会自动给对象发送一条dealloc消息(因此,从dealloc方法有没有被调用,就可以判断出对象是否被销毁)dealloc方法的重写一般会重写dealloc方法,在这里释放相关资源,dealloc就是对象的遗言一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用使用注意不能直接调用dealloc方法一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃

(二)好处

  (1)不需要再关心对象释放的时间

  (2)不需要再关心什么时候调用release

(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法

(1)内存管理相关参数

MRC循环retian

循环retain的场景比如A对象retain了B对象,B对象retain了A对象

循环retain的弊端这样会导致A对象和B对象永远无法释放

循环retain的解决方案当两端互相引用时,应该一端用retain、一端用assign

同理,在ARC下,如果两个对象相互引用,并且用strong修饰,那两个对象都无法释放。解决方案:其中一个对象用weak修饰,一个用strong修饰。那就可以让两个对象都可以释放。

七、autorelease

当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。

[super dealloc];

苹果官方规定的内存管理原则

谁创建谁release:如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease。谁retain谁release:只要你调用了retain,就必须调用一次release。总结一下就是有加就有减曾经让对象的计数器+1,就必须在最后让对象计数器-1

(二)指针分类:

  (1)强指针:默认的情况下,所有的指针都是强指针,关键字strong

  (2)弱指针:_ _weak关键字修饰的指针

  声明一个弱指针如下:

    _ _weak Person *p;

  ARC中,只要弱指针指向的对象不在了,就直接把弱指针做清空操作。

  _ _weak Person *p=[[Person alloc]  init];//不合理,对象一创建出来就被释放掉,对象释放掉后,ARC把指针自动清零。

  ARC中在property处不再使用retain,而是使用strong,在dealloc中不需要再[super dealloc]。

  @property(nonatomic,strong)Dog *dog;// 意味着生成的成员变量_dog是一个强指针,相当于以前的retain。

  如果换成是弱指针,则换成weak,不需要加_ _。 

空指针:没有指向任何东西的指针(存储的东西是0,null,nil),给空指针发送消息不会报错

 

@property参数修饰
控制set方法的内存管理

retain:release旧值,retain新值assign:直接赋值,不做任何内存管理(默认,用于非OC对象类型)copy :release旧值,copy新值(一般用于NSString*,block)

控制需不需生成set方法

readwrite:同时生成set方法和get方法readonly :只会生成get方法

多线程管理

atomic :性能低nonatomic:性能高

控制set方法和get方法的名称

setter:设置set方法的名称,一定有个冒号:getter:设置get方法的名称

强引用strong与弱引用weak的广义区别:

强引用strong也就是我们通常所讲的引用,其存亡直接决定了所指对象的存亡。如果不存在指向一个对象的引用,并且此对象不再显示列表中,则此对象会被从内存中释放。弱引用weak除了不决定对象的存亡外,其他与强引用相同。即使一个对象被持有无数个若引用,只要没有强引用指向他,那麽其还是会被清除。没办法,还是 “强哥” 有面子。

简单讲strong等同retainARC时候用strong,MRC时候用returnweak比assign多了一个功能,当对象消失后自动把指针变成nil,好处不言而喻。所以,我觉得在delegate时候用weak会好过assign。

至于block的话,就要结合考虑。(weak,copy,assign)这三个结合情况,在下一篇的介绍。

__weak ,__strong ,__unsafe_unretained,** __autoreleasing**用来修饰变量. 是缺省的关键词。 声明了一个可以自动 nil 化的弱引用。(__unsafe_unretained) 声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野指针了。(__autoreleasing) 用来修饰一个函数的参数,这个参数会在函数返回的时候被自动释放。

六、内存管理中的循环引用问题以及解决

  案例:每个人有一张身份证,每张身份证对应一个人,不能使用#import的方式相互包含,这就形成了循环引用。

  新的关键字:@class 类名;——解决循环引用问题,提高性能

  @class仅仅告诉编译器,在进行编译的时候把后面的名字作为一个类来处理。

    (1)@class的作用:声明一个类,告诉编译器某个名称是一个类

    (2)开发中引用一个类的规范

      1)在.h文件中使用@class来声明类

      2)在.m文件中真正要使用到的时候,使用#import来包含类中的所有东西

    (3)两端循环引用的解决方法

  一端使用retain,一端使用assign(使用assign的在dealloc中也不用再release)

(三)谁retain,谁release

(四)错误写法

空指针野指针

僵尸对象已经被销毁的对象

野指针指向僵尸对象的指针给野指针发消息会报EXC_BAD_ACCESS错误

空指针没有指向存储空间的指针(里面存的是nil,也就是0)给空指针发消息是没有任何反应的。为了避免野指针错误的常见办法在对象被销毁之后,将指向对象的指针变为空指针

(二)对象的基本结构

  每个OC对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象。对象刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁。

  在每个OC对象内部,都专门有4个字节的存储空间来存储引用计数器。

三、内存管理原则

(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法

dealloc方法内存管理
- dealloc{ //当人不在了,代表不用车了 // 对车做一次release操作 [_car release]; //调用dealloc方法时候一定要调用父类的dealloc的方法 [super dealloc];}

(三)使用注意

  (1)占用内存较大的对象,不要随便使用autorelease,应该使用release来精确控制

  (2)占用内存较小的对象使用autorelease,没有太大的影响

(1)会将对象放到一个自动释放池中

{

@class和#import的区别

作用上的区别#import会包含引用类的所有信息, 包括引用类的变量和方法@class仅仅是告诉编译器有这么一个类,具体这个类里有什么信息, 完全不知道。

效率上的区别如果有上百个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,编译效率非常低相对来讲,使用@class方式就不会出现这种问题了

(四)错误写法

  (1)连续调用多次autorelease,释放池销毁时执行两次release(-1吗?)

  (2)Alloc之后调用了autorelease,之后又调用了release。

{

2)在.m文件中真正要使用到的时候,使用#import来包含类中的所有东西

只有OC对象才需要进行内存管理的本质原因

OC对象存放于堆里面OC基础类型一般放在栈里面(栈内存会被系统自动回收)

(一)为什么要进行内存管理。

  由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等。

  管理范围:任何继承NSObject的对象,对其他的基本数据类型无效。

  本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。

(二)Set方法的代码规范

Atomic:低性能

四、内存管理代码规范

Strong:相当于原来的retain(适用于OC对象类型),成员变量是强指针

(1)连续调用多次autorelease,释放池销毁时执行两次release(-1吗?)

(六)自动释放池的创建方式

  (1)ios 5.0以前的创建方式

    NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];

    ......

    [pool  release];//[pool drain];用于mac 

  (2)Ios5.0以后

    @autoreleasepool

    { // 开始代表创建自动释放池

    ·······

    } // 结束代表销毁自动释放池

(2)当自动释放池被销毁时,会对池子里的所有对象做一次release

{//开始代表创建自动释放池

(一)基本用法

  (1)会将对象放到一个自动释放池中

  (2)当自动释放池被销毁时,会对池子里的所有对象做一次release

  (3)会返回对象本身

  (4)调用完autorelease方法后,对象的计数器不受影响(销毁时影响)

BOOL b=p.isRich;//调用

案例:每个人有一张身份证,每张身份证对应一个人,不能使用#import的方式相互包含,这就形成了循环引用。

(2)是否要生成set方法(若为只读属性,则不生成)

  readonly:只读,只会生成getter的声明和实现

  readwrite:默认的,同时生成setter和getter的声明和实现

(4)调用完autorelease方法后,对象的计数器不受影响(销毁时影响)

Release消息:使计数器-1(并不代表释放对象)

五、@property的参数

案例:每个人有一张身份证,每张身份证对应一个人,不能使用#import的方式相互包含,这就形成了循环引用。

1)在.h文件中使用@class来声明类

(三)ARC的特点总结:

  (1)不允许调用release,retain,retainCount 

  (2)不允许重写dealloc,但是不允许调用[super dealloc]

  (3)@property的参数:

  strong:相当于原来的retain(适用于OC对象类型),成员变量是强指针

  weak:相当于原来的assign,(适用于oc对象类型),成员变量是弱指针

  assign:适用于非OC对象类型(基础类型)

(2)占用内存较小的对象使用autorelease,没有太大的影响

 

(一)ARC的判断准则:

  只要没有强指针指向对象,对象就会被释放。

管理范围:任何继承NSObject的对象,对其他的基本数据类型无效。

(2)不需要再关心什么时候调用release

(1)内存管理相关参数

  retain:对对象release旧值,retain新值(适用于OC对象类型)

  assign:直接赋值(默认,适用于非oc对象类型)

  copy:release旧值,copy新值

Retain消息:使计数器+1,改方法返回对象本身

修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用在布尔类型中的getter。

(四)总结

  有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1.

(3)两端循环引用的解决方法

(五)自动释放池

(二)谁创建,谁release

  (1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法

  (2)不是你创建的就不用你去负责

(六)自动释放池的创建方式

(七)Autorelease注意

(五) 对象的销毁

  当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。

  当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就像是对象的“临终遗言”。一旦重写了dealloc方法就必须调用[super dealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。

  一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。

一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。

让程序兼容ARC和非ARC部分。转变为非ARC  -fno-objc-arc  转变为ARC的, -f-objc-arc 。

(一)只要调用了alloc,就必须有release(autorelease)

(七)Autorelease注意

retainCount消息:获得对象当前的引用计数器值

(四)操作

  给对象发送消息,进行相应的计数器操作。

  retain消息:使计数器+1,改方法返回对象本身

  release消息:使计数器-1(并不代表释放对象)

  retainCount消息:获得对象当前的引用计数器值

-(void)dealloc

(1)一定要[super dealloc],而且要放到最后

八、ARC内存管理机制

声明一个弱指针如下:

[pool  release];//[pool drain];用于mac 

(四)补充

  让程序兼容ARC和非ARC部分。转变为非ARC  -fno-objc-arc  转变为ARC的, -f-objc-arc 。

  ARC也需要考虑循环引用问题:一端使用retain,另一端使用assign。

  图片 3

  提示:字符串是特殊的对象,但不需要使用release手动释放,这种字符串对象默认就是autorelease的,不用额外的去管内存。

一、基本原理 (一)为什么要进行内存管理。 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的...

只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;

(3)多线程管理(苹果在一定程度上屏蔽了多线程操作)

(七)autorelease注意

  (1)系统自带的方法中,如果不包含alloc new copy等,则这些方法返回的对象都是autorelease的,如[NSDate  date];

  (2)开发中经常会写一些类方法来快速创建一个autorelease对象,创建对象时不要直接使用类名,而是使用self

(2)弱指针:_ _weak关键字修饰的指针

(3)两端循环引用的解决方法

TAG标签:
版权声明:本文由必威发布于必威-编程,转载请注明出处:这篇纯粹是笔记,指向对象的指针也被回收