【iOS開發-117】block為什麼用copy?利用runtime運行時的objc_方法為分類擴充成員變數

來源:互聯網
上載者:User

標籤:

(1)block

- (void)viewDidLoad {    [super viewDidLoad];    __block int a=10;    NSLog(@"a=%d",a);    void (^blockName)()=^{        a=20;    };    NSLog(@"a=%d",a);    blockName();    NSLog(@"a=%d",a);}

——以上輸出結果是10,10,20。

——只要在變數前面增加__block,在block裡面就可以修改該變數的值。當然也有其他方法如添加static等。

——如何能實現,需要查看底層代碼,也就是用C語言寫成的運行時代碼。在終端利用clang -rewrite-objc .m檔案名稱,把檔案轉為.cpp的C++底層代碼,可以分析底層實現的原理,可以用open .cpp檔案名稱,開啟查看。

——核心原理是,因為有一個__forwarding參數,每次輸出都是調用a.__forwarding->a的值。而且block本質上就是一個指向結構體的地址。


(2)運行時,平時我們寫得代碼其實最終都會轉成運行時代碼,效率快。但是我們一般用OC寫。如果非要使用運行時代碼方式書寫,可以增加下面的類。

#import <objc/message.h>//需要用到發送訊息的時候,設定函數的時候#import <objc/runtime.h>//裡面有一些特殊的函數

我們平時使用的方法,其實就是訊息機制,用得就是objc_msgSend這個函數。我們只要包含了上面的標頭檔<objc/message.h>,也可以用這個函數寫代碼。

——使用價值之一。我們平時的分類一般只能擴充一個類的方法,而不能擴充它的成員屬性。而使用的某些方法(如下)就可以為類動態地擴充成員屬性。

static double heightKey;-(void)setHeight:(double)height{    objc_setAssociatedObject(self, &heightKey, @(height), OBJC_ASSOCIATION_ASSIGN);}-(double)height{    return [objc_getAssociatedObject(self, &heightKey) doubleValue];}

——遍曆類的成員變數(使用者就是可以遍曆出所有變數統一操作,比如encode或者decode之類的操作)

#import "ViewController.h"#import "Person.h"#import <objc/message.h>#import <objc/runtime.h>@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];        unsigned int count=0;    //可以獲得類的所有成員屬性,預設指向0,即類的第一個成員屬性    Ivar *ivars=class_copyIvarList([Person class], &count);    //遍曆成員變數    for (int i=0; i<count; i++) {        Ivar ivar=ivars[i];        const char *name=ivar_getName(ivar);        const char *type=ivar_getTypeEncoding(ivar);        NSLog(@"%s,%s",name,type);    }}

輸出結果是:

_age,i_name,@"NSString"

(3)block變數定義時為什麼用copy?block是放在哪裡的?

——預設情況下,block是存檔在棧中,可能被隨時回收,需要copy操作。這也就是我們在定義block的時候用得時copy。而不是weak等等。

//預設是放在棧中,可能會被隨時銷毀    void (^blockName)()=^{            };    //進行一次copy操作,就可以放在堆中了。    //[blockName copy];    //以下方法也一樣。但是只能在非ARC中使用。    //Block_copy(blockName);        //用retain沒有用的原因:retain只是增加一次計數,block記憶體還是在棧中,並沒有轉移到堆中。

——block如果是copy的話,裡面使用它所在的類的對象的話,這個對象永遠無法被釋放。即person對象在堆中是強指標,且person在blockName就在,而blockName指向的代碼也在堆中,即它的person.age=20的那些代碼也在堆中,而這些代碼中有person對象,所以又反過來指向person對象。就這麼在相互指向的,永遠不能釋放。

    Person *person=[[Person alloc]init];    person.blockName=^{        person.age=20;    };

解決辦法如下。此處還不能直接把__unsafe_unretained放在建立person對象的那一行。因為如果那樣的話,這個person對象是一個弱指標指向的,一出生就死了。引入弱指標person0的目的就是block代碼裡的person0回指對象時,是弱引用,這樣就不會出現2個強引用互相指著。也可以用__weak。

    Person *person=[[Person alloc]init];    __unsafe_unretained Person *person0=person;    person.blockName=^{        person0.age=20;    };



【iOS開發-117】block為什麼用copy?利用runtime運行時的objc_方法為分類擴充成員變數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.