欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Objective-C Runtime Classes

程序员文章站 2022-06-24 23:14:06
objective-c语言的许多决策可以在编译和运行时执行。只要有可能,它是动态的。这意味着objective-c语言不仅需要一个编译器,还需要一个运行时来执行编译的代码。runtime系统是一种用...

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 

/// 用户
@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, 
父类
);
    id superuserclass = class_getsuperclass(userclass);
    nslog(@%@, superuserclass);
    // 等价
    superuserclass = [user new].superclass;
    nslog(@%@, superuserclass);

    // 更改对象的类
    fprintf(stdout, 
更改对象的类
);
    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
, classname);
    // 等价
    classname = object_getclassname(userclass);
    fprintf(stdout, 类名:%s
, 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, 获取所有属性
);
    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
, propertyname, propertyattributes);
        // 等价输出
        nslog(@%@, [nsstring stringwithcstring:propertyname encoding:nsutf8stringencoding]);
    }

    // 单一属性
    fprintf(stdout, 
单一属性
);
    ivar var = class_getinstancevariable(userclass, _username);
    const char *typeencoding =ivar_gettypeencoding(var);
    const char *ivarname = ivar_getname(var);
    fprintf(stdout, 属性名:%s; 类型:%s
, ivarname, typeencoding);

    // 设置/获取属性值,需要关闭arc模式
    fprintf(stdout, 
设置/获取属性值
);
    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, 获取所有方法
);
    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
, selname, methodtype, methodtypeencoding);
    }

    // 1.提取method(类方法)
    fprintf(stdout, 
方法提取
);
    sel name = sel_registername(userwithusername:);
    method method = class_getclassmethod(userclass, name);
    name = method_getname(method);
    fprintf(stdout, 提取方法(+):%s
, sel_getname(name));
    // 2.提取method(实例方法)
    name = sel_registername(initwithusername:);
    method = class_getinstancemethod(userclass, name);
    name = method_getname(method);
    fprintf(stdout, 提取方法(-):%s
, 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, 
类增加方法
);
    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成功
, 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, 
方法交换
);
    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, 
方法替换
);
    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, 
方法覆盖
);
    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