[Note] Effective OC - Item 49~52

Chapter 7. The System Frameworks

<br />


Item 49: Use Toll-Free Bridging for Collections with Custom Memory-Management Semantics

<br />
这一节讲Toll-Free Bridging。

CFArrayRef aCFArray = (__bridge CFArrayRef)anNSArray;

这是一个NSArray桥接成CFArray的例子。非OC对象有ARC不适用的问题。bridged cast涉及到ARC对OC对象的引用,__bridge__bridge_transfer(把CF数据结构变成OC对象)都是保留了ARC对OC对象的所有权,所以就不用手动写对象的释放了。而__bridge_retained则是放弃了所有权,这时需要手动调用CFRelease(CFObject)来手动释放非OC对象。
使用桥接来转换的目的是使用CoreFoundation中具有的一些独特功能。文中举的例子是改变字典对键和值得内存语义。普通的OC字典,对键进行copy,对值进行retain,而用CFDictionary可以改变这一点。例子有点长,然后我好像不是特别懂…等我懂了再来更一下。
<br />


Item 50: Use NSCache Instead of NSDictionary for Caches

<br />
这一节讲NSCache对象来做缓存。
抄一段Reference:

An NSCache object is a collection-like container, or cache, that stores key-value pairs, similar to the NSDictionary class.
While a key-value pair is in the cache, the cache maintains a strong reference to it. A common data type stored in NSCache objects is an object that implements the NSDiscardableContent protocol. Storing this type of object in a cache has benefits, because its content can be discarded when it is not needed anymore, thus saving memory.

NSCache objects differ from other mutable collections in a few ways:

  • The NSCache class incorporates various auto-removal policies, which ensure that it does not use too much of the system’s memory. The system automatically carries out these policies if memory is needed by other applications. When invoked, these policies remove some items from the cache, minimizing its memory footprint.
  • You can add, remove, and query items in the cache from different threads without having to lock the cache yourself.
  • Unlike an NSMutableDictionary object, a cache does not copy the key objects that are put into it.

其实这一节讲的内容以上就大概都提到了。首先这个类是thread-safe的,因为缓存如果不thread-safe会很麻烦,我猜可能会引起重复下载。NSCache的键可以是不支持copy的对象,NSCache也不对键做copy操作,所以用起来比NSDictionary要灵活方便。另外比较厉害的是在内存紧张的时候它可以删减使用频率最低的对象。上面提到了这个对象需要实现NSDiscardableContent协议,比如NSPurgeableData类的对象。NSDiscardableContent协议中,beginContentAccessendContentAccess这两个方法用来表示当前对象是否处于可被丢弃的状态。
<br />


Item 51: Keep initialize and load Implementations Lean

<br />
这一节讲load与initialize两个方法。
都是初始化的方法,但是有一些不同之处。load是程序启动时就会调用的,所有用到的类都会调用,调用时整个程序阻塞,要等待所有类加载完毕才会响应,所以尽量不要在里面做操作。特别是不要做用到别的类的操作,因为load的阶段属于fragile state,各个类的加载顺序不定,也不能确定哪个类加载完毕了,所以可能不能正常调用别的类的方法。另外load是不遵守类继承规则的,如果本类没有实现load方法,就不会调用了,不会像继承系统一样向父类寻找方法的实现。
initialize采取的是懒加载的方式,程序使用到这个类时才会调用,调用时线程阻塞,如果是主线程,会造成UI无响应,所以也是尽量不要做复杂的操作。initialize应只用来设置内部数据,如果设置其他类的数据,也会出现类似的可能没有完全加载好的问题。initialize遵守类继承规则,如果本类没有实现会向父类查找。
对于不能在编译器初始化的全局对象,可以放在initialize做。这个坑我踩过。因为NSString对象的初始化可以写在外面,我以为其他的对象也可以,然而并不能[\再见]。应该在外面声明,然后在initialize内部进行初始化,此时已经不是编译期而是运行期了,对象可以正常初始化了。
<br />


Item 52: Remember that NSTimer Retains Its Target

<br />
这一节讲NSTimer是怎么出现retain cycle的,以及怎样去解决。
直接看一下代码分析一下吧:

@interface EOCClass : NSObject
- (void)startPolling;
- (void)stopPolling;
@end

@implementation EOCClass {
 NSTimer *_pollTimer;
}

- (id)init {
    return [super init];
}

- (void)dealloc {
    [_pollTimer invalidate];
}

- (void)stopPolling {
    [_pollTimer invalidate];
    [_pollTimer = nil];
}

- (void)startPolling {
    __weak EOCClass *weakSelf = self;
    _pollTimer = [NSTimer eoc_scheduledTimerWithTimeInterval:5.0 
                          block:^{
                              EOCClass *strongSelf = weakSelf;
                             [strongSelf p_doPoll];
                          } 
                          repeats:(BOOL)repeats];
}

- (void)p_doPoll {
    //Poll the resource
}

@end
@interface NSTimer (EOCBlocksSupport)

+ (NSTimer *)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;
@end

@implementation NSTimer (EOCBlocksSupport)

+ (NSTimer *)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats
{
    return [self scheculedTimerWithTimeInterval:interval target:self selector:@selector(eoc_blockInvoke:) userInfo:[block copy] repeats:repeats];
}

+ (void)eoc_blockInvoke:(NSTimer *)timer {
    void (^block)() = timer.userInfo;
    if (block) {
        block();
    }
}

@end

再放一个EOCClass类原来的startPolling方法对比一下:

- (void)startPolling {
    _pollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 traget:self selector:@selector(p_doPoll) userInfo:nil repeats:(BOOL)repeats];
}

这里的场景是创建一个EOCClass类型的对象(起个名字叫EOCObject吧),然后调用它的startPolling方法。EOCObject对于pollTimer的保留很明显能看到。如果采用之前的startPolling方法,pollTimer因为以EOCObject为target,所以也会保留它,这样就形成了保留环。这个保留环打破的时机是pollTimer调用invalidate的时候,也就是调用stopPolling方法或者EOCObject被销毁时,但此时由于保留环的存在,EOCObject很难被销毁,那就只有采取当外部指向这个保留环的最后一个引用撤销时,手动调用stopPolling,操作性比较差。
解决的思路是,不使用target来调用p_doPoll方法,而改用传入block来实现,并且使用weakSelf避免了block中的保留环。这样pollTimer不再有指向EOCObject的强引用,也就避免了内存泄露的发生。具体的方法是,给NSTimer添加一个分类,把block作为userInfo传入,然后调用时在block里调用p_doPoll就可以了。


终于有时间完结了这本书。开心O(∩_∩)O 撒花!

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

推荐阅读更多精彩内容