Runtime

1.歸檔與反歸檔

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "Dog.h"
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *gender;
@property (nonatomic, strong) NSNumber *age;
@property (nonatomic, assign) NSInteger weight;
@property (nonatomic, strong) Dog *dog;
+ (Person *)personWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age weight:(NSInteger)weight;
- (void)getPersonMessage;
- (void)walkonTheStreet:(NSString *)str;
@end
#import "Person.h"
#import <objc/runtime.h>// 導(dǎo)入<objc/runtime.h>
@interface Person ()<NSCoding>
@end

@implementation Person
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    unsigned int outCount;
    Ivar *ivarList = class_copyIvarList([Person class], &outCount);
    for (NSInteger i = 0; i < outCount; i++) {  // 采用for循環(huán)遍歷屬性,無需一一歸檔
        const char *cName = ivar_getName(ivarList[i]);
        NSString *name = [NSString stringWithUTF8String:cName];
        [aCoder encodeObject:[self valueForKey:name] forKey:name];
    }   
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        unsigned int outCount;
        Ivar *ivarList = class_copyIvarList([Person class], &outCount);
        for (NSInteger i = 0; i < outCount; i++) { // 采用for循環(huán)遍歷屬性,無需一一反歸檔
            const char *cName = ivar_getName(ivarList[i]);
            NSString *name = [NSString stringWithUTF8String:cName];
            [self setValue:[aDecoder decodeObjectForKey:name] forKey:name];
        }
    }
    return  self;
}

如下方法

Ivar *class_copyIvarList(Class cls, unsigned int *outCount)      //獲取所有成員變量
 const char *ivar_getName(Ivar v)            //獲取某個(gè)成員變量的名字
 const char *ivar_getTypeEncoding(Ivar v)   //獲取某個(gè)成員變量的類型編碼
 Ivar class_getInstanceVariable(Class cls, const char *name)    //獲取某個(gè)類中指定名稱的成員變量
 id object_getIvar(id obj, Ivar ivar)    //獲取某個(gè)對象中的某個(gè)成員變量的值
 void object_setIvar(id obj, Ivar ivar, id value)    //設(shè)置某個(gè)對象的某個(gè)成員變量的值
 TypeEncoding:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1  // 編碼形式

打印實(shí)例變量

- (NSString *)description
{
    /*
     * class: 要獲取的某個(gè)類, outCount: 通過這一個(gè)函數(shù)執(zhí)行之后會(huì)將成員變量的個(gè)數(shù)賦值到此
     */
    unsigned int outCount;
    Ivar *ivarList = class_copyIvarList([Person class], &outCount);
    for (NSInteger i = 0; i < outCount; i ++) {
//        每次獲取一個(gè)成員變量
        Ivar ivar = ivarList[i];
//        打印成員變量的名字和類型編碼
        NSLog(@"name = %s, type = %s",ivar_getName(ivar), ivar_getTypeEncoding(ivar));
    }
    return nil;
}

2.消息轉(zhuǎn)發(fā)

OC的消息發(fā)送機(jī)制根據(jù)方法名來尋找聲明完成的實(shí)例方法的實(shí)現(xiàn)方法,當(dāng)類中的方法只聲明而未實(shí)現(xiàn)時(shí),系統(tǒng)會(huì)在逐級父類中尋找方法的實(shí)現(xiàn),當(dāng)父類中均無方法的實(shí)現(xiàn)時(shí), 系統(tǒng)會(huì)執(zhí)行以下方法,故可為未實(shí)行的方法進(jìn)行消息轉(zhuǎn)發(fā),添加實(shí)現(xiàn)
1    + resolveInstanceMethod:(SEL)sel      // 為一個(gè)實(shí)例方法動(dòng)態(tài)添加實(shí)現(xiàn)
+ resolveClassMethod:(SEL)sel      //   為一個(gè)類方法動(dòng)態(tài)添加實(shí)現(xiàn)
2     - (id)forwardingTargetForSelector:(SEL)aSelector
//為沒有實(shí)現(xiàn)的方法指定一個(gè)對象
3     - (void)forwardInvocation:(NSInvocation *)anInvocation
//子類重載這個(gè)方法為消息指定其他對象

a. 為一個(gè)實(shí)例方法動(dòng)態(tài)添加實(shí)現(xiàn)

+ (BOOL)resolveInstanceMethod:(SEL)sel 
{
   //    將方法轉(zhuǎn)換為字符串
    NSString *selString = NSStringFromSelector(sel);
    if ([selString isEqualToString:@"walkonTheStreet:"]) {
     //   為一個(gè)沒有實(shí)現(xiàn)的方法動(dòng)態(tài)添加實(shí)現(xiàn)
        /* cls: 類
         name: 沒有實(shí)現(xiàn)的方法
         IMP: 要添加的實(shí)現(xiàn)
         types: 動(dòng)態(tài)添加的實(shí)現(xiàn)的類型編碼*/
        class_addMethod(self, @selector(walkonTheStreet:), (IMP)walkFunc, "V@:@");  // void的編碼為 V,  SEL的編碼為 :
    }
    return [super resolveInstanceMethod:sel];
}

void walkFunc(id self,SEL sel, NSString *str){
    NSLog(@"Person---%s------%@", __func__, str);
}

b. 為沒有實(shí)現(xiàn)的方法指定一個(gè)對象

方式1
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    NSString *selString = NSStringFromSelector(aSelector);
   if ([selString isEqualToString:@"walkonTheStreet:"]) {
       self.dog = [Dog new];
       return self.dog;
   }
    return [super forwardingTargetForSelector:aSelector];
}
方式2
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([Dog instanceMethodSignatureForSelector:anInvocation.selector]) {
        self.dog = [Dog new];
        [anInvocation invokeWithTarget:self.dog];
    }
}

// 給方法制定一個(gè)有效的簽名

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
    if (!methodSignature) {
        methodSignature = [Dog instanceMethodSignatureForSelector:aSelector];
    }
    return methodSignature;
}

3.給類目添加實(shí)例變量

延展可為類添加屬性和方法, 但外界不可訪問; 類目可為類添加方法,但無法添加實(shí)例變量, 采用runtime可為類目添加外界可訪問的實(shí)例變量
#import <Foundation/Foundation.h>
@interface NSDictionary (Mydict)
@property (nonatomic,strong) NSString *name;
@end
#import "NSDictionary+Mydict.h"
#import <objc/runtime.h>
@implementation NSDictionary (Mydict)

/*
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)     //為某個(gè)類關(guān)聯(lián)某個(gè)對象
id objc_getAssociatedObject(id object, const void *key)
//獲取到某個(gè)類的某個(gè)關(guān)聯(lián)對象
void objc_removeAssociatedObjects(id object) //移除已經(jīng)關(guān)聯(lián)的對象
*/
// 關(guān)聯(lián)后此屬性name在外界可以訪問,并且通過移除對象方法隨時(shí)移除
- (void)setName:(NSString *)name
{
//    objc: 要關(guān)聯(lián)的對象  key: 成員變量對應(yīng)的key值
//    @selector(屬性名) value: value
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);  // set方法
}

- (NSString *)name
{
    return objc_getAssociatedObject(self, @selector(name));  //get方法
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄 Objective-C Runtime到底是什么 Objective-C的元素認(rèn)知 Runtime詳解 應(yīng)用...
    Ryan___閱讀 2,011評論 1 3
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡介 Runt...
    樂樂的簡書閱讀 2,249評論 0 9
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,887評論 33 466
  • 1.理解NSObject和元類 1.1 在OC中的對象和類是什么 對象是在objc.h中定義的 類是在runtim...
    HWenj閱讀 982評論 0 3
  • 文中的實(shí)驗(yàn)代碼我放在了這個(gè)項(xiàng)目中。 以下內(nèi)容是我通過整理[這篇博客] (http://yulingtianxia....
    茗涙閱讀 1,028評論 0 6

友情鏈接更多精彩內(nèi)容