Objective-C Runtime

描述macOS OC运行时库支持的函数和数据结构.

通览

OC运行时是一个运行时库,该库用来支持OC语言的动态属性.并且这种情况对所有的的Objectiv-C的app都有关系.OC运行时库支持的函数实现在 /usr/lib/libobjc.A.dylib中的分享库中可以查到.(自己测试是在资源库文件夹下面)

在OC编程中,您完全没有必要直接地使用OC运行时库.这些Api的主要作用是作为OC和其他语言的桥接层.或者更底层的调试.

OC运行时库在macOS 中的实现是特殊的.对于其他平台,GNU编译集合使用类似的Api提供了一种不同的的实现.这个文档只包含了macOS的实现.

底层的OC运行时Api在OS X 版本10.5中做了显著更新.许多函数和所有现有的数据结构被替换为新的函数.老的函数和数据结构在32位模式下被弃用.64位模式下仍然存在.Api在64位模式下约束了一些在32位模式下表示的整型数据值.比如 class Count, protocol Count, methods per class, ivars per class, arguments per method, sizeof(all arguments) per method, class version number.另外,新的Objective-C ABI 对32位模式下的对象实例化约束更多.并且三个其他的24位模式下表示的一些值 methods per class, ivars per class, sizeof(a single ivar).最后,
老式的NXHashTable和NXMapTable被限制到四百万项.

字符串编码
在运行时API中所有的字符指针应该
被看作UTF-8编码格式.

该文档适用哪些人?

这个文档适用那些对OC运行时有兴趣学习的读者.
因为这不是关于C的文档.该文档仅当做对OC开发者的一些拓展.

Topics

与Class一起使用


    /*
     cls: 一个类对象
     返回值: 类的名称,如果传Nil则为空字符串
     **/

    func class_getName(_ cls:AnyClass?) -> UnsafePointer
    
    /*
     cls: 一个类对象
     返回值: 该类的父类. 如果cls为根类或者cls为Nil的话,返回值为Nil
     
     讨论:
     你应该通常使用NSObject的 superclass()方法替换该方法
     **/

    func class_getSuperclass(_ cls: AnyClass?) -> AnyClass?
    
    /*
     返回一个布尔值, 该值表示是否一个类对象是一个元类
     
     cls: 一个类对象
     返回值: 如果参数是一个元类,则返回true. 如果非元类,则返回false,或者参数为Nil也返回false.
    
     **/

    func class_isMetaClass(_ cls: AnyClass?) -> Bool

    /*
     返回一个类的实例占用内存的大小
     
     cls: 一个类对象
     返回值: 类实例的占用的字节.如果参数为Nil则返回0
    **/

    func class_getInstanceSize(_ cls: AnyClass?) -> Int
    
    
    /*
     返回给定类的一个指定实例变量
     
     cls: 想要获取实例变量的类
     name: 去获取的实例变量名
     返回值: 指定名字的实例变量的指针
    **/

    func class_getInstanceVariable(_ cls: AnyClass?, _ name: UnsafePointer) -> Ivar?
    
    /*
     返回某个类指定名字的类变量
     
     cls: 要获取类变量的类
     name: 要获取的类变量名称
     返回值: 指定名字的类变量的指针
    **/

    func class_getClassVariable(_ cls: AnyClass?, _ name: UnsagePointer) ->Ivar?
    
    /*
     给一个类添加一个实例变量
     
     返回值: 如果实例变量加入成功,返回true.否则返回false(比如该类已经包含一个相同名字的实例变量)
     
     讨论:
     这个函数只能在objc_allocateClassPair(_:_:_:)之后调用.在objc_registerClassPair(_:)之前调用.不支持给一个已经注册过的类添加实例变量.
     
     操作的类不能使元类.不支持给一个元类添加实例变量.
     
     实例变量以字节的最小对齐方式为1<, _ size: Int, _ alignment: UInt8, _ types: UnsagePointer?) -> Bool
    
    /*
     获取类的实例变量列表
     
     cls: 需要拷贝属性列表的类
     outCount: 在返回时,包含返回数组的长度.如果outCount是NULL,则不反悔该长度.
     返回值: 一个指针数组描述类声明的实例变量.任何被父类声明的实例变量不包含在内.数组包含* outCount指针,后跟一个空终止符。您必须使用free()函数释放数组.
     如果类声明中没有实例变量.或者cls为Nil,则返回NULL 并且*coutCount指针为0
     **/

    func class_copyIvarList(_ cls: AnyClass?, _ outCount: UnsafeMutablePointer?) -> UnsafeMutablePointer?
    
    //返回指定类实例变量布局的描述
    func class_getIvarLayout(AnyClass?)
    
    //设置指定类实例变量布局
    func class_setIvarLayout(AnyClass?, UnsafePointer?)
    
    //返回弱引用实例变量的布局描述
    func class_getWeakIvarLayout(AnyClass?)
    
    //设置弱引用实例变量的布局
    func class_setWeakIvarLayout(AnyClas?, UnsafePointer?)
    
    /*
     返回指定类的指定名称的属性
     
     返回值: 一个objc_property_t类型的指针.如果类中并未声明该名称属性或者cls为Nil则返回NULL.
     **/
    func class_getProperty(_ cls: AnyClass?, _ name: UnsafePointer) -> objc_property_t?
    
    /*
     描述声明的一个类的属性
     
     cls: 想要检查的类
     outCount: 在返回时,包含返回数组的长度.如果outCount 是NULL,数组长度不返回.
     返回值: objc_property_t类型的指针数组.任何父类声明的属性不包含在内.数组包含* outCount指针,后跟一个空终止符。您必须使用free()函数释放数组.
     如果类声明中没有实例变量.或者cls为Nil,则返回NULL 并且*coutCount指针为0
     **/

    func class_copyPropertyList(_ cls: AnyClass?, _ outCount: UnsageMutablePointer?) -> UnsafeMutablePointer?
    
    /*添加一个新方法给指定类.指定方法名和方法实现
    
      cls:需要添加方法的类 
      name: 指定添加的方法名  
      imp: 方法的实现的函数,该函数必须携带两个参数 self 和  _cmd
      types: 一个字符数组,用来描述方法的参数类型.参考苹果官方文档 [Type Encodings](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100)
      返回值: 如果添加成功,返回true 否则返回false(例如添加的方法已经存在)
      
      讨论:
      该方法会重载父类的实现,但是并不会替换在这个类中已经存在的实现.想要改变已经存在的实现的话,使用method_setImplementation(_:_:)
      一个OC方法仅仅是一个C的函数.该函数携带至少两个参数----self 和 _cmd.举例,给定下列函数
    
      void myMethodIMP(id self, SEL _cmd)
      {
        //implementation ...
        
      }
      
      您可以动态添加该函数到一个类中作为一个方法.(调用 resolveThisMethodDynamically) 像这样:
      
      class_addMethod([self class], @selector(resolveThisMethodDynamically), (IMP) myMethodIMP, "v@:");
      
     **/

    func  class_addMethod(_ cls:AnyClass?,_ name:Selector,_ imp:IMP,_ types: UnsagePointer?)
    
    /*
     获取一个类的指定实例方法
     
     aClass: 要检查的类
     aSelector: 要获取方法的选择器
     返回值: 指定方法选择器所对应的方法实现,如果指定类或者它的父类不包含指定选择器的实例方法则返回NULL.
     
     讨论:
     注意这个函数搜索父类的实现,而class_copyMethodList(_:_:)是不会的
     **/

    func class_getInstanceMethod(_ cls:AnyClass?,_ name: Selector) -> Method?
    
    /*
     返回指定类指定名称的类方法
     
     aClass: 一个雷定义的指针.该类包含您想要获取的方法.
     aSelector: 一个SEL类型的指针.该SEL包含你想要获取的方法.
     返回值: Method的指针.对应指定类指定方法选择器的实现.如果该类或者它的父类不包含这个类方法,则返回NULL.
     
     讨论:
     注意这个函数搜索父类的方法实现.class_copyMethodList(_:_:)不搜索
     **/

     func class_getClassMethod(_ cls: AnyClass?, _ name: Selector) -> Method?
     
    /*
     返回一个类的实例方法列表
     
     cls: 想要检测的类
     outCount: 在返回时,包含数组的长度.如果outCounte是NULL,则不返回.
     返回值: Method类型的指针数组.表示该类所有的实例方法实现.
     不包含父类的实例方法实现.该数组包含*outCount指针后面跟一个空终止符.您必须使用free()函数释放该数组.
     
     如果该类没有实例方法.或者该类为Nil,则返回NULL并且*outCount是0
     
     讨论:
     
     获取一个类的类方法列表.使用class_copyMethodList(object_getClass(cls), &count)
     获取父类的方法列表,使用class_getInstanceMethod(_:_:)或者class_getClassMehtod(_:_:)
     **/

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

    /*
     替换指定类的方法的实现
     
     cls:要修改的类
     name: 一个方法选择器用来确认哪个方法实现要被替换
     imp:新的方法实现.
     types: 一个字符串集合,用来描述参数的类型.必须至少携带两个参数, self 和_cmd, 第二个和第三个字符必须为"@:"(第一个参数为返回类型)
     
     返回值: 修改的类之前的方法实现.
     
     讨论:
    可以通过两种方式实现该函数行为:
    如果方法名不存在,通过call_addMethod(_:_:_:_:)方法的调用添加函数实现.按照types添加参数类型和返回值类型.
    如果方法名存在,他的IMP通过method_setImplementation(_:_:)方法的调用来替换函数实现.types参数被忽略.
    
     **/

    func class_replaceMethod(_ cls:AnyClass?, _ name: Selector,_ imp: IMP, _ types: UnsafePointer?) -> IMP?
    
    /*
     获取指定实例方法的实现
    
     cls: 指定类
     name: 方法选择器
     返回值: 返回函数指针,如果cls为Nil,则返回NULL.
     
     讨论:
     
     class_getMethodImplementation(_:_:)可能会比method_getImplementtation(class_getInstanceMethod(cls, name))更快一些.
     
     返回的函数指针可能是运行时的函数,而不是实际的方法实现。例如,如果类的实例不响应选择器,那么返回的函数指针将是运行时消息转发机制的一部分。
     **/ 

    func class_getMethodImplementation(_ cls: AnyClass?,_ name: Selector) -> IMP?
    
    /*
     返回将要被调用的指定消息的函数指针
     
     cls: 指定的类
     name: 一个方法选择器
     返回值: 返回函数指针,如果cls为Nil,则返回NULL.
     **/ 

    func class_getMethodImplementation_stret(_ cls: AnyClass?,_ name: Selector) -> IMP?
    
    /*
    返回一个布尔值表示是否一个实例响应了指定方法
    
    cls : 响应消息的类
    sel : 一个方法选择器
    返回值: 响应方法,则返回true,否则返回false
    
    讨论:
    通常使用NSObject的responds(to:)或者instancesRespond(to:)方法来替换该方法.
     **/
    func class_respondsToSelector(AnyClass?, Selector)

    /*
     给一个类添加一个协议
     
     cls: 要改动的类
     outCount: 要添加到该类的协议
     返回值: 添加成功,返回ture;否则false(比如该类中已经存在该协议)
    
     **/
    func class_addProtocol(_ cls: AnyClass?, _ protocol: Protocol) -> Bool
    
    /*
     给一个类添加一个属性
     
     cls: 要改动的类
     name: 属性名
     attributes: 属性的描述(readonly, nonatomic, asign...)
     attributeCount: 属性描述的数量
     返回值: 添加成功,返回true,否则false(比如已经存在该属性)
     **/

    func class_addProperty(_ cls: AnyClass?, _ name: UnsagePointer, _ attributes: UnsafePointer?, _ attributeCounte: UInt32) -> Bool
    
    /*
     替换一个类的属性
     **/
    func class_replaceProperty(_ cls:AnyClass?, _ name: UnsafePointer, _ attributes: UnsafePointer?, _ attrubuteCount: UInt32)
    
    /*
     返回一个布尔值 表示是否一个类执行指定协议方法
     
     通常使用NSObject的conforms(to:) 来替换它
     **/

    func class_conformsToProtocol(_ cls: AnyClass?,_ protocol: Protocol?) -> Bool
    /*
     描述一个类包含的协议
     cls: 指定的类
     outCount: 返回数组的长度.如果outCount是NULL,返回值不包含数组的长度.
     返回值: Protocol* 类型的指针数组.描述类中包含的协议.父类的协议不包含其中.数组中包含*outCount指针,并庚随一个空的终止符.必须使用free()函数释放数组.
     
     返回值: 如果cls中没有协议,或者cls为Nil,返回NULL并且*outCount为0
     **/

    func class_copyProtocolList(_ cls: AnyClass?,_ outCount: UnsafeMutablePointer?)  -> AutoreleasingUnsafeMutablePointer?
    
    //返回类定义的版本号
    func class_getVersion(AnyClass?)
    
    //设置一个类定义的版本号
    func class_setVersion(AnyClass, Int32)


添加Class


    /*
     创建一个类和元类
     
     superclass: 新创建类的父类.如果创建一个根类则为Nil
     name: 新创建类的类名.该字符串会被拷贝.
     extraBytes: 类和元类末尾为索引实例变量而分配的字节数.通常为0
     返回值: 新创建的类.或者为Nil如果该类无法被创建(比如使用的名字已经被使用)
     
     讨论:
     可以获取新创建元类的指针通过调用object_getClass(newClass).
     创建一个类.需要先调用objc_allocateClassPair(_:_:_:).然后设置类的特性使用诸如class_addMethod(_:_:_:_:)和class_addIvar(_:_:_:_:_:)这些方法.当你创建完该类后.调用objc_registerClassPair(_:)注册该类后才可以使用.
     
     实例方法和实例变量应该添加到自身类中.类方法应该添加到元类中.
     
     **/

    func objc_allocateClassPair(_ superclass: AnyClass?, _ name: UnsafePointer, _ extraBytes: Int) -> AnyClass?
    
    /*
     销毁一个类和它关联的元类.
     
     讨论:
     如果cls类实例或者它的任何子类存在的话,不要调用该函数.
     **/

    func objc_disposeClassPair(_ cls: AnyClass)
    
    //注册一个类 该类已使用objc_allocateClassPair(_:_:_:)方法创建
    func objc_registerClassPair(AnyClass)
    
    /*
     在Foundation框架下的KVO使用
     
     讨论:
     自身不要调用该函数
     **/

    func objc_duplicateClass(AnyClass, UnsafePointer, Int)

与实例一起使用


    /*
     读取一个对象中实例变量的值
     讨论:
     如果实例变量名已知的话,object_getIvar(_:_:)比object_getInstanceVariable获取值更快一些.
     **/

    func object_getIvar(_ obj: Any?,_ ivar: Ivar) -> Any?
    
    //设置一个对象实例变量的值
    func object_setIvar(_ obj: Any?,_ ivar: Ivar,_ varlue: Any?)
    
    //返回某对象的类名
    func object_getClassName(_obj: Any?)
    
    //返回实例对象的类对象
    func object_getClass(_ obj: Any?) -> AnyClass?
    
    //设置一个对象的类 返回值为对象之前所属的类对象.
    func object_setClass(_ obj: Any?,_ cls: AnyClass) -> AnyClass?

获取类定义

    //获取已注册类定义的列表
    func objc_getClassList(AutoreleasingUnsafeMutablePointer?, Int32)
    
    //创建并且返回所有已注册的类定义的指针列表
    func objc_copyClassList(UnsafeMutablePointer?)
    
    //返回某个类的类定义
    func objc_lookUpClass(UnsafePointer)
    
    //返回某个类的类定义
    func objc_getClass(UnsafePointer)
    
    //返回某个类的类定义
    func objc_getRequiredClass(UnsafePointer)
    
    //返回某个类的元类定义
    func objc_getMetaClass(UnsafePointer)

与实例变量一起使用

    //返回实例变量名称
    func ivar_getName(Ivar)
    
    //返回实例变量的类型
    func ivar_getTypeEncoding(Ivar)

    //返回一个实例变量相对内存基址的偏移值
    func ivar_getOffset(Ivar)

关联引用

    //使用指定key和关联策略设置某个对象的关联值
    func objc_setAssociateObject(Any, UnsafeRawPointer, Any?, objc_AssociationPoicy)
    
    //返回某个对象该key下对应的关联值
    func objc_getAssociateObject(Any, UnsafeRawPointer)
    
    //移除某个对象所有关联对象
    func objc_removeAssociateObjects(Any)

与方法一起使用

    /*
     返回方法的SEL
     
     讨论:
     获取C字符串的方法名.调用sel_getName(method_getName(method))
     **/

    func method_getName(_ m: Method) -> Selector
    
    //返回IMP类型的函数指针
    func method_getImplementation(_ m: Method) -> IMP
    
    //返回一个字符串描述方法的参数和返回类型
    func method_getTypeEncoding(_ m: Method) -> UnsafePointer?
    
    //返回一个字符串描述方法的返回类型
    func method_copyReturnType(Method)
    
    //返回一个字符串描述方法的单个参数类型
    func method_copyArgumentType(Method, UInt32)
    
    //通过引用返回一个字符串描述方法的返回值类型
    func method_getReturnType(Method, UInt32)
    
    //返回一个方法接受的参数数量
    func method_getNumberOfArguments(Method)
    
    //通过引用返回一个字符串描述方法单个参数的类型
    func method_getArgumentType(Method, UInt32, UnsafeMutablePointer?, Int)
    
    //返回某个方法的结构描述
    func method_getDescription(Method)
    
    //设置某个方法的实现
    func method_setImplementation(_ m: Method, _ imp: IMP) -> IMP
    
    /*
     交换两个方法的实现
     
     IMP imp1 = method_getImplementation(m1);
     IMP imp2 = method_getImplementation(m2);
     method_setImplementation(m1, imp2);
     method_setImplementation(m2, imp1);
     
     **/ 
    func method_exchangeImplementations(_m1: Method,_ m2: Method)

与库一起使用

    
    //返回所有加载的OC框架和动态库名称  
    func objc_copyImageNames(UnsafeMutablePointer?)
    
    //返回动态库中一个类的原始格式的名称
    func objc_getImageName(AnyClass?)
    
    //返回某个库或者框架中所有类的名称
    func objc_copyClassNameForImage(UnsafePointer, UnsafeMutablePointer?)


与Selectors一起使用


    //返回某一方法的名称
    func sel_getName(Selector)
    
    //在OC runtime系统中注册一个方法,映射方法名到一个selector,并且返回selector的值
    func sel_registerName(UnsafePointer)
    
    //注册一个方法名到 OC runtime系统中
    func sel_getUid(UnsafePointer)
    
    //返回一个布尔值 表示两个方法是否相等
    func sel_isEqual(Selector, Selector)

与协议一起使用

    //返回指定协议
    func objc_getProtocol(UnsafePointer)
    
    //以数组形式返回runtime中所有已知协议
    func objc_copyProtocolList(UnsafeMutablePointer)
    
    //创建一个协议实例
    func objc_allocateProtocol(UnsafePointer)
    
    //在OC运行时系统中注册一个新协议
    func objc_registerProtocol(Protocol)
    
    //给协议添加一个方法
    func protocol_addMethodDescription(Protocol, Selector, UnsafePointer?, Bool, Bool)

    //添加注册过的协议到正在构建的协议中
    func protocol_addProtocol(Protocol, Protocol)
    
    //添加属性到正在构建的协议中
    func protocol_addProperty(Protocol, UnsafePointer, UnsafePointer?, UInt32, Bool, Bool)
    
    //返回协议名称
    func protocol_getName(Protocol)
    
    //返回布尔值 表示是否两个协议相等
    func protocol_isEqual(Protocol?, Protocol?)
    
    //返回满足给定协议的方法描述数组
    func protocol_copyMethodDescriptionList(Protocol, Bool, Bool, UnsafeMutablePointer?)
    
    //返回满足给定协议的指定方法的方法描述
    func protocol_getMethodDescription(Protocol, Selector, Bool, Bool)
    
    //返回一个协议声明的属性数组
    func protocol_copyPropertyList(Protocol, UnsafeMutablePointer)
    
    //返回给定协议的指定属性
    func protocol_getProperty(Protocol, UnsafePointer, Bool, Bool)
    
    //返回适用某协议的协议数组
    func protocol_copyProtocolList(Protocol, UnsafeMutablePointer)
    
    //返回一个布尔值 表示是否一个协议遵循另一个协议
    func protocol_comformsToProtocol(Protocol?, Protocol?)

与属性一起使用

    //返回属性名
    func property_getName(_ property: objc_property_t) -> UnsafePointer
    
    //返回一个属性的的特征字符串
    func property_getAttributes(_ property: objc_property_t) -> UnsafePointer
    
    //返回指定特征名的属性值
    func property_copyAttributeValue(_ property: objc_property_t,_ attributeName: UnsafePointer) -> UnsafeMutablePointer?
    
    //返回指定属性的属性特征数组
    func property_copyAttributeList(_ property: objc_property_t, _ outCount: UnsafeMutablePointer?) -> UnsafeMutablePointer?

OC语言特色的使用

    //当在foreach迭代中检测到一个突变时,由编译器插入。
    func objc_enumerationMutation(Any)
    
    //设置当前的突变处理
    func objc_setEnumerationMutationHandler(((Any) -> Void)?)
    
    //给一个函数创建一个指针  当方法被调用的使用调用指定Block
    func imp_implementationWithBlock(Any)
    
    //返回与一个已经创建使用的IMP关联的Block
    func imp_getBlock(IMP)
    
    //取消与已经创建使用的IMP关联的Block
    func imp_removeBlock(IMP)
    
    //加载被弱引用的对象并返回它
    func objc_loadWeak()
    
    //存储一个弱引用变量值
    func objc_storeWeak(AutoreleasingUnsafeMutablePointer, Any?)

类定义数据结构

    //在类定义中表示一个方法类型
    typealias Method
    
    //表示一个实例变量类型
    typealias Ivar
    
    //表示一个分类类型
    typealias Category
    
    //表示一个OC声明的属性类型
    typealias objc_property_t
    
    //定义一个OC方法
    struct objc_method_description
    
    //定义一个属性特性
    struct objc_property_attribute_t

实例数据类型

这些是表示对象,类,父类的数据类型

  • objc_object 指向一个实例对象的指针
  • objc_object 表示一个实例对象
  • objc_super 一个实例对象的父类
    //一个类的实例的指针
    struct objc_object
    
    //指定实例对象的父类
    struct objc_super
    

你可能感兴趣的:(Objective-C Runtime)