runtime動(dòng)態(tài)創(chuàng)建類(lèi)

這里舉個(gè)簡(jiǎn)單的例子來(lái)介紹一下如何動(dòng)態(tài)創(chuàng)建類(lèi)(Student):

 const char * className;
    className = [@"Student" UTF8String];
    Class kclass = objc_getClass(className);
    //判斷此類(lèi)是否已經(jīng)存在,如果存在則返回澄阳,不存在就創(chuàng)建
    if (!kclass)
    {
        Class superClass = [NSObject class];
        kclass = objc_allocateClassPair(superClass, className, 0);
    }
    else return;

為Student添加一個(gè)NSString類(lèi)型的成員變量stuName

//為類(lèi)添加成員變量
    class_addIvar(kclass, "_stuName", sizeof(NSString *), 0, "@");

為Student添加一個(gè)say:方法
這里第一個(gè)參數(shù)為類(lèi)名宵晚,第二個(gè)參數(shù)為方法名瓢谢,第三個(gè)參數(shù)是函數(shù)名窍帝,第四個(gè)參數(shù)是函數(shù)的返回值和參數(shù)的類(lèi)型勋锤,v表是void,@表示id,:表示SEL,定義參考

//為類(lèi)添加方法  
    class_addMethod([kclass class], @selector(say:), (IMP)say, "v@:");

需要實(shí)現(xiàn)這個(gè)方法

//這個(gè)方法實(shí)際上沒(méi)有被調(diào)用,但是必須實(shí)現(xiàn)否則不會(huì)調(diào)用下面的函數(shù)
- (void)say:(NSString *)aString
{
}

//self和_cmd是必須的骇塘,在之后可以隨意添加其他參數(shù)
void say(id self,SEL _cmd,NSString *aString)
{
    NSLog(@"你好%@",aString);
}

為Student添加一個(gè)stuSex屬性

NSString *propertyName = @"stuSex";
    objc_property_attribute_t type = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership = { "C", "copy" };
    objc_property_attribute_t backingivar  = { "V", [propertyName UTF8String]};
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    BOOL isOk=class_addProperty(kclass, [propertyName UTF8String], attrs, 3);

然后注冊(cè)這個(gè)類(lèi)

objc_registerClassPair(kclass);

然后調(diào)用一下試試

id p = [[kclass alloc] init];
[p setValue:@"張三" forKey:@"stuName"];
 [p setValue:@"男" forKey:@"stuSex"];
NSLog(@"%@",[p valueForKey:@"stuSex"]);
 NSLog(@"%@",[p valueForKey:@"stuName"]);
    [p say:[p valueForKey:@"stuName"]];

此時(shí)程序是會(huì)出錯(cuò)的捉片。因?yàn)榇藭r(shí)屬性是不可以調(diào)用setValue:forKey:方法的,為此我在網(wǎng)上找了很多資料艺骂,大部分都是說(shuō)需要自己去添加方法如下:

    class_addMethod(kclass,@selector(stuSex), (IMP)Getter, "@@:");
    class_addMethod(kclass,@selector(setStuSex:), (IMP)Setter, "v@:@");

//在創(chuàng)建類(lèi)的時(shí)候再添加上面兩個(gè)方法诸老。然后去實(shí)現(xiàn)這兩個(gè)方法

- (void)setStuSex:(NSString *)stuSex
{
    
}
- (NSString *)stuSex
{
    return nil;
}
NSString * Getter(id self1,SEL _cmd1){
    NSString * var=NSStringFromSelector(_cmd1);
    Ivar ivar=class_getInstanceVariable([self1 class], [var cStringUsingEncoding:NSUTF8StringEncoding]);
    return object_getIvar(self1, ivar);
}

void Setter(id self1,SEL _cmd1,NSString* newObject){
    NSString * var=[NSStringFromSelector(_cmd1) stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""];
    NSString * head=[var substringWithRange:NSMakeRange(0, 1)];
    head=[head lowercaseString];
    var=[var stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:head];
    var=[var stringByReplacingCharactersInRange:NSMakeRange([var length]-1, 1) withString:@""];
    Ivar ivar=class_getInstanceVariable([self1 class], [var cStringUsingEncoding:NSUTF8StringEncoding]);
    id oldName=object_getIvar(self1, ivar);
    if (oldName!=newObject) {
        object_setIvar(self1, ivar, [newObject copy]);
    }
}

然后去調(diào)用這兩個(gè)方法以達(dá)到賦值和取值的目的

[p setStuSex:@"男"];
    NSLog(@"%@",[p stuSex]);

結(jié)果是空

屏幕快照 2016-05-13 下午6.34.47.png

那么該如何解決這個(gè)問(wèn)題呢。其實(shí)是因?yàn)樵谔砑訉傩缘臅r(shí)候需要關(guān)聯(lián)一個(gè)成員變量钳恕,所以我們需要再去聲明這個(gè)成員變量别伏,并在添加屬性的時(shí)候去關(guān)聯(lián)它:

NSString *propertyName = @"stuSex";
//在這里添加這么一句就可以了
    class_addIvar(kclass, [propertyName UTF8String], sizeof(NSString *), 0, "@");
    objc_property_attribute_t type = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership = { "C", "copy" };
    objc_property_attribute_t backingivar  = { "V", [propertyName UTF8String]};
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    
    BOOL isOk=class_addProperty(kclass, [propertyName UTF8String], attrs, 3);

結(jié)果顯示如下:


屏幕快照 2016-05-13 下午6.38.35.png

如果在添加屬性的時(shí)候先添加一個(gè)成員變量并進(jìn)行關(guān)聯(lián),此時(shí)我們是不需要再去添加別的方法也可以使用setValue:forKey:的,所以說(shuō)在添加屬性時(shí)是必需要關(guān)聯(lián)到一個(gè)成員變量上的忧额,結(jié)合iOS反射機(jī)制: objc_property_t的使用可知我們?cè)谑褂聾property時(shí)應(yīng)該是已經(jīng)幫我們關(guān)聯(lián)了一個(gè)成員變量厘肮。
所有代碼如下:

- (void)createClass
{
    const char * className;
    className = [@"Student" UTF8String];
    Class kclass = objc_getClass(className);
    //判斷此類(lèi)是否已經(jīng)存在,如果存在則返回宙址,不存在就創(chuàng)建
    if (!kclass)
    {
        Class superClass = [NSObject class];
        kclass = objc_allocateClassPair(superClass, className, 0);
    }
    else return;
    //為類(lèi)添加成員變量
    class_addIvar(kclass, "_stuName", sizeof(NSString *), 0, "@");
    //為類(lèi)添加方法
    class_addMethod([kclass class], @selector(say:), (IMP)say, "v@:");
    
    NSString *propertyName = @"stuSex";
    class_addIvar(kclass, [propertyName UTF8String], sizeof(NSString *), 0, "@");
    objc_property_attribute_t type = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership = { "C", "copy" };
    objc_property_attribute_t backingivar  = { "V", [propertyName UTF8String]};
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    
    BOOL isOk=class_addProperty(kclass, [propertyName UTF8String], attrs, 3);
//    class_addMethod(kclass,@selector(stuSex), (IMP)Getter, "@@:");
//    class_addMethod(kclass,@selector(setStuSex:), (IMP)Setter, "v@:@");
//    
    NSLog(@"add property =%d",isOk);
    objc_registerClassPair(kclass);

    id p = [[kclass alloc] init];
    [p setStuSex:@"男"];
    NSLog(@"%@",[p stuSex]);
    [p setValue:@"張三" forKey:@"stuName"];
    [p setValue:@"男" forKey:@"stuSex"];
    NSLog(@"%@",[p valueForKey:@"stuSex"]);
    NSLog(@"%@",[p valueForKey:@"stuName"]);
    [p say:[p valueForKey:@"stuName"]];
    NSLog(@"%@",[p valueForKey:@"stuSex"]);
}
- (void)setStuSex:(NSString *)stuSex
{
    
}
- (NSString *)stuSex
{
    return nil;
}
//這個(gè)方法實(shí)際上沒(méi)有被調(diào)用,但是必須實(shí)現(xiàn)否則不會(huì)調(diào)用下面的方法
- (void)say:(NSString *)aString
{
    
}
//self和_cmd是必須的轴脐,在之后可以隨意添加其他參數(shù)
void say(id self,SEL _cmd,NSString *aString)
{
    NSLog(@"你好%@",aString);
}


//NSString * Getter(id self1,SEL _cmd1){
//    NSString * var=NSStringFromSelector(_cmd1);
//    Ivar ivar=class_getInstanceVariable([self1 class], [var cStringUsingEncoding:NSUTF8StringEncoding]);
//    return object_getIvar(self1, ivar);
//}
//
//void Setter(id self1,SEL _cmd1,NSString* newObject){
//    NSString * var=[NSStringFromSelector(_cmd1) stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""];
//    NSString * head=[var substringWithRange:NSMakeRange(0, 1)];
//    head=[head lowercaseString];
//    var=[var stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:head];
//    var=[var stringByReplacingCharactersInRange:NSMakeRange([var length]-1, 1) withString:@""];
//    Ivar ivar=class_getInstanceVariable([self1 class], [var cStringUsingEncoding:NSUTF8StringEncoding]);
//    id oldName=object_getIvar(self1, ivar);
//    if (oldName!=newObject) {
//        object_setIvar(self1, ivar, [newObject copy]);
//    }
//}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子大咱,更是在濱河造成了極大的恐慌恬涧,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碴巾,死亡現(xiàn)場(chǎng)離奇詭異溯捆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)厦瓢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)提揍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人煮仇,你說(shuō)我怎么就攤上這事劳跃。” “怎么了浙垫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵刨仑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我夹姥,道長(zhǎng)杉武,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任辙售,我火速辦了婚禮轻抱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旦部。我一直安慰自己祈搜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布志鹃。 她就那樣靜靜地躺著夭问,像睡著了一般。 火紅的嫁衣襯著肌膚如雪曹铃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天捧杉,我揣著相機(jī)與錄音陕见,去河邊找鬼。 笑死味抖,一個(gè)胖子當(dāng)著我的面吹牛评甜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仔涩,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼忍坷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起佩研,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柑肴,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后旬薯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體晰骑,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年绊序,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了硕舆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骤公,死狀恐怖抚官,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阶捆,我是刑警寧澤凌节,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站趁猴,受9級(jí)特大地震影響刊咳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜儡司,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一娱挨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捕犬,春花似錦跷坝、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至垢粮,卻和暖如春贴届,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜡吧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工毫蚓, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人昔善。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓元潘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親君仆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子翩概,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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