iOS 开发基础(1)--内存管理

内存管理的作用:实质就是管理堆(自己申请,自己释放)空间上的内存;在恰当的时候销毁对象的内存空间;合理使用内存,保证程序的高效运行;

1.内存管理的基本原则

MRC:遵循"谁创建,谁释放;谁引用,谁管理"的机制;当创建或者引用一个对象的时候,需要向这个对象发送alloc,copy,retain或者new消息,当释放对象的时候需要向该对象发送release或autorelease消息;每个对象都有一个引用计数器,初始化的值为1,引用计数器的是OC中判断这个对象是否被销毁的唯一标准,当对象的引用计数器为0的时候才会被销毁,对象自动调用dealloc方法;

ARC:iOS5.0/Mac OS X 10.7之后引入了自动内存管理机制----自动引用计数器;ARC的本质和MRC的实质是一样的,只是在ARC中不在显式的调用release或autorelease消息;在编译的时候编译器会自动在相应的位置加上release或autorelease;这是编译器的一个特性;同时在ARC环境下retain和release是被禁用,相应的修饰符换成了strong,在OC中默认情况下所有的指针都是强指针;在ARC环境中只要没有强指针指向对象这个对象就会被销毁;

2.属性修饰符的使用

使用场合 修饰符 修饰类型及作用
strong ARC 相当于MRC下的retain,修饰OC对象
weak ARC 修饰delegate和UI控件;所有被weak修饰的指针在对象被释放的时候都会将指针置为nil;避免循环引用的问题,同时也避免了野指针操作;
retain MRC 引用计数器加1;指针拷贝,指向同一内存空间
assign MRC/ARC 一般只用来修饰基本数据类型,只是简单的赋值,不改变引用计数器;有时也会用于切断循环引用的问题修饰delegate;
copy MRC/ARC 修饰字符串,block;属于内容的拷贝(内存分配一个新的对象),指针指向不同的内存;

符合内存管理原则的setter方法的写法:

- (void)setName:(NSString *)name
{
      if(_name != name){
           [_name release];
           _name = [name retain];
      }
}

- (void)setName:(NSString *)name
{
      if(_name != name){
           [_name release];
           _name = [name copy];
      }
}

@synthesize和@dynamic分别有什么作用?

@synthesize
除非已经实现属性的getter和setter方法,否则由编译器自动生成getter和setter方法;当开发人员已经实现的话,编译器就不会自动生成getter和setter方法的实现;
@dyanmic
就是告诉编译器不自动生成getter和setter方法,避免编译期间产生警告;

3.自动释放池

自动释放池就是一个池子,当对象调用autorelease方法的时候,会自动将对象放在自动释放池中;只有当池子被销毁的时候,会给池子中所有的对象执行一个release方法,达到延迟释放对象的效果;

自动释放池和垃圾回收(gc)的区别

ios 是没有垃圾回收的,自动释放池是 oc 中管理内存的一种方式,它和 gc 是本质区别的,自动释放池管理内存的前提是,必须把要管理内存的对象加入池内,才会生效。而 gc 是不断检测当前程序中是否有不再使用的内存进而释放

4.内存管理的注意事项

  1. _ _weak 和 __strong用来修饰变量的.

__weak是声明一个可以自动nil化的弱引用.

__strong是缺省的关键字.

__unsafe_unretained声明一个弱引用,不会自动你nil化;作用相当于assign;

2.声明属性的时候不能以new开头;如果非要以new开头的话需要自定义getter方法名,如:

@property(getter = getName) NSString *name;

3.UI控件声明属性的时候一般使用weak;因为UIWinow ----- RootViewController ----- view ----- subViews ----- 数组包含当前的控件;也就是说当前控制器已经强引用当前控件了,因此在声明属性的时候使用weak比较好;

4.block中为了避免循环引用应使用_ _weak typeof(self) weakself = self;同时在block内部修改外部变量的时候使用 __block修饰;其作用是只要观察到该变量被block所持有,就将外部变量在栈中的内存地址放到堆中,进而可以在block内部也可以修改外部变量的值;

5.ARC只能管理Foundation框架的变量,如果程序中把Foundation中的变量强制换成Core Foundation中的变量需要交换管理权;

__bridge只做类型的转换,但是不修改对象的内存管理权;
__bridge_ratained (也可以使用CFBridgingRetain)将OC对象转换成C对象,同时将对象的内存管理权将给我们,后续需要使用CGRelease或者相关方法来释放对象
__bridge_transfer(也可以使用CFBridgingRelease)将C对象转换成OC对象,同时将对象的内存管理权交给ARC来处理;

6.ARC和MRC混编的转换
在非ARC工程中采用ARC去编译某些类:-fobjc-arc。
在ARC下的工程采用非ARC去编译某些类:-fno-objc-arc。

7.代理(delegate)声明属性的时候使用weak或者assign;这样是为了防止循环引用,因为一般情况下控件的代理都是控制器,而控制器拥有这个控件,构成了循环引用是文字;

5.@property 的本质是什么?

本质就是:@property = ivar + setter + getter;

解释:
"属性(property)有两打概念:ivar(实例变量) 存取方法(access method = setter +getter)".

“属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。这个概念已经定型,并且经由“属性”这一特性而成为 Objective-C 2.0 的一部分。 而在正规的 Objective-C 编码风格中,存取方法有着严格的命名规范。 正因为有了这种严格的命名规范,所以 Objective-C 这门语言才能根据名称自动创建出存取方法。其实也可以把属性当做一种关键字,其表示:

编译器会自动写出一套存取方法,用以访问给定类型中具有给定名称的变量。 所以你也可以这么说:@property = getter + setter;

ivar、getter、setter 是如何生成并添加到这个类中的?
“自动合成”( autosynthesis)
完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。也可以在类的实现代码里通过 @synthesize 语法来指定实例变量的名字.

我为了搞清属性是怎么实现的,曾经反编译过相关的代码,他大致生成了五个东西:

  1. OBJC_IVAR_$类名$属性名称 :该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示该变量距离存放对象的内存区域的起始地址有多远。
  1. setter 与 getter 方法对应的实现函数
  2. ivar_list :成员变量列表
  3. method_list :方法列表
  4. prop_list :属性列表

也就是说我们每次在增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 method_list 中增加 setter 与 getter 方法的描述,在属性列表中增加一个属性的描述,然后计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 内存管理是程序在运行时分配内存、使用内存,并在程序完成时释放内存的过程。在Objective-C中,也被看作是在众...
    蹲瓜阅读 3,001评论 1 8
  • iOS内存管理 概述 什么是内存管理 应用程序内存管理是在程序运行时分配内存(比如创建一个对象,会增加内存占用)与...
    蚊香酱阅读 5,694评论 8 119
  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,948评论 1 16
  • 在我看来,人生是漫长又孤独的旅程。伴随着哭声降临,也在哭声中离去。生死是人力无法改变的事。历经悲欢离合,成功...
    弓长木水阅读 222评论 0 2
  • 南昌人的早餐通常是一碗拌粉,一个瓦罐汤,俗称“恰汤 唆粉”。 今天一大早起床,媳妇正酣睡。我蹑手蹑脚地起床出去买的...
    LJ李健阅读 670评论 0 51