文章目录
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