runtime.h-Functions-Working with Classes (二)

Working with Classes (二)

class_getIvarLayout

/** 
 * Returns a description of the \c Ivar layout for a given class.
 * 
 * @param cls The class to inspect.
 * 
 * @return A description of the \c Ivar layout for \e cls.
 */
OBJC_EXPORT const uint8_t * _Nullable
class_getIvarLayout(Class _Nullable cls)
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
const uint8_t *des = class_getIvarLayout([Person class]);
NSLog(@"%s",des);

打印了des

2020-03-08 17:03:05.219458+0800 Test-2[29215:2542044] !\^Q
Printing description of des:
(const uint8_t *) des = 0x000000010ef5849a "!\x11"

这是个什么鬼结果?这个函数返回给定的类的布局说明,这个怎么用?有什么实际性的作用吗?

class_getWeakIvarLayout

/** 
 * Returns a description of the layout of weak Ivars for a given class.
 * 
 * @param cls The class to inspect.
 * 
 * @return A description of the layout of the weak \c Ivars for \e cls.
 */
 OBJC_EXPORT const uint8_t * _Nullable
class_getWeakIvarLayout(Class _Nullable cls)
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

返回weak类型的变量的布局说明。

class_addMethod

/** 
 * Adds a new method to a class with a given name and implementation.
 * 
 * @param cls The class to which to add a method.
 * @param name A selector that specifies the name of the method being added.
 * @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.
 * @param types An array of characters that describe the types of the arguments to the method. 
 * 
 * @return YES if the method was added successfully, otherwise NO 
 *  (for example, the class already contains a method implementation with that name).
 *
 * @note class_addMethod will add an override of a superclass's implementation, 
 *  but will not replace an existing implementation in this class. 
 *  To change an existing implementation, use method_setImplementation.
 */
OBJC_EXPORT BOOL
class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
                const char * _Nullable types) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

给指定的类添加新的方法

如果返回YES表示新的方法添加成功,否则返回NO

如果本类中已经存在了一个与新的方法同名的方法实现,这个函数会放回NO

如果添加了一个同名方法,新的方法会覆盖父类的同名方法的实现,但是不会覆盖本类里面同名方法的实现

如果要修改本类中已经实现的方法,使用method_setImplementation这个函数

  • 新的方法的实现写在哪里呢?

我试了试新的方法只要写在一个类的实现里面就行

  • 第三个参数types是个什么含义?查了查网友的资料

“v@:” 意思就是这是一个void类型的方法,没有参数传入。
“i@:” 就是说这是一个int类型的方法,没有参数传入。
“i@😡” 就是说这是一个int类型的方法,有一个参数传入。

这个的获取可以通过method_getTypeEncoding(Method _Nonnull m)这个函数获取

//获取laugh的Method
Method laughMethod = class_getInstanceMethod([self class], @selector(laugh));
//获取方法的type
method_getTypeEncoding(laughMethod);

实例代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    ///给Person类添加一个laugh的方法
    //获取新方法的实现
    IMP laughIMP = class_getMethodImplementation([self class], @selector(laugh));
    //添加新方法
    BOOL isAdd = class_addMethod([Person class], @selector(laugh), laughIMP, "v@:");
    NSLog(@"isAdd %d",isAdd);
    if (isAdd) {
        //调用新添加的方法
        ((void (*)(id, SEL))objc_msgSend)(p, @selector(laugh));
    }
}

- (void)laugh {
    NSLog(@"make somebody laugh");
}

@end 

注意这里的laughIMP的获取,class_getMethodImplementation第一个参数应该是[self class],而不是[UIViewController Class],因为添加的方法是一个实例方法,是添加在self里面的。

通过laughMethod直接可以获取到方法的实现和方法的编码类型

///给Person类添加一个laugh的方法
//获取laugh的Method
Method laughMethod = class_getInstanceMethod([self class], @selector(laugh));
//获取新方法的实现
IMP laughIMP = method_getImplementation(laughMethod);
//添加新方法
BOOL isAdd = class_addMethod([Person class], @selector(laugh), laughIMP, method_getTypeEncoding(laughMethod));
NSLog(@"isAdd %d",isAdd);
if (isAdd) {
    //调用新添加的方法
    ((void (*)(id, SEL))objc_msgSend)(p, @selector(laugh));
}

怎么添加一个类方法呢?

class_replaceMethod

OBJC_EXPORT IMP _Nullable
class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
                    const char * _Nullable types) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
  • @note This function behaves in two different ways:
    • If the method identified by \e name does not yet exist, it is added as if \c class_addMethod were called.
  • The type encoding specified by \e types is used as given.
    • If the method identified by \e name does exist, its \c IMP is replaced as if \c method_setImplementation were called.
  • The type encoding specified by \e types is ignored.

如果方法不存在则添加,存在则替换。

简单的方法替换不用多说,关于方法替换在开发中的实际用途网上很多博客,可以学习学习。

class_addIvar

OBJC_EXPORT BOOL
class_addIvar(Class _Nullable cls, const char * _Nonnull name, size_t size, 
              uint8_t alignment, const char * _Nullable types) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

给一个类添加实例变量

如果该变量已存在,则返回NO,添加成功返回YES

该类必须是一个元类,因为元类里存储实例变量

This function may only be called after objc_allocateClassPair and before objc_registerClassPair 这两个方法的调用机制是什么呢?

class_addProtocol

OBJC_EXPORT BOOL
class_addProtocol(Class _Nullable cls, Protocol * _Nonnull protocol) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

添加协议

class_addProperty

OBJC_EXPORT BOOL
class_addProperty(Class _Nullable cls, const char * _Nonnull name,
                  const objc_property_attribute_t * _Nullable attributes,
                  unsigned int attributeCount)
    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);

给一个类添加属性。这里属性和变量要区分开,_属性名是一个变量,在OC里,属性最终的存储都是以变量的形式存储的。

添加属性和添加变量在开发中我没有想到有什么具体的使用场景,能否给一个SDK里的类动态的添加一个属性或者变量呢?为了达到某种目的,应该是可以的我觉得。

class_replaceProperty

OBJC_EXPORT void
class_replaceProperty(Class _Nullable cls, const char * _Nonnull name,
                      const objc_property_attribute_t * _Nullable attributes,
                      unsigned int attributeCount)
    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);

不用说了。

class_setIvarLayout

OBJC_EXPORT void
class_setIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

这个变量的Layout是个什么东西一直没有搞懂过

class_setWeakIvarLayout

OBJC_EXPORT void
class_setWeakIvarLayout(Class _Nullable cls, const uint8_t * _Nullable layout)
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

objc_getFutureClass

/** 
 * Used by CoreFoundation's toll-free bridging.
 * Return the id of the named class.
 * 
 * @return The id of the named class, or an uninitialized class
 *  structure that will be used for the class when and if it does 
 *  get loaded.
 * 
 * @warning Do not call this function yourself.
 */
 OBJC_EXPORT Class _Nonnull
objc_getFutureClass(const char * _Nonnull name) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0)
    OBJC_ARC_UNAVAILABLE;

warning Do not call this function yourself

OBJC_ARC_UNAVAILABLE

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Morris_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值