天天看點

Runtime方法的使用—Protocol、SEL篇

本篇主要是Protocol、SEL相關的方法調用

完整代碼在這裡

#pragma mark - IBAction
- (IBAction)logRunTimeAction:(id)sender {
    objc_property_attribute_t attrs[] = { { "T", "@\"NSString\"" }, { "&", "N" }, { "V", "" } };

    size_t objSize = class_getInstanceSize([_person class]);
    size_t allocSize =  * objSize;
    uintptr_t ptr = (uintptr_t)calloc(allocSize, );

    // Sel
    [self sel_getName:@selector(sel_getName:)];
    [self sel_registerName:"runtimeTestAction3"];
    [self sel_getUid:"runtimeTestAction3"];
    [self sel_isEqual:@selector(runtimeTestAction3) sel2:@selector(runtimeTestAction2)];

    // Protocol
    [self protocol_getName:protocol];
    [self protocol_getProperty:NSProtocolFromString(@"RuntimeBaseProtocol") name:"protocolString" isRequiredProperty:YES isInstanceProperty:YES];

    Protocol *testProtocol = [self objc_allocateProtocol:"TestProtocol"];
    [self protocol_addProperty:testProtocol name:"newProperty" attributes:attrs attributeCount: isRequiredProperty:YES isInstanceProperty:YES];
    [self protocol_addProtocol:testProtocol addition:protocol];
    [self protocol_addMethodDescription:testProtocol sel:@selector(runtimeTestAction3) types:"v@:" isRequiredMethod:NO isInstanceMethod:YES]; // 已注冊的協定無法添加

    [self objc_registerProtocol:testProtocol];

    [self protocol_copyPropertyList:testProtocol];
    [self protocol_copyProtocolList:testProtocol];
    [self protocol_copyMethodDescriptionList:testProtocol isRequiredMethod:NO isInstanceMethod:YES];
    [self protocol_isEqual:testProtocol other:protocol];
    [self protocol_conformsToProtocol:testProtocol other:protocol];
}

#pragma mark - SEL
/**
 *  傳回指定選擇器指定的方法的名稱
 *
 *  @param sel 方法選擇器
 *
 *  @return 方法選擇器名稱
 */
- (const char *)sel_getName:(SEL)sel {
    const char *selName = sel_getName(sel);
    NSLog(@"%s %s",__func__,selName);
    return selName;
}

/**
 *  在Objective-C Runtime系統中注冊一個方法,将方法名映射到一個選擇器,并傳回這個選擇器
 *
 *  @param name 方法名
 *
 *  @return 方法選擇器
 */
- (SEL)sel_registerName:(const char *)name {
    SEL sel = sel_registerName(name);
    [_person performSelector:sel withObject:nil afterDelay:];
    return sel;
}

/**
 *  在Objective-C Runtime系統中注冊一個方法
 *
 *  @param name 方法名
 *
 *  @return 方法選擇器
 */
- (SEL)sel_getUid:(const char *)name {
    SEL sel = sel_getUid(name);
    [_person performSelector:sel withObject:nil afterDelay:];
    return sel;

}

/**
 *  比較兩個選擇器
 *
 *  @param sel1 方法選擇器1
 *  @param sel2 方法選擇器2
 *
 *  @return 是否比對
 */
- (BOOL)sel_isEqual:(SEL)sel1 sel2:(SEL)sel2 {
    BOOL isEqual = sel_isEqual(sel1, sel2);
    if (isEqual) {
        NSLog(@"%s equal",__func__);
    }else{
        NSLog(@"%s unequal",__func__);
    }
    return isEqual;
}



#pragma mark - Protocol get: 協定;屬性;
/**
 *  傳回協定名
 *
 *  @param protocol 協定
 *
 *  @return 協定名
 */
- (const char *)protocol_getName:(Protocol *)protocol {
    const char *name = protocol_getName(protocol);
//    NSLog(@"%s %s",__func__,name);
    return name;
}

/**
 *  擷取協定的指定屬性
 *
 *  @param protocol           協定
 *  @param name               屬性名
 *  @param isRequiredProperty 是否為必須屬性
 *  @param isInstanceProperty 是否為執行個體屬性
 *
 *  @return 屬性
 */
- (objc_property_t)protocol_getProperty:(Protocol *)protocol name:(const char *)name isRequiredProperty:(BOOL)isRequiredProperty isInstanceProperty:(BOOL)isInstanceProperty{
    objc_property_t property = protocol_getProperty(protocol, name, isRequiredProperty, isInstanceProperty);
    NSLog(@"%s %s",__func__,property_getName(property));
    return property;
}

#pragma mark - Protocol add:屬性;方法;協定;
/**
 *  為協定添加屬性(隻能向未注冊的協定中添加)
 *
 *  @param protocol           協定
 *  @param name               屬性名
 *  @param attributes         屬性類型字元串
 *  @param attributeCount     屬性類型數量
 *  @param isRequiredProperty 是否為必需屬性
 *  @param isInstanceProperty 是否為執行個體屬性
 */
- (void)protocol_addProperty:(Protocol *)protocol name:(const char *)name attributes:(const objc_property_attribute_t *)attributes attributeCount:(unsigned int)attributeCount isRequiredProperty:(BOOL)isRequiredProperty isInstanceProperty:(BOOL)isInstanceProperty {
    protocol_addProperty(protocol, name, attributes, attributeCount, isRequiredProperty, isInstanceProperty);
}
/**
 *  為協定添加方法(隻能向未注冊的協定中添加)
 *
 *  @param protocol         協定
 *  @param sel              方法選擇器
 *  @param types            方法類型
 *  @param isRequiredMethod 是否為必需方法
 *  @param isInstanceMethod 是否為執行個體方法
 */
- (void)protocol_addMethodDescription:(Protocol *)protocol sel:(SEL)sel types:(const char *)types isRequiredMethod:(BOOL)isRequiredMethod isInstanceMethod:(BOOL)isInstanceMethod{
    protocol_addMethodDescription(protocol, sel, types, isRequiredMethod, isInstanceMethod);
}

/**
 *  添加一個已注冊的協定到一個未注冊的協定中(隻能向未注冊的協定中添加)
 *
 *  @param protocol 協定
 *  @param addition 被添加的已注冊的協定
 */
- (void)protocol_addProtocol:(Protocol*)protocol addition:(Protocol*)addition {
    protocol_addProtocol(protocol, addition);
}



#pragma mark - Protocol copy:協定清單;屬性清單
/**
 *  擷取協定中的屬性清單
 *
 *  @param protocol 協定
 *
 *  @return 屬性
 */
- (objc_property_t *)protocol_copyPropertyList:(Protocol *)protocol {
    unsigned int outCount;
    objc_property_t *propertyList = protocol_copyPropertyList(protocol,&outCount);
    for (int i = ; i < outCount; i++) {
        objc_property_t property = propertyList[i];
        NSLog(@"%s %s",__func__,property_getName(property));
    }
    return propertyList;
}

/**
 *  擷取協定中遵循的協定清單
 *
 *  @param protocol 協定
 *
 *  @return 協定清單
 */
- (Protocol **)protocol_copyProtocolList:(Protocol *)protocol {
    unsigned int outCount;
    Protocol **protocolList = protocol_copyProtocolList(protocol,&outCount);
    for (int i = ; i < outCount; i++) {
        Protocol *protocol = protocolList[i];
        NSLog(@"%s %s",__func__,protocol_getName(protocol));
    }
    return protocolList;
}

/**
 *  擷取協定的方法清單
 *
 *  @param protocol         協定
 *  @param isRequiredMethod 是否為必需方法
 *  @param isInstanceMethod 是否為執行個體方法
 *
 *  @return 方法清單
 */
- (struct objc_method_description *)protocol_copyMethodDescriptionList:(Protocol *)protocol isRequiredMethod:(BOOL)isRequiredMethod isInstanceMethod:(BOOL)isInstanceMethod{
    unsigned int outCount;
    struct objc_method_description *methodList = protocol_copyMethodDescriptionList(protocol, isRequiredMethod, isInstanceMethod, &outCount);
    for (int i = ; i < outCount; i++) {
        struct objc_method_description method = methodList[i];
        NSLog(@"%s %@",__func__,NSStringFromSelector(method.name));
    }
    return methodList;
}

#pragma mark - Protocol 判斷
/**
 *  測試兩個協定是否相等
 *
 *  @param protocol 協定
 *  @param other    另外一個協定
 *
 *  @return 是否相等
 */
- (BOOL)protocol_isEqual:(Protocol *)protocol other:(Protocol *)other {
    BOOL isEqual = protocol_isEqual(protocol, other);
    if (isEqual) {
        NSLog(@"%s %s equal %s ",__func__,protocol_getName(protocol),protocol_getName(other));
    }else{
        NSLog(@"%s %s unequal %s ",__func__,protocol_getName(protocol),protocol_getName(other));
    }
    return isEqual;
}

/**
 *  檢視協定是否遵循了另一個協定
 *
 *  @param protocol 協定
 *  @param other    另外一個協定
 *
 *  @return 是否遵循
 */
- (BOOL)protocol_conformsToProtocol:(Protocol *)protocol other:(Protocol *)other {
    BOOL isConform = protocol_conformsToProtocol(protocol, other);
    if (isConform) {
        NSLog(@"%s %s conform %s ",__func__,protocol_getName(protocol),protocol_getName(other));
    }else{
        NSLog(@"%s %s unconform %s ",__func__,protocol_getName(protocol),protocol_getName(other));
    }
    return isConform;
}