kkbox-ios-dev笔记(三) - 内存管理/代理

内存管理(一)

  • 内存泄漏:该释放的对象, 没有被释放(已经不再使用的对象, 没有被释放)
  • 无效内存引用:内存已经被释放了,我们还强行调用。会报EXC_BAD_ACCESS错误。

基本原则

  • 如果是initnewcopy这些方法产生出来的对象,用完就该调用release.
  • 如果是其他一般方法产生出来的对象,就会回调auto-release对象、或是singleton对象(稍晚会解释什么是singleton),就不需要另外调用release.

而调用retain与release的时机包括:

  • 如果是在一般代码中用了某个对象,用完就要release或是auto-release
  • 如果是要将某个Objective-C对象,变成是另外一个对象的成员变量,就要将对象retain起来。但是delegate对象不该retain
  • 在一个对象被释放的时候,要同时释放自己的成员变量,也就是要在实现delloc的时候,释放自己的成员变量。
  • 要将某个对象设为另外一个对象的成员变量,需要写一组getter/setter

Getter/SetterProperty语法

  • 基本数据类型

@interface MyClass:NSObject
{
int number;
}

  • (int)number;
  • (void)setNumber:(int)inNumber;
    @end
> * 实现部分

> ```swift
- (int)number

{
return number;
}

  • (void)setNumber:(int)inNumber
    {
    number = inNumber;
    }

>* 如果是 OC 对象,我们则是要将原本成员变量已经指向的内存释放,然后将传入的对象`retain`起来。该写法并不安全

>```swift
- (id)myVar {
return myVar;

}

  • (void)setMyVar:(id)inMyVar
    {
    [myVar release];
    myVar = [inMyVar retain];
    }
* 假如今天我们在开发中用到很多个线程,而在不同的线程中同时会用到`myVar`,在某某个线程中调用了`[myVar release]`之后,到`myVar`指定到`inMyVar`的位置之间,假如另外一个线程刚好用到了`myVar`,这时候`myVar`刚好指到了一个已経被释放的内存,这就造成了

EXC_BAD_ACCESS错误.

  • 更安全的写法:加锁,让程序在调用setMyVar:的时候,不让其他线程调用myVar;另外一种简单的方法如下:
  • (void)setMyVar:(id)inMyVar
    {
    id tmp = myVar;
    myVar = [inMyVar retain];
    [tmp release];
    }

* 上面的例子,用`property`语法可以写成:

```swift
@interface MyClass:NSObject

{
id myVar;
int number;
}
@property (retain, nonatomic) id myVar;
@property (assign, nonatomic) int number;
@end
@implementation MyClass

  • (void)dealloc
    {
    [myVar release];
    [super dealloc];
    }
    @end
**`myVar = nil`与`self.myVar = nil`的区别?**

* 前者只是单纯的将`myVar`的指针指向`nil`,但是并没有释放原本所指向的内存位置,所以会造成内存泄漏,但后者却等同于调用`[self setMyVar:nil]`,会先释放`myVar`原本指向的位置,然后将`myVar`设成`nil`。

内存管理(二)

  • ARC 是通过静态分析,在编译时决定应该要在代码的哪个地方加入retainrelease

循环retain

  • 错误情况:
    1. 把代理设置为strong
    1. 某对象的某property是一个block,但是在这个block里面把对象自己给retain了一份。
    1. 使用timer的时候,到了dealloc的时候才停止timer
  • 假如我们在有一控制器,我们希望这个控制器可以定时更新,
    那么,我可能会使用+scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:方法建立timer对象,指定定时执行某个selector.要特别注意,在建立这个timer的时候,我指定给timertarget,也曾被timer retain一份,因此,我们想要在控制器在dealloc的时候,才停止timer就曾有问题:因为控制器已经被timer retain起来了,所以只要timer还在执行,控制器就不
    可能走到dealloc的地方。

对象桥接

  • 什么是对象桥接:Foundation库里面的每一个对象,都有对应的 C 实现,这 C 的实现叫作Core Foundation,当我们在使用Core Foundation里面的 C 形态时,像CFStringCFArray等,我们可以让这些形态变成可以接受 ARC 的管理.这种让 C 形态也可以被当做 OC 对象,接受 ARC 管理的方式,就叫对象桥接。
  • 有三个关键字:__bridge__bridge_retained__bridge_transfer
  • __bridge:会把Core Foundation的 C 资料形态转换成 OC 对象,但是不会多做retainrelease
  • __bridge_retained:会把Core Foundation的 C 资料形态转换成 OC 对象,并且会做一次retain,但是之后必须由我们手动调用CFRelease,释放内存。
  • __bridge_transfer:会把Core Foundation转换成 OC 对象,并且会让 ARC 主动添加retainrelease
  • 但不一定每个Core Foundation型态都有办法转换成OC对象。详见苹果文档详细说明

内存管理(三)

  • 略 (关于控制器的内存管理)

代理

Delegate属性应该要用Weak,而非strong

  • 原因是:需要设置代理对象的这个对象,往往是其代理对象的成员变量,A 的实例是 A 对象,是 B 的成员变量,可能已经被 B retain了一份,如果 A 又 retain了一次 B,就会出现循环 retain的问题 -- 已经被别人retain,又把别人retain一次。

命名规范

  • 至少传入一个参数,就是代理调用者本身;往往以传入的类名开头,让我们可以辨别这是哪各类的代理方法。以代理UITableViewDelegate为例
  • - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

我们曾经犯过的低级错误

  • 源代码
@class MyClass;

@protocol MyClassDelegate <NSObject>

  • (void)myClassWillBegin:(MyClass *)myClasss;
  • (void)myClassDidBegin:(MyClass *)myClasss;
  • (void)myClassWillStop:(MyClass *)myClasss;
  • (void)myClassDidStop:(MyClass *)myClasss;
    @end
    @interface MyClass : NSObject
    {
    id <MyClassDelegate> delegate;
    }
  • (void)begin;
  • (void)stop;
    @property (assign, nonatomic) id <MyClassDelegate> delegate;
    @end
    @implementation MyClass
  • (void)begin
    {
    [delegate myClassWillBegin:self];
    // Do something
    [delegate myClassDidBegin:self];
    }
  • (void)stop
    {
    [delegate myClassWillStop:self];
    // Do something
    [delegate myClassDidStop:self];
    }
    @synthesize delegate;
    @end
* 问题:在`myClassWillBegin:`里面想要做一些检查,如果在某些条件下,这件事情不该跑起来,而应该停止,所以在`myClassWillBegin:`里面调用了`stop`。但这么做,并不会让这件事情结束,因为`begin`这个方法在对代理调用完`myClassWillBegin:`之后,程序还是会继续走下去,所以还是把`begin`整个做完了。

* 优化后:

```swift
@class MyClass;
####Delegate属性应该要用Weak,而非strong
>* **原因是:**需要设置代理对象的这个对象,往往是其代理对象的成员变量,A 的实例是 A 对象,是 B 的成员变量,可能已经被 B `retain`了一份,如果 A 又 `retain`了一次 B,就会出现循环 `retain`的问题 -- 已经被别人`retain`,又把别人`retain`一次。
>
>####命名规范
>* 至少传入一个参数,就是代理调用者本身;往往以传入的类名开头,让我们可以辨别这是哪各类的代理方法。以代理`UITableViewDelegate`为例
>  * `- (void)tableView:(UITableView *)tableView
        didSelectRowAtIndexPath:(NSIndexPath *)indexPath`
>
>####我们曾经犯过的低级错误
>>* 源代码
>>
>>```swift
>>@class MyClass;
@protocol MyClassDelegate <NSObject>
- (void)myClassWillBegin:(MyClass *)myClasss;
- (void)myClassDidBegin:(MyClass *)myClasss;
- (void)myClassWillStop:(MyClass *)myClasss;
- (void)myClassDidStop:(MyClass *)myClasss;
@end
@interface MyClass : NSObject
{
    id <MyClassDelegate> delegate;
}
- (void)begin;
- (void)stop;
@property (assign, nonatomic) id <MyClassDelegate> delegate;
@end
@implementation MyClass
- (void)begin
{
    [delegate myClassWillBegin:self];
    // Do something
    [delegate myClassDidBegin:self];
}
- (void)stop
{
    [delegate myClassWillStop:self];
    // Do something
    [delegate myClassDidStop:self];
}
@synthesize delegate;
@end
>>```
>>* 问题:在`myClassWillBegin:`里面想要做一些检查,如果在某些条件下,这件事情不该跑起来,而应该停止,所以在`myClassWillBegin:`里面调用了`stop`。但这么做,并不会让这件事情结束,因为`begin`这个方法在对代理调用完`myClassWillBegin:`之后,程序还是会继续走下去,所以还是把`begin`整个做完了。
>>
>>* 优化后:
>>
>>```swift
>>@class MyClass;
@protocol MyClassDelegate <NSObject>
  • (BOOL)myClassShouldBegin:(MyClass *)myClasss;
  • (void)myClassDidBegin:(MyClass *)myClasss;
  • (BOOL)myClassShouldStop:(MyClass *)myClasss;
  • (void)myClassDidStop:(MyClass *)myClasss;
    @end
    @interface MyClass : NSObject
    {
    id <MyClassDelegate> delegate;
    }
  • (void)begin;
  • (void)stop;
    @property (assign, nonatomic) id <MyClassDelegate> delegate;
    @end
    @implementation MyClass
  • (void)begin
    {
    if (![delegate myClassShouldBegin:self]) {
    return;
    }
    // Do something
    [delegate myClassDidBegin:self];
    }
  • (void)stop
    {
    if (![delegate myClassShouldStop:self]) {
    return;
    }
    // Do something
    [delegate myClassDidStop:self];
    }
    @synthesize delegate;
    @end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 37.cocoa内存管理规则 1)当你使用new,alloc或copy方法创建一个对象时,该对象的保留计数器值为1...
    如风家的秘密阅读 829评论 0 4
  • 1.Difference between shallow copy and deep copy? 浅复制和深复制的...
    用心在飞阅读 989评论 0 9
  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,948评论 1 16
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,124评论 29 470
  • 给七七的一封信 七七、好久不见。那天看到你写的这句话、忽然好难过、是真的好久不见了。 七七、不敢用亲爱的再来称呼你...
    毛蛋碎碎念阅读 187评论 0 0