iOS 被濫用的weak

看其他人的代碼,發(fā)現(xiàn)weak出現(xiàn)在了幾乎所有有block的地方振湾,比如 GCD 比如杀迹,使用Masnory布局的地方,


weak
weak1.jpeg

問了幾個同學(xué)押搪,理由大都是树酪,避免循環(huán)引用,被循環(huán)引用整怕了大州。
反正用了也沒什么不好之類的续语。。厦画。

屏幕快照 2017-08-04 下午10.24.21.png

打個符號斷點疮茄,觀察一下滥朱,這兩個函數(shù)在不斷的調(diào)用,函數(shù)內(nèi)部在操作一個不簡單的list,有興趣可以自己閱讀 runtime源碼力试。你看徙邻,不但每次調(diào)用兩個開銷挺大的函數(shù),而且還有一個list

雖說現(xiàn)在手機(jī)好了畸裳,但是缰犁,對自己狠點,能規(guī)范的地方就規(guī)范怖糊,app會有意想不到的收獲帅容。。

以布局Monsary 為栗子伍伤,我們看看到底要不要使用weak并徘。。

看到QQ群里有人說嚷缭,出現(xiàn)block 必然會copy block中引用到的東西饮亏。
暫且不管Monsary 源碼實現(xiàn)部分,

我們使用符號斷點阅爽。符號斷點斷在

_Block_copy
_Block_release

部分路幸,測試代碼:

[self.personsLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mostCostLabel);
        make.right.equalTo(self.mostCostLabel);
        make.top.equalTo(self.mostCostLabel.mas_bottom).offset(6.0f);
        make.height.mas_equalTo(10.0f);
}];

通過斷點可以看到,當(dāng)執(zhí)行 block 中的語句的時候付翁,的確會調(diào)用 _Block_copy简肴,但是在 block 執(zhí)行完之后,斷點會停在 _Block_release 這里百侧。

所以砰识,安全可靠,不用使用weak 的佣渴,GCD 和 系統(tǒng) 的動畫樣式如果不放心辫狼,也可以這樣子測試是否釋放。

后記

@implementation NSTimer (PTVSafe)

+ (id)safe_scheduledTimerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)())inBlock repeats:(BOOL)inRepeats {
    void (^block)() = [inBlock copy];
    id ret = [self scheduledTimerWithTimeInterval:inTimeInterval target:self selector:@selector(ptv_jdExecuteSimpleBlock:) userInfo:block repeats:inRepeats];
    return ret;
}

+ (void)ptv_jdExecuteSimpleBlock:(NSTimer *)inTimer; {
    if ([inTimer userInfo]) {
        void (^block)() = (void (^)())[inTimer userInfo];
        block();
    }
}

@end

對于NSTimer 這樣子進(jìn)行擴(kuò)展辛润,完全沒有必要的感覺膨处,每次都要調(diào)用copy,全局給項目中的 _Block_copy 打符號斷點,timer 這里調(diào)用的甚多砂竖。釋放的也不是很及時真椿。

反思:設(shè)計一個通用組件給別人調(diào)用的時候,要想的東西乎澄,不止使用方便這個層面突硝!

符號斷點

UIView 自帶的動畫實現(xiàn)探究

- (void)viewDidLoad {
    
    UIView *view = [UIView new];
    view.backgroundColor = [UIColor redColor];
    view.frame = CGRectMake(0, 30, 200, 200);
    
    [self.view addSubview:view];
    
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
        //①
//        view.frame = CGRectMake(10, 20, 30, 40);
        
        //②
        [UIView animateWithDuration:0.5
                         animations:^{
                             view.frame = CGRectMake(10, 20, 30, 40);
                         }];
    
        
    });
 }

我們順勢探究一下動畫的實現(xiàn)過程。

使用 ① 的方式直接修改frame 是不會有動畫的置济。
使用 ② 的方式是有動畫的解恰。

but why?

我們知道锋八,UIView 和 CALayer 的關(guān)系,想完成動畫修噪,肯定是在layer 層做的查库,于是我們打符號斷點給 layer 層的

- (void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key;

函數(shù),看看是否會調(diào)用黄琼,該函數(shù)。重新運(yùn)行整慎,真的調(diào)用了脏款。

QuartzCore`-[CALayer addAnimation:forKey:]:
->  0x10c569654 <+0>:   pushq  %rbp
    0x10c569655 <+1>:   movq   %rsp, %rbp
    0x10c569658 <+4>:   pushq  %r15
    0x10c56965a <+6>:   pushq  %r14
    0x10c56965c <+8>:   pushq  %r13
    0x10c56965e <+10>:  pushq  %r12
    0x10c569660 <+12>:  pushq  %rbx
    0x10c569661 <+13>:  subq   $0x18, %rsp
    0x10c569665 <+17>:  movq   %rcx, %r14
    0x10c569668 <+20>:  movq   %rdx, %r12
    0x10c56966b <+23>:  movq   %rdi, %r15
    0x10c56966e <+26>:  movq   0xc8203(%rip), %rdi       ; (void *)0x000000010c633108: CATransition

當(dāng)然,我們不看匯編函數(shù)裤园,下來我們改造一下我們的demo, 看看究竟3肥Α!

改造后的代碼如下:

@interface PDLayer : CALayer

@end

@implementation PDLayer

- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key {
    [super addAnimation:anim
                 forKey:key];
    NSLog(@"%@ %@", anim, key);
}

@end


@interface PDView : UIView

@end

@implementation PDView

+ (Class)layerClass {
    return [PDLayer class];
}

@end
- (void)viewDidLoad {
    
    PDView *view = [PDView new];
    view.backgroundColor = [UIColor redColor];
    view.frame = CGRectMake(0, 30, 200, 200);
    
    [self.view addSubview:view];
    
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
        //①
//        view.frame = CGRectMake(10, 20, 30, 40);
        
        //②
        [UIView animateWithDuration:0.5
                         animations:^{
                             view.frame = CGRectMake(10, 20, 30, 40);
                         }];
    
        
    });

其實什么都沒變拧揽,只是把上面的UIView 替換成了 PDView. 給 PDLayer 的 addAnimation 斷點剃盾。看看會發(fā)生什么淤袜。

我們po 一下輸出的東東

(lldb) po anim
<CABasicAnimation:0x60800003f3c0; toValue = NSPoint: {0, 0}; additive = 1; delegate = <UIViewAnimationState: 0x7ff8d9d02ec0>; fillMode = both; timingFunction = easeInEaseOut; duration = 0.5; fromValue = NSPoint: {75, 90}; keyPath = position>

(lldb) po key
position

(lldb) 

可以看到痒谴,給view 的 layer 層添加了CABasicAnimation 動畫, key 的 值為 position

繼續(xù)執(zhí)行铡羡,斷點又?jǐn)嘣诹送瑯拥牡胤交担敵鋈缦?/p>

(lldb) po key
bounds.origin

(lldb) po anim
<CABasicAnimation:0x600000039e60; toValue = NSPoint: {0, 0}; additive = 1; fromValue = NSPoint: {0, 0}; keyPath = bounds.origin; delegate = <UIViewAnimationState: 0x7ff8d9d02ec0>; fillMode = both; timingFunction = easeInEaseOut; duration = 0.5>

這回加的key 是 bounds.origin

繼續(xù)運(yùn)行

斷點又?jǐn)嗔?/p>

(lldb) po key
bounds.size

(lldb) po anim
<CABasicAnimation:0x60000003a1c0; toValue = NSSize: {0, 0}; additive = 1; fromValue = NSSize: {170, 160}; keyPath = bounds.size; delegate = <UIViewAnimationState: 0x7ff8d9d02ec0>; fillMode = both; timingFunction = easeInEaseOut; duration = 0.5>

(lldb) 

這回添加的動畫key 是 bounds.size。

可見UIView 的動畫過程調(diào)用的都是 CABasicAnimation 系列的動畫添加給 layer.

那么問題來了烦周,為什么上面的 1 和 2 會有不同的表現(xiàn)呢

我們再觀察兩秒

        //①
//        view.frame = CGRectMake(10, 20, 30, 40);
        
        //②
        [UIView animateWithDuration:0.5
                         animations:^{
                             view.frame = CGRectMake(10, 20, 30, 40);
                         }];

我們觀察calayer 的函數(shù)尽爆,又發(fā)現(xiàn)了

- (nullable id<CAAction>)actionForKey:(NSString *)event;

難道這個函數(shù)在不同的場景返回值不一樣?
我們測試一下读慎。

代碼修改如下:

 //①
//        view.frame = CGRectMake(10, 20, 30, 40);
        id cc = [view.layer actionForKey:@"position"];
        NSLog(@"%@",cc);
        //②
        [UIView animateWithDuration:0.5
                         animations:^{
                             id cc = [view.layer actionForKey:@"position"];
                             NSLog(@"%@",cc);
                             
                             view.frame = CGRectMake(10, 20, 30, 40);
                         }];
    

我們觀察兩次 cc 有何不同

還真被蒙對了

(lldb) po cc
 nil
(lldb) c
Process 13382 resuming
2017-09-07 14:48:32.908 imageName[13382:1401757] (null)
(lldb) po cc
<_UIViewAdditiveAnimationAction: 0x60000003e660>

(lldb) 

在動畫block里面打印出的值是完全不一樣的漱贱。第一次是nil 第二次是個動畫

我們再觀察一次

[UIView performWithoutAnimation:^{
        id cc = [view.layer actionForKey:@"position"];
        NSLog(@"%@",cc);
    }];
    

這次打印出來依舊是 nil.由此,結(jié)論十分明確了夭委。

由此幅狮,我們明白了,UIView 自帶的系統(tǒng)動畫是如何實現(xiàn)的闰靴,而且知道了彪笼,這種情況下,是絕對不用weak的蚂且。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末配猫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子杏死,更是在濱河造成了極大的恐慌泵肄,老刑警劉巖捆交,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異腐巢,居然都是意外死亡品追,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門冯丙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肉瓦,“玉大人,你說我怎么就攤上這事胃惜∨⒗颍” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵船殉,是天一觀的道長鲫趁。 經(jīng)常有香客問我,道長利虫,這世上最難降的妖魔是什么挨厚? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮糠惫,結(jié)果婚禮上疫剃,老公的妹妹穿的比我還像新娘。我一直安慰自己寞钥,他們只是感情好慌申,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著理郑,像睡著了一般蹄溉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上您炉,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天柒爵,我揣著相機(jī)與錄音,去河邊找鬼赚爵。 笑死棉胀,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冀膝。 我是一名探鬼主播唁奢,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼窝剖!你這毒婦竟也來了麻掸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赐纱,失蹤者是張志新(化名)和其女友劉穎熬北,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诚隙,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年久又,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片地消。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡烈评,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出犯建,到底是詐尸還是另有隱情,我是刑警寧澤瓜客,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布适瓦,位于F島的核電站,受9級特大地震影響谱仪,放射性物質(zhì)發(fā)生泄漏玻熙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一疯攒、第九天 我趴在偏房一處隱蔽的房頂上張望嗦随。 院中可真熱鬧,春花似錦敬尺、人聲如沸枚尼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽署恍。三九已至,卻和暖如春蜻直,著一層夾襖步出監(jiān)牢的瞬間盯质,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工概而, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留呼巷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓赎瑰,卻偏偏與公主長得像王悍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子乡范,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,146評論 30 470
  • 在iOS中隨處都可以看到絢麗的動畫效果配名,實現(xiàn)這些動畫的過程并不復(fù)雜啤咽,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,495評論 6 30
  • 在iOS實際開發(fā)中常用的動畫無非是以下四種:UIView動畫渠脉,核心動畫宇整,幀動畫,自定義轉(zhuǎn)場動畫芋膘。 1.UIView...
    請叫我周小帥閱讀 3,098評論 1 23
  • 前言 本文只要描述了iOS中的Core Animation(核心動畫:隱式動畫鳞青、顯示動畫)、貝塞爾曲線为朋、UIVie...
    GitHubPorter閱讀 3,628評論 7 11
  • 1臂拓,NSObject中description屬性的意義,它可以重寫嗎?答案:每當(dāng) NSLog(@"")函數(shù)中出現(xiàn) ...
    eightzg閱讀 4,144評論 2 19