我们为什么须要内存管理?当使用内存达到40M和45M时候会发出警告,假设不处理,占用内存达到120M时直接强制关闭程序。

所以出现闪退除了是程序出现逻辑错误,还有可能是内存使用过大。

(1)创建一个对象的过程:先分配内存空间存储对象;初始化成员变量;返回对象的指针。

(2)对象在创建时,内部会自己主动创建一个引用计数器retainCount,当retainCount=0时,系统会回收当前对象,retainCount是唯一推断标记。release会-1。retain会+1,retain后返回的是自己self指针。

(3)将ARC关闭调成手动内存管理模式。

(4)内存配对原则:仅仅要有new、alloc或retain,都须要配对一个release或autorelease。

在main.m中,须要把@autorelease pool{}去除。全然靠手动管理:

#import <Foundation/Foundation.h>
#import "Person.h" int main(int argc, const char * argv[]) { //alloc时retainCount=1
Person *p1=[[Person alloc]init];
NSLog(@"%lu",p1.retainCount); //引用计数=2
[p1 retain];
NSLog(@"%lu",p1.retainCount); //引用计数=1
[p1 release];
NSLog(@"%lu",p1.retainCount); //引用计数=0
[p1 release];
//怎么验证此时对象已被销毁呢?每一个对象被销毁时会调用dealloc方法,我们重写dealloc,让它输出一些东西。证明被调用了就可以
//重写是在这个对象所属类的.m文件里,即本例的Person.m中 return 0;
}

在Person.m中:

#import "Person.h"

@implementation Person

-(void)dealloc{

    //在对象被销毁之前,先用下面语句释放父类中得相关对象
[super dealloc];
NSLog(@"i am dealloc");
} @end

(5)一个对象被回收后。这个对象被称之为僵尸对象,由于Xcode不会时时检查僵尸对象,所以在CMD+R执行时,訪问已经被回收的对象有时会报错有时不报错。

假设想Xcode时时检查。下面设置。默认是不时时检查。是为了提高编码效率。

但建议关闭。由于当类比較多项目大时非常耗内存。

(6)手动内存管理研究的两个问题就是:野指针和内存泄露。当对象对回收后,该指针变量没有被设置为nil时,这个&#28;指针就是野指针,会导致程序出现闪退。所以我们一般在release后把这个指针变量设置为nil。虽然兴许还用到p1,可是p1是nil。向其发送不论什么消息都没回应也没影响,不会出现闪退。

(7)内存泄露:第一种情况是,不再被使用的对象没有回收一直存在内存中。另外一种情况是,不小心先把指针变量设置为nil。然后再[p1 release];已经无效了,此时由于retainCount是唯一标记,虽然没有指针指向这个对象,但对象依旧存在在内存中。

#import <Foundation/Foundation.h>
#import "Person.h" int main(int argc, const char * argv[]) { //alloc时retainCount=1
Person *p1=[[Person alloc]init];
NSLog(@"%lu",p1.retainCount); //引用计数=2
[p1 retain];
NSLog(@"%lu",p1.retainCount); //引用计数=1
[p1 release];
NSLog(@"%lu",p1.retainCount); //引用计数=0
[p1 release];
//怎么验证此时对象已被销毁呢?每一个对象被销毁时会调用dealloc方法,我们重写dealloc。让它输出一些东西。证明被调用了就可以
//重写是在这个对象所属类的.m文件里。即本例的Person.m中 return 0;
}

(8)定义一个p1指针变量后,将其赋值给还有一个指针变量p2。那么这个对象retainCount不变。仅仅是多了一个p2指向这个对象而已。不论什么一个p1和p2都能够release这个对象。release后,这两个指针变量假设不设置为nil就变成野指针。

(9)将指针变量作为參数传递给其它方法时。不会添加其指向对象的引用计数。

所以归根结底还是看是否有无retain、new、alloc,以及看是否与release、autorelease配对使用。

(10)Car类是Person类的子类,Person类有个方法是-(void)setCar:(Car *)car{_car=car;}和-(void)drive{[_car run];},run方法是Car类的方法。在主函数中我们的Person对象p1在alloc时候须要配对一个release。假设须要使用[p1 drive];那么须要实例化一个Car对象car1,那么也须要为car1匹配个release。通常是car1的alloc和release被包裹在p1的alloc和release里面。

假设我计划在[car1
release];和[p1 release];之间再使用p1的随意方法,比方[p1 drive];发现由于car1已经被release,所以会报错。也就是说,我的p1对象还存在。可是我已经不能随意使用它全部的方法了。怎么解决?

第一步:在setCar方法中改动为_car=[car retain];相当于给这个car1对象的retainCount+1。这样就算我们在主函数中使用配对原则。retainCount仍然还有1。这样p1就能够随意使用。

第二步:就是消除上面仍然存在的car1的retainCount的1。我们的目的是要这个car1的retainCount一直是1。除非我的p1不在了,那car1能够不在。所以我们须要在p1不在的时候把它消除,即在p1的dealloc里面把它消除,消除就是把它[_car release];

(11)接以上问题:假设在主函数里面连续定义两个Car对象变量car1和car2,则最后一个对象变量的内存管理正常,可是前面的几个不正常。

由于car1的retainCount还有1。在dealloc里面的_car是car2,所以car2内存正常,car1不正常,内存泄露。解决的方法?

问题还是集中在setCar中,在前面添加一句[_car release];如此便好。当第一次调用_car是nil,不影响。转了一圈出去后car1的retainCount为2,当第二次调用时[_car release];里的_car是car1,所以把car1释放了,然后接着把car2的retainCount变成2,随后在主函数以及dealloc中分别释放掉car2。

(12)接以上问题。假设我第二次调用setCar时不时传递car2,而是依旧传递的时car1。那么此时在第二次调用时,遇到[_car release];则已经释放了car1,所以以下一句_car=[car retain];就变成野指针操作了。解决的方法?

我们给这个[_car release};添加1个推断语句。由于假设是同一个对象没有新对象传递进来的话,_car就一直是这个对象。那么我们会在dealloc中的[_car release];释放掉,而假设后来传递的对象和上一次的不同的话,在dealloc中得[_car release];会变成第二个对象在释放,第一个对象就少了一个释放操作。

所以我们的结论是,推断一下,假设传递的新对象是上一次的那个。就不在这个释放,否则就在这里释放。

即变成if(_car!=car){[_car release];_car=[car
retain];},这句话的核心就是release旧值,retain新值。

并且假设传递的和上次一样的对象。则不做不论什么操作,retainCount仍然是1。

(13)所以,总结成员变量对象的内存管理。就是:a)主要针对setter方法。b)在setter方法中添加一个if(新值!

=旧值){release旧值,retain新值};c)并在类的dealloc函数中写一个release。

(14)事实上利用@property定义成员变量的时候事实上不同的參数就是在指示程序生成不同类型的setter方法。retain是指示程序生成符合内存管理的setter方法,就是上面的if的那一串。而assign则是普通setter方法,所以我们一般对对象类型用retain。而基本数据类型用assign。

可是,关键是上面的retain仅仅是改变了setter方法,并没有自己主动在dealloc中release。所以,我们在用@property(retain)***的时候,尽管不须要重写setter方法,可是须要重写类的dealloc方法来release释放一次这个成员变量。

(15)顺便,线程管理參数atomic是mac开发的残留物,一般iOS都是nonatomic,并且要书写,由于默认是atomic。所以一般仅仅有两种形式@property(nonatomic,retain)Char *char1;和@property(nonatomic,assign) int age;

(16)顺便,readwrite(生成getter和setter方法)和readonly(仅仅生成getter方法),默认是readwrite。

能够利用下面语句更换默认的setter或者getter方法名@property(nonatomic,assign,setter=abc) int age;以后调用setter方法就直接用abc取代。

这个一般用在定义BOOL变量时改变setter和getter的名称,一般改成isXXX。

【iOS开发-33】学习手动内存管理临时抛弃ARC以及retain/assign知识——iOSproject师面试必考内容的更多相关文章

  1. iOS-旧项目中手动内存管理(MRC)转ARC

    在ARC之前,iOS内存管理无论对资深级还是菜鸟级开发者来说都是一件很头疼的事.我参 加过几个使用手动内存管理的项目,印象最深刻的是一个地图类应用,由于应用本身就非常耗内存,当时为了解决内存泄露问题, ...

  2. iOS开发系列—Objective-C之内存管理

    概述 我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是由系统自己管理的,放在栈上).如果一个对象创建并使用后没 ...

  3. 【iOS开发-34】自己主动释放池@autoreleasepool的使用注意事项以及ARC机制——面试必考内容

    自己主动释放池@autorelease面试频率可能会吧release还要高. (1)在自己主动释放池@autoreleasepool{}中alloc一个对象后(如p1).仍然须要用[p1 autore ...

  4. IOS基础 Day-1手动内存管理

    辞职回家打算自学IOS开发,就在借个地方记录一下 Day-1      手动内存管理                   主要内容:release  retain必须配对好,不然会占用内存 慢慢积累导 ...

  5. OC学习10——内存管理

    1.对于面向对象的语言,程序需要不断地创建对象.这些对象都是保存在堆内存中,而我们的指针变量中保存的是这些对象在堆内存中的地址,当该对象使用结束之后,指针变量指向其他对象或者指向nil时,这个对象将称 ...

  6. Objective-C 【内存管理&手动内存管理 综述】

    ------------------------------------------- 内存管理 (1)Objective-C的内存管理 栈区    存放局部变量(由于基本数据类型占用的存储空间是固定 ...

  7. 关于iOS开发的学习

    关于iOS开发的学习,打个比方就像把汽车分解:    最底层的原料有塑料,钢铁    再用这些底层的东西造出来发动机,座椅    最后再加上写螺丝,胶水等,把汽车就拼起来了 iOS基本都是英文的资料, ...

  8. iOS经典面试题总结--内存管理

    iOS经典面试题总结--内存管理 内存管理 1.什么是ARC? ARC是automatic reference counting自动引用计数,在程序编译时自动加入retain/release.在对象被 ...

  9. Xcode 如何设置 自动内存管理 转换为 手动内存管理

    建议使用自动内存管理 ARC. 如果不想自动内存管理,可以在build phases 下的compile sources 中找到不想自动管理的.m文件 ,给它加compiler flags 为 -fn ...

随机推荐

  1. mysql 创建存储过程及测试sql

    --存储过程 CREATE PROCEDURE proc_batch_id( out batch_id bigint ) begin insert into generate_sync_batch ( ...

  2. ORADEBUG DOC 12.1.0.2

     https://berxblog.blogspot.com/2015/01/oradebug-doc-12102.html   this is just an online docu of ORAD ...

  3. WebService基于SoapHeader实现安全认证(二)

    支持通过Http请求方法调用webservice,同时支持SoapHeader验证. using Globalegrow.Common; using Globalegrow.Model; using ...

  4. Delphi XE10下用FireDAC与SQLite连接要注意的问题 转

      Delphi在XE的版本上,已经实现了安卓与苹果的移动跨平台,因此只需要一份代码,就可以统领两种手机平台,确实是一种高效的做法和节约的策略. 用Delphi XE7连接SQLite,主流使用Fir ...

  5. ArcGIS10.1发布WFS-T服务

    官方帮助文档:http://resources.arcgis.com/zh-cn/help/main/10.1/index.html#/na/0154000003m3000000/ 本文介绍了如何使用 ...

  6. 【java】LIst切割----划分 List为几个LIst的几种工具类 1.按照目标份数划分 2.按照目标容量划分 【适用场景:mybatis分批次In查询,放置In拼接sql过长】

    如题,示例代码如下: /** * 1> 按照份数---划分list * @param source * @param num 想要划分成多少份 * @return */ public stati ...

  7. Mybatis注解方法操作数据库

    Java中使用Mybatis操作数据库主要有两种方法:注解和xml配置,注解相对比较简单和方便,两种方式的效果一致.本文以注解的方式说明用Mybatis访问数据库的方法 一.创建数据表(MySql) ...

  8. mongo 误操作恢复数据

    场景:我往同一个集合里面插入 三条数据  aa:aa  bb:bb  cc:cc .后来我后悔了,不想插入 bb:bb,通过oplog重放过滤好 bb:bb这条数据. 原理: 1.通过 oplog.r ...

  9. JavaScript 创建类/对象的几种方式

    在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活的. JS对象是一种复合类型,它允许你通过变量 ...

  10. Python学习之路上的几个经典问题

    1.python有三元运算符语法(类似C语言的"?")么? 语法如下: [on_true] if [expression] else [on_false] 如果[expressio ...