Objective-C Runtime Classes

       Objective-C语言的许多决策可以在编译和运行时执行。只要有可能,它是动态的。这意味着Objective-C语言不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。Runtime系统是一种用于Objective-C语言的操作系统,它使OC语言工作起来。
  Runtime的核心是在运行时动态操作类和消息分发给其他对象,本文档主要介绍在运行时动态操作类。
  你可以从中学到运行时动态操作类。但是,多数情况下,我们并不需要编写Runtime系统的相关代码。
  

注意:在Runtime中,所有的char * 数据是UTF-8编码。


一、准备工作

1. 导入框架objc/runtime.h

#import < objc/runtime.h >

2. User类

User.h

//
//  User.h
//  Runtime
//
//  Created by yangjun on 15/9/21.
//  Copyright © 2015年 六月. All rights reserved.
//

#import <Foundation/Foundation.h>

/// 用户
@interface User : NSObject

@property (nonatomic, copy) NSString *userName;///< 用户名

/**
 *  初始化
 *
 *  @param userName 用户名
 *
 *  @return id
 */
- (id)initWithUserName:(NSString *)userName;

/**
 *  初始化
 *
 *  @param userName 用户名
 *
 *  @return id
 */
+ (id)userWithUserName:(NSString *)userName;

@end

User.m

//
//  User.m
//  Runtime
//
//  Created by yangjun on 15/9/21.
//  Copyright © 2015年 六月. All rights reserved.
//

#import "User.h"

@implementation User

+ (id)userWithUserName:(NSString *)userName
{
    User *user = [[User alloc] init];
    user.userName = userName;
    return userName;
}

#pragma mark 初始化
- (id)initWithUserName:(NSString *)userName
{
    self = [super init];
    if (self) {
        self.userName = userName;
    }
    return self;
}

@end

 

二、类

1.源代码

#pragma mark - 类
- (void)testClass
{
    // 获取类
    id userClass = objc_getClass("User");
    NSLog(@"%@", userClass);
    // 等价
    userClass = [User class];
    NSLog(@"%@", userClass);

    // 父类
    fprintf(stdout, "\n父类\n");
    id superUserClass = class_getSuperclass(userClass);
    NSLog(@"%@", superUserClass);
    // 等价
    superUserClass = [User new].superclass;
    NSLog(@"%@", superUserClass);

    // 更改对象的类
    fprintf(stdout, "\n更改对象的类\n");
    User *user = [User new];
    NSLog(@"类:%@ userName:%@", user, user.userName);
    userClass = object_setClass(user, [ClassTest class]);// 类替换,并返回原来的类属性
    NSLog(@"类:%@ userName:%@", user, user.userName);
}

 
2.输出
2015-09-23 10:12:52.140 Runtime[14129:681188] User
2015-09-23 10:12:52.141 Runtime[14129:681188] User

父类
2015-09-23 10:12:52.141 Runtime[14129:681188] NSObject
2015-09-23 10:12:52.141 Runtime[14129:681188] NSObject

更改对象的类
2015-09-23 10:12:52.141 Runtime[14129:681188] 类: userName:(null)
2015-09-23 10:12:52.141 Runtime[14129:681188] 类: userName:阳君

 

三、类名

1.源代码

#pragma mark - 类名
- (void)testName{
    // 获取class
    id userClass = objc_getClass("User");
    const char *className = class_getName(userClass);
    fprintf(stdout, "类名:%s\n", className);
    // 等价
    className = object_getClassName(userClass);
    fprintf(stdout, "类名:%s\n", className);
    // 等价OC
    userClass = [User class];
    NSString *name = NSStringFromClass(userClass);
    NSLog(@"类名:%@", name);
    // 底层转换
    name = [NSString stringWithCString:className encoding:NSUTF8StringEncoding];
    NSLog(@"类名:%@", name);
}

 
2.输出
类名:User
类名:User
2015-09-23 10:14:03.278 Runtime[14140:681770] 类名:User
2015-09-23 10:14:03.279 Runtime[14140:681770] 类名:User

 

四、属性

1.源代码

#pragma mark - 属性
- (void)testPropertyName
{
    // 获取所有属性
    fprintf(stdout, "获取所有属性\n");
    id userClass = objc_getClass("User");
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(userClass, &outCount);// 所有属性
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];// 属性
        const char *propertyName = property_getName(property);// 属性名
        const char *propertyAttributes = property_getAttributes(property); //属性类型
        fprintf(stdout, "%s %s\n", propertyName, propertyAttributes);
        // 等价输出
        NSLog(@"%@", [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]);
    }

    // 单一属性
    fprintf(stdout, "\n单一属性\n");
    Ivar var = class_getInstanceVariable(userClass, "_userName");
    const char *typeEncoding =ivar_getTypeEncoding(var);
    const char *ivarName = ivar_getName(var);
    fprintf(stdout, "属性名:%s; 类型:%s\n", ivarName, typeEncoding);

    // 设置/获取属性值,需要关闭ARC模式
    fprintf(stdout, "\n设置/获取属性值\n");
    User *user = [[[User alloc] init] autorelease];
    NSString *userName = @"阳君";
    object_setInstanceVariable(user, "_userName", userName);
    NSLog(@"user.userName:%@", user.userName);
    user.userName = @"开启ARC";// 修改值
    object_getInstanceVariable(user, "_userName", (void*)&userName);
    NSLog(@"user.userName:%@", userName);
}

 
2.输出
获取所有属性
userName T@”NSString”,C,N,V_userName
2015-09-23 10:18:54.365 Runtime[14155:684097] userName

单一属性
属性名:_userName; 类型:@”NSString”

设置/获取属性值
2015-09-23 10:18:54.366 Runtime[14155:684097] user.userName:阳君
2015-09-23 10:18:54.367 Runtime[14155:684097] user.userName:开启ARC

 

五、方法

1.源代码
全局方法:

NSString *classAddMethodIMP(id self, SEL _cmd, NSString *str) {
    // implementation ....
    NSLog(@"值:%@", str);
    return str;
}

NSString *userName(id self, SEL _cmd) {
    return @"OC";
}

局部方法:

#pragma mark - 方法
- (void)testMethod
{
    // 获取所有方法
    fprintf(stdout, "获取所有方法\n");
    id userClass = objc_getClass("User");
    u_int count;// unsigned int
    Method *methods= class_copyMethodList(userClass, &count);// 所有方法,只包含实例方法)
    for (int i = 0; i < count ; i++) {
        Method method = methods[i];
        SEL name = method_getName(method);// 转为方法
        const char *selName = sel_getName(name);// 转为方法名
        const char *methodTypeEncoding = method_getTypeEncoding(method);// 方法传输的参数
        char *methodType = method_copyReturnType(method);// 方法返回的类型
        fprintf(stdout, "方法名:%s; 返回类型%s; 参数:%s\n", selName, methodType, methodTypeEncoding);
    }

    // 1.提取Method(类方法)
    fprintf(stdout, "\n方法提取\n");
    SEL name = sel_registerName("userWithUserName:");
    Method method = class_getClassMethod(userClass, name);
    name = method_getName(method);
    fprintf(stdout, "提取方法(+):%s\n", sel_getName(name));
    // 2.提取Method(实例方法)
    name = sel_registerName("initWithUserName:");
    method = class_getInstanceMethod(userClass, name);
    name = method_getName(method);
    fprintf(stdout, "提取方法(-):%s\n", sel_getName(name));
    // 3.提取IMP
    IMP imp = method_getImplementation(method);
    // 只能获取(-)方法
    imp = class_getMethodImplementation(userClass, name);
    imp = class_getMethodImplementation_stret(userClass, name);
    // 等价
    User *user = [[User alloc] init];
    imp = [user methodForSelector:name];

    // 类增加方法(全局方法)
    fprintf(stdout, "\n类增加方法\n");
    name = sel_registerName("classAddMethodIMP");
    BOOL addMethod = class_addMethod(userClass, name, (IMP)classAddMethodIMP,"i@:@");
    // 判断类是否有此方法
    if (addMethod && class_respondsToSelector(userClass, name) && [user respondsToSelector:name]) {
        fprintf(stdout, "类%s添加方法%s成功\n", class_getName(userClass), sel_getName(name));
    }
    // 类添加方法(-)
    name = @selector(classAddMethod:);
    method = class_getInstanceMethod(self.class, name);// 方法体
    imp = method_getImplementation(method);// 方法的实现
    class_addMethod(userClass, name, imp, "v@:");
    // 方法调用
    id methodBack = [user performSelector:@selector(classAddMethod:) withObject:@"阳君"];
    NSLog(@"类%@调用方法%@ 返回:%@", NSStringFromClass(user.class), [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding], methodBack);

    // 方法交换
    fprintf(stdout, "\n方法交换\n");
    Method m1 = class_getInstanceMethod([self class], @selector(userName));
    Method m2 = class_getInstanceMethod([self class], @selector(userName2));
    method_exchangeImplementations(m1, m2);
    NSLog(@"%@", [self userName]);
    NSLog(@"%@", [self userName2]);

    // 方法替换
    fprintf(stdout, "\n方法替换\n");
    Method userNameMethod = class_getInstanceMethod(self.class, @selector(userName));
    IMP userNameImp = method_getImplementation(userNameMethod);
    Method setUserNameMethod = class_getInstanceMethod(self.class, @selector(userName2));
    method_setImplementation(setUserNameMethod, userNameImp);
    NSLog(@"%@", [self userName]);
    NSLog(@"%@", [self userName2]);

    // 方法覆盖,只能使用全局方法替换,方法名需要一致
    fprintf(stdout, "\n方法覆盖\n");
    NSLog(@"%@", user.userName);
    name = sel_registerName("userName");
    imp = class_replaceMethod(userClass, name, (IMP)userName,"i@:@");
    NSLog(@"%@", user.userName);
}

#pragma mark 覆盖的方法
- (NSString *)userName
{
    return @"阳君";
}

- (NSString *)userName2
{
    return @"IOS";
}

#pragma mark 增加的方法
- (NSString *)classAddMethod:(NSString *)str
{
    return str;
}

 
2.输出
获取所有方法
方法名:initWithUserName:; 返回类型@; 参数:@24@0:8@16
方法名:userName; 返回类型@; 参数:@16@0:8
方法名:setUserName:; 返回类型v; 参数:v24@0:8@16

方法提取
提取方法(+):userWithUserName:
提取方法(-):initWithUserName:

类增加方法
类User添加方法classAddMethodIMP成功
2015-09-23 10:21:19.167 Runtime[14182:685354] 类User调用方法classAddMethod: 返回:阳君

方法交换
2015-09-23 10:21:19.168 Runtime[14182:685354] IOS
2015-09-23 10:21:19.168 Runtime[14182:685354] 阳君

方法替换
2015-09-23 10:21:19.168 Runtime[14182:685354] IOS
2015-09-23 10:21:19.168 Runtime[14182:685354] IOS

方法覆盖
2015-09-23 10:21:19.169 Runtime[14182:685354] (null)
2015-09-23 10:21:19.169 Runtime[14182:685354] OC

 

源代码下载:http://download.csdn.net/detail/y550918116j/9133687

参考文献

Objective-C Runtime Reference
Objective-C Runtime Programming Guide

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值