OC&Swift runtime 一 Classes

在Swift 4中继承 NSObject 的 swift class 不再默认全部 bridge 到 OC,如果我们想要使用的话我们就需要在class前面加上@objcMembers 这么一个关键字。

方法一:class_getName
Discussion:获取类的名字
在这之前先看在NSObject里的两个方法声明

- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");
+ (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");

实例方法获取class
type(of: object) = [object class];
类方法获取class
Class.self = [Class class];
OC

const char * class_getName(Class cls);
NSLog(@"%s", class_getName([self class]));
NSLog(@"%s", class_getName([ViewController class]));

Swift

public func class_getName(_ cls: Swift.AnyClass?) -> UnsafePointer
print("\(String(cString: class_getName(type(of: self))))")
print("\(String(cString: class_getName(ViewController.self)))")

注意在Swift里返回的是UnsafePointer类型,但是我们想要的是字符串。所以用String(cString: UnsafePointer)。把UnsafePointer转成String类型。

方法二:class_getSuperclass
Discussion:获取类的父类
OC

Class class_getSuperclass(Class cls);
NSLog(@"%@", class_getSuperclass([self class]));
NSLog(@"%@", class_getSuperclass([ViewController class]));

Swift

func class_getSuperclass(_ cls: AnyClass?) -> AnyClass?
print("\(class_getSuperclass(type(of: self)))")
print("\(class_getSuperclass(ViewController.self))")

同时还可以获取object的父类,但是在NSObject的类里有一个superclass方法。(最简单的方法调用不写例子了)

方法三:class_isMetaClass
Discussion:判断是不是metaclass
OC

BOOL class_isMetaClass(Class cls);
NSLog(@"%d", class_isMetaClass(nil));

Swift

func class_isMetaClass(_ cls: AnyClass?) -> Bool
print("\(class_isMetaClass(nil))")

这个方法可以用nil。虽然OC方法的声明里没有写。nil在OC里是指向空对象的指针。

方法四:class_getInstanceSize
Discussion:返回类对象的大小
OC

size_t class_getInstanceSize(Class cls);
size_t size = class_getInstanceSize([ViewController class]);

size_t是标准C库中定义的,应为unsigned int,在64位系统中为 long unsigned int。一个是4字节一个是8字节。返回的是size_t类型。也就是说系统不同返回的可能也不同。
Swift

func class_getInstanceSize(_ cls: AnyClass?) -> Int
print("\(class_getInstanceSize(type(of: string)))")

方法五: class_getInstanceVariable
Discussion:返回一个指定的Ivar给定类的实例变量。
OC

Ivar class_getInstanceVariable(Class cls, const char *name);
NSLog(@"666%s", ivar_getName(class_getInstanceVariable(classType, "XXX")));

Swift

func class_getInstanceVariable(_ cls: AnyClass?, _ name: UnsafePointer) -> Ivar?
print("\(String(cString: ivar_getName(class_getInstanceVariable(classType, "XXX")!)!))")

这里的classType是我自己通过objc_allocateClassPair创建的类,然后class_addIvar添加的实例变量。

方法六: class_getClassVariable
Discussion:返回一个指定的Ivar给定类的类变量。
class_getClassVariable(cls, name) merely calls class_getInstanceVariable(cls->isa, name)这是一个国外大佬写的。就是说class的isa里的Ivar。class的isa是metaclass,object的isa是class。metaclass的Ivar就是isa了
OC

Ivar class_getClassVariable(Class cls, const char *name);
NSLog(@"777%s", ivar_getName(class_getClassVariable([self class], "isa")));

Swift

func class_getClassVariable(_ cls: AnyClass?, _ name: UnsafePointer) -> Ivar?
print("\(String(cString: ivar_getName(class_getClassVariable(ViewController.self, "isa")!)!))")

方法七: class_addIvar
Discussion:给一个类添加一个新的实例变量。
这个方法要使用在objc_allocateClassPair之后和objc_registerClassPair之前。说人话就是要写在这两个方法之间。(苹果没有用between)。而且这个类不能是元类。对已存在的类不能使用。
第4个参数alignment。内存对齐。这个东西大家有兴趣可以自己查。东西太多就不写了。第五个参数types。是@encode码表里的。
OC

BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, const char *types);
class_addIvar(DXArrayClass, "XXX", sizeof(NSString *), log2(sizeof(NSString *)), "@");
class_addIvar(DXArrayClass, "age", sizeof(int), log2(sizeof(int)), "i");

Swift

func class_addIvar(_ cls: AnyClass?, _ name: UnsafePointer, _ size: Int, _ alignment: UInt8, _ types: UnsafePointer?) -> Bool
class_addIvar(classType!, "XXX", MemoryLayout.size(ofValue: NSString.init()), UInt8(log2(Float.init(MemoryLayout.size(ofValue: NSString.init())))), "@")
class_addIvar(classType!, "age", MemoryLayout.size(ofValue: Int32()), UInt8(log2(Float.init(MemoryLayout.size(ofValue: NSString.init())))), "i")

这里我对swift的处理可能不太好。求指教。
方法八: class_copyIvarList
Discussion:获取一个类的实例变量数组
OC

Ivar  _Nonnull * class_copyIvarList(Class cls, unsigned int *outCount);
unsigned int i;
Ivar *array = class_copyIvarList(DXArrayClass, &i);
for (int temp = 0; temp < i; array++, temp++) {
      Ivar ivar = *array;
      NSLog(@"%s", ivar_getName(ivar));
      NSLog(@"%s", ivar_getTypeEncoding(ivar));
}

Swift

func class_copyIvarList(_ cls: AnyClass?, _ outCount: UnsafeMutablePointer?) -> UnsafeMutablePointer?
var i : UInt32 = 0
var array = class_copyIvarList(classType, &i)
var temp = 0
while temp < i {
    temp += 1
    print("\(String(cString: ivar_getName((array?.pointee)!)!))")
    array = array?.successor()
}

方法九: class_getIvarLayout
Discussion:返回一个类的ivar描述,关于是否是strong类型的
OC

const uint8_t * class_getIvarLayout(Class cls);
const uint8_t * layoutArray = class_getIvarLayout([self class]);
int j = 0;
uint8_t value_w = layoutArray[j];
while (value_w != 0x0) {
     printf("\\x%02x\n", value_w);
     value_w = layoutArray[++j];
}

看一下打印出来的数据。第一位是非strong的个数第二位是strong的个数。

\x01
\x11
\x32
\x12
\x22

翻译过来就是。非strong strong 非strong strong 非strong 非strong 非strong strong strong 非strong strong strong 非strong 非strong strong strong。
Swift

func class_getIvarLayout(_ cls: AnyClass?) -> UnsafePointer?
let point = class_getIvarLayout(ViewController.self)
if ((point?.successor()) != nil) {
     print("\(String.init(cString: point!))")
}

Swift用这个方法返回是个nil。
方法十: class_setIvarLayout

方法十一: class_getWeakIvarLayout
Discussion:返回一个类的ivar描述,关于是否是weak类型的
OC

const uint8_t * class_getWeakIvarLayout(Class cls);

Swift

func class_getWeakIvarLayout(_ cls: AnyClass?) -> UnsafePointer?

方法十二: class_setWeakIvarLayout

方法十三: class_getProperty
Discussion:返回具有给定类的给定名称的属性。
OC

objc_property_t  _Nonnull * class_copyPropertyList(Class cls, unsigned int *outCount);
NSLog(@"888%s", property_getName(class_getProperty([self class], "property_1_s")));

Swift

func class_copyPropertyList(_ cls: AnyClass?, _ outCount: UnsafeMutablePointer?) -> UnsafeMutablePointer?

方法十四: class_copyPropertyList
Discussion:
OC

objc_property_t  _Nonnull * class_copyPropertyList(Class cls, unsigned int *outCount);
objc_property_t *properties = class_copyPropertyList([self class], &i);
j = 0;
while (j < i) {
    NSLog(@"property   %s", property_getName(*properties));
    properties++;
    j++;
}

Swift

func class_copyPropertyList(_ cls: AnyClass?, _ outCount: UnsafeMutablePointer?) -> UnsafeMutablePointer?

方法十五: class_addMethod
Discussion:class_addMethod将添加父类实现的重写,但不会替换该类中的现有实现。要更改现有实现,请使用method_setImplementation。
OC

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
class_addMethod([UIApplication class], @selector(addMethodxxx:), class_getMethodImplementation([self class], @selector(addMethodxxx:)), "v@:@");

方法十六: class_getInstanceMethod
Discussion:注意,该函数可以搜索到从父类继承来且自己没重写实现的方法,而class_copyMethodList则没有。
OC

Method class_getInstanceMethod(Class cls, SEL name);
NSLog(@"%@", NSStringFromSelector(method_getName(class_getInstanceMethod([NewModel class], @selector(init)))));

方法十七: class_getClassMethod
OC

Method class_getClassMethod(Class cls, SEL name);
NSLog(@"%@", NSStringFromSelector(method_getName(class_getClassMethod([NewModel class], @selector(load)))));

方法十八: class_copyMethodList
Discussion:获取一个类的所有实现的实例方法,不能获取未被重写实现的父类的方法。
OC

Method  _Nonnull * class_copyMethodList(Class cls, unsigned int *outCount);
Method *methods = class_copyMethodList([NewModel class], &i);
j = 0;
while (j < i) {
   NSLog(@"method   %s", sel_getName(method_getName(*methods)));
    methods++;
    j++;
}
free(methods);

方法十九: class_replaceMethod
Discussion:这个函数有两种不同的表现方式:
如果名称所标识的方法还不存在,那么它就会被添加,就像调用class_addMethod一样。类型指定的类型编码被使用为给定。
如果名称所标识的方法确实存在,那么它的IMP就会被替换为method_setImplementation。类型指定的类型编码将被忽略
OC

IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types);
class_replaceMethod([self class], @selector(addMethodxxx:), class_getMethodImplementation([self class], @selector(nslogMySon)), method_getTypeEncoding(class_getInstanceMethod([self class], @selector(nslogMySon))));

Swift

func class_replaceMethod(_ cls: AnyClass?, _ name: Selector, _ imp: IMP, _ types: UnsafePointer?) -> IMP?

方法二十: class_getMethodImplementation
Discussion:class_getdimplementation可能比method_getimplem(class_getInstanceMethod(cls, name))更快。
返回的函数指针可能是运行时的函数,而不是实际的方法实现。例如,如果类的实例不响应选择器,返回的函数指针将是运行时消息转发机制的一部分。
OC

IMP class_getMethodImplementation(Class cls, SEL name);
class_getMethodImplementation([self class], @selector(addMethodxxx:))

方法二十一: class_respondsToSelector
Discussion:你通常应该使用NSObject的respondsToSelector:或者instancesRespondToSelector:方法而不是这个函数。
OC

BOOL class_respondsToSelector(Class cls, SEL sel);
NSLog(@"%d", class_respondsToSelector([self class], @selector(viewDidAppear:)));

方法二十二: class_addProtocol
OC

BOOL class_addProtocol(Class cls, Protocol *protocol);
class_addProtocol([self class], objc_getProtocol("UICollectionViewDelegate"));

方法二十三: class_addProperty
OC

BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount);
objc_property_attribute_t nonatomic = {"N", ""};
objc_property_attribute_t strong = {"&", ""};
objc_property_attribute_t type = {"T", "@\"NSString\""};
objc_property_attribute_t ivar = {"V", "_qqqqq"};
objc_property_attribute_t attributes[] = {nonatomic, strong, type, ivar};
class_addProperty([self class], "qqqqq", attributes, 4);

方法二十四: class_replaceProperty
Discussion:property = ivar + setter + getter。我们在这个方法里只替换了ivar。但是没有替换getter和setter。
OC

void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount);
    NSLog(@"666%s", property_getAttributes(class_getProperty([self class], "property_1_s")));
    objc_property_attribute_t nonatomic = {"N", ""};
    objc_property_attribute_t strong = {"&", ""};
    objc_property_attribute_t type = {"T", "@\"NSString\""};
    objc_property_attribute_t ivar = {"V", "_name"};
    objc_property_attribute_t attributes[] = {nonatomic, strong, type, ivar};
    ([self class], "property_1_s", attributes, 4);
    NSLog(@"666%s", property_getAttributes(class_getProperty([self class], "property_1_s")));

方法二十五: class_conformsToProtocol
Discussion:通常应该使用NSObject的conformsToProtocol:方法而不是这个函数。同样也是引入即可。
OC

BOOL class_conformsToProtocol(Class cls, Protocol *protocol);
NSLog(@"%d", class_conformsToProtocol([self class], objc_getProtocol("UICollectionViewDelegate")));

方法二十六: class_copyProtocolList
Discussion:这个方法里返回的protocol不需要类进行设置代理,只需要引入协议即可
OC

Protocol * _Nonnull * class_copyProtocolList(Class cls, unsigned int *outCount);
Protocol * _Nonnull __unsafe_unretained *protocolList = class_copyProtocolList([self class], &protocolCount);
    j = 0;
    while (j < protocolCount) {
        j ++;
        NSLog(@"%s", protocol_getName(*protocolList));
        protocolList ++;
    }

方法二十七: class_getVersion
OC

int class_getVersion(Class cls);
NSLog(@"%d", class_getVersion([self class]));

Swift

int class_getVersion(Class cls);
print(class_getVersion(ViewController.self))

方法二十八: class_setVersion
OC

void class_setVersion(Class cls, int version);
class_setVersion([self class], 10086);

Swift

void class_setVersion(Class cls, int version);
class_setVersion(ViewController.self, 10086)

方法二十九: objc_allocateClassPair
Discussion:第一个参数,创建类的父类,如果为nil就创建一个NSObject类似的root class。第三个参数,给0就行。要创建一个新类,首先调用objc_allocateClassPair。然后使用class_addMethod和class_addIvar之类的函数设置类的属性。构建完类后,调用objc_registerClassPair。新类现在可以使用了。应该将实例方法和实例变量添加到类本身。类方法应该添加到元类中。
OC

Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes);
Class DXArrayClass = objc_allocateClassPair([NSArray class], "DXArray", 0);

Swift

func objc_allocateClassPair(_ superclass: AnyClass?, _ name: UnsafePointer, _ extraBytes: Int) -> AnyClass?
let classType = objc_allocateClassPair(NSArray.self, "DXArray", 0)

方法三十: objc_registerClassPair
OC

void objc_registerClassPair(Class cls);
objc_registerClassPair(DXArrayClass);

Swift

func objc_registerClassPair(_ cls: AnyClass)
objc_registerClassPair(classType!)

方法三十一: objc_disposeClassPair
Discussion:删除类及其关联元类。如果存在类或任何子类的实例,则不要调用此函数。
OC

void objc_disposeClassPair(Class cls);
objc_disposeClassPair(DXArrayClass);

Swift

func objc_disposeClassPair(_ cls: AnyClass)
objc_disposeClassPair(classType!)

方法三十二: class_createInstance
Discussion:创建一个类的实例,在默认的malloc内存区域中为该类分配内存。
OC

id class_createInstance(Class cls, size_t extraBytes);

方法三十三: objc_constructInstance
Discussion:不能在ARC中使用
方法三十四:objc_destructInstance
Discussion:不能在ARC中使用

你可能感兴趣的:(OC&Swift runtime 一 Classes)