iOS動態新增屬性

2021-09-11 10:57:02 字數 4726 閱讀 7692

之前一篇文章《ios關聯物件》詳細介紹了如何通過關聯物件新增屬性,本篇文章將介紹如何通過runtime的class_addpropertyclass_addivar動態新增屬性,並且帶領大家看看這兩個方法底層是如何實現的。

對於已經存在的類我們用class_addproperty方法來新增屬性,而對於動態建立的類我們通過class_addivar新增屬性, 它會改變乙個已有類的記憶體布局,一般是通過objc_allocateclasspair動態建立乙個class,才能呼叫class_addivar建立ivar,最後通過objc_registerclasspair註冊class。

對於已經存在的類,class_addivar是不能夠新增屬性的

首先我們宣告了乙個person

@inte***ce person : nsobject

@property (nonatomic,copy)nsstring *name;

@end

複製**

然後我們通過class_addproperty動態新增屬性

id getter(id object,sel _cmd1)

void setter(id object,sel _cmd1,id newvalue)

int main(int argc, const char * ar**) ; //type

objc_property_attribute_t ownership0 = ; // c = copy

objc_property_attribute_t ownership = ; //n = nonatomic

objc_property_attribute_t backingivar = ; //variable name

objc_property_attribute_t attrs = ;//這個陣列一定要按照此順序才行

bool add = class_addproperty([person class], "***", attrs, 4);

if (add) else

class_addmethod([person class], nsselectorfromstring(@"***"), (imp)getter, "@@:");

class_addmethod([person class], nsselectorfromstring(@"set***:"), (imp)setter, "v@:@");

unsigned int count;

objc_property_t *properties =class_copypropertylist([person class], &count);

for (int i = 0; i < count; i++)

person *person = [person new];

person.name = @"flyoceanfish";

[person setvalue:@"男" forkey:@"***"];

nslog(@"name:%@",person.name);

nslog(@"***:%@",[person valueforkey:@"***"]);

}return 0;

}複製**

demo位址

這裡要注意幾點:

2019-01-02 14:39:39.370405+0800 myproperty[1354:159207] 名字:***--屬性:t@"nsstring",c,n,v_***

2019-01-02 14:39:39.370425+0800 myproperty[1354:159207] 名字:name--屬性:t@"nsstring",c,n,v_name

上邊**演示了如何動態新增屬性,接下來讓我們看看蘋果底層是如何實現的。

bool

class_addproperty(class cls, const char *name,

const objc_property_attribute_t *attrs, unsigned int n)

複製**

static

bool

_class_addproperty(class cls, const

char *name,

const

objc_property_attribute_t *attrs, unsigned

int count,

bool replace)

else

if (prop)

else

}複製**

通過**我們可以看到如果新增乙個已經存在的屬性是新增不成功的; 新增乙個新屬性,是例項化了乙個property_list_t物件,最終呼叫了cls的data方法,返回了class_rw_t指標,最終新增在屬性properties的乙個陣列中。

還有乙個結構體的名字是class_ro_t,與class_rw_t是配合使用的,大家有興趣可以自行去研究。ro即read only;rw即read write。看到這裡應該能猜個**不離十

class物件結構體

struct

objc_class : objc_object

...}複製**

class_rw_t結構體

struct

class_rw_t

複製**

bool

// can only add ivars to in-construction classes.

if (!(cls->data()->flags & rw_constructing))

// check for existing ivar with this name, unless it's anonymous.

// check for too-big ivar.

// fixme check for superclass ivar too?

if ((name && getivar(cls, name)) || size > uint32_max)

class_ro_t *ro_w = make_ro_writeable(cls->data());

// fixme allocate less memory here

ivar_list_t *oldlist, *newlist;

if ((oldlist = (ivar_list_t *)cls->data()->ro->ivars)) else

uint32_t offset = cls->unalignedinstancesize();

uint32_t alignmask = (1

<-1;

offset = (offset + alignmask) & ~alignmask;

ivar_t& ivar = newlist->get(newlist->count++);

#if __x86_64__

// deliberately over-allocate the ivar offset variable.

// use calloc() to clear all 64 bits. see the note in struct ivar_t.

ivar.offset = (int32_t *)(int64_t *)calloc(sizeof(int64_t), 1);

#else

ivar.offset = (int32_t *)malloc(sizeof(int32_t));

#endif

*ivar.offset = offset;

ivar.name = name ? strdupifmutable(name) : nil;

ivar.type = strdupifmutable(type);

ivar.alignment_raw = alignment;

ivar.size = (uint32_t)size;

ro_w->ivars = newlist;

cls->setinstancesize((uint32_t)(offset + size));

// ivar layout updated in registerclass.

return yes;

}複製**

通過以上**我們可以看到通過此方法新增的屬性是例項化了ivar_t物件,並且儲存在了class_ro_t物件中了。所以跟我們上邊說的改變了類的記憶體布局一致。

我們通過乙個demo實現了動態新增屬性,通過底層原始碼解析讓大家徹底認識了class_addpropertyclass_addivar兩個方法。runtime讓oc成為了一門動態語言,只有我們想不到的,沒有runtime做不到的。

flyoceanfish

ios動態新增屬性的幾種方法

在ios執行過程中,有幾種方式能夠動態的新增屬性。1 通過runtime動態關聯物件 主要用到了objc setassociatedobject,objc getassociatedobject以及objc removeassociatedobjects objc view plain copy 在...

iOS分類新增屬性

我們可以通過runtime來給ios的分類新增屬性.1.首先我們像普通的類一樣在.h裡頭使用 property宣告乙個屬性 ch.h.這裡是 類的ch分類的.h檔案 inte ce ch property nonatomic strong nsstring name end這時,m中就會出現兩個警告...

ios 分類新增屬性。

我們都知道可以通過分類新增方法,但是是否可以新增變數有一部分人就不知道了 其實分類裡面是不可以新增成員變數的,但是卻可以新增屬性。這是因為在分類中新增的屬性不會自動生成set get方法,這是就需要自己在分類的實現檔案裡面實現屬性的set get方法,如果你跟平時一樣去寫set get方法你會發現 ...