之前一篇文章《ios關聯物件》詳細介紹了如何通過關聯物件新增屬性,本篇文章將介紹如何通過runtime的class_addproperty
或class_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_addproperty
和class_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方法你會發現 ...