【4858.com】runtime常用方法,Runtime实际运用之一

By admin in 4858.com on 2019年9月11日

ios开辟中 runtime是何许的定义,小编相信在Google以至 ”度娘“
上追寻就可以有一大把。可点击这个博客:地址1 ,地址2 ,地址3
…,上面笔者就大概的叙述多少个runtime在大家平昔的开垦中的使用情形,只投石问路。OO哈哈~

【4858.com】runtime常用方法,Runtime实际运用之一。富含:对象绑定,获取属性,获取成员变量,获取情势,交流方法调用,动态增加方法。

一、runtime介绍、OC的使用

有关runtime的介绍,和OC的行使,这里就不再去介绍了,我们能够看下以下这两篇前辈们写的篇章,一篇是runtime的牵线,一篇是runtime在OC语言下的利用。

1、runtime介绍

2、runtime OC介绍和行使

Object-C是一门动态语言,独有在程序运转时,才会去分明目标的品种,并调用类或对象的对应措施。
4858.com ,runtime是一套相比较底层的纯C语言API,基本是利用C语言来成功的(也包涵部分
汇编)。在大家平昔编写制定的OC代码中,在程序运转的历程中,最后都以转成runtime
的C语言代码,也正是说runtime才是确实的私自老大。
runtime能够完结比非常多工作,能够给类增添方法、动态加多属性、获取类的名号、获取贰个类的具有办法、获取三个类的享有属性、获取类的享有成员变量等等,如若能稳当的运用好runtime对项目标支付会起到非常的大的援助。
此处有本身要好写的一个德姆o,里面包罗了部分常用的runtime用法,截图如下:

动用运营时办法要求引进runtime.h文件。

4858.com 1部分格局解释

二、runtime使用(swift开拓蒙受)

此地是那篇作品的显要内容,重要介绍swift的编制程序语言下runtime的使用。这里根本介绍了runtime常用的两种效应:

提示:
swift运用runtime的时候不要求再导入runtime库了。

4858.com 2

一、基础知识

runtime简称运维时,OC就是运维时机制,也等于在运作时候的局地机制,当中最重大的是消息机制。
对此C语言,函数的调用是在编写翻译的时候会调控调用哪个函数。
对此OC的函数,属于动态调用进程,在编写翻译的时候并不能调整真正调用哪个函数,唯有在真正运行的时候才会依赖函数的称谓找到相应的函数来调用。

求❤️、求粉!OO

1、类进行增多属性

思路:

通过runtime的关联函数用一个关联key将索要加上的习性的值存储(set方法)获取(get方法)出来。

步骤:

  • 1、设置关联key
  • 2、定义要拉长的习性
  • 3、重写属性的set和get方法
  • 4、set和get方法中须求调用runtime的关系函数

** 代码完成 **

// 属性关联的key
private var newPropertyKey = "toNewPropertyKey"

extension ViewController {

    var newproperty: String {

        // 新添加属性的set方法
        set(value) {
            /**
             * 第一个参数:关联的对象:给哪一个对象添加关联,这里就传哪一个对象
             * 第二个参数:关联的key,通过这个key设置(存储)对应的值,这里定义了一个newPropertyKey的key
             * 第三个参数:关联的值,即通过key所关联的值,在get方法中获取的就是这个值
             * 第四个参数:关联的方式
             */
            objc_setAssociatedObject(self, &newPropertyKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }

        // 新添加属性的get方法
        get{
            /**
             * 第一个参数:关联的对象:给哪一个对象添加关联,这里就传哪一个对象
             * 第二个参数:关联的key,通过这个key获取对应的值
             */
            return objc_getAssociatedObject(self, &newPropertyKey) as! String
        }
    }

    // 测试这个新属性
    override func viewDidLoad() {
        super.viewDidLoad()

        // 这里可以设置成功
        newproperty = "newproperty"

        // 这里测试下打印获取
        print(newproperty)

        // 打印结果:
           newproperty
    }
}

本人不推荐应用方面包车型大巴方法定义key,特别OC化。。。建议在swift语言下使用以下方法:

// 利用swift强大的结构体去封装关联key,然后用swift典型的链式编程方式用这些key

extension ViewController {

    // 私有的结构体: 这个类扩展下所有新添加属性的关联值的keys
    private struct AssociateKeys {
        static var toNewPropertyKey = "toNewPropertyKey" // 关联值的key
    }


    var newproperty: String {

        // 新添加属性的set方法
        set(value) {
            /**
             * 第一个参数:关联的对象:给哪一个对象添加关联,这里就传哪一个对象
             * 第二个参数:关联的key,通过这个key设置(存储)对应的值,这里定义了一个newPropertyKey的key
             * 第三个参数:关联的值,即通过key所关联的值,在get方法中获取的就是这个值
             * 第四个参数:关联的方式
             */
            objc_setAssociatedObject(self, &AssociateKeys.toNewPropertyKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }

        // 新添加属性的get方法
        get{
            /**
             * 第一个参数:关联的对象:给哪一个对象添加关联,这里就传哪一个对象
             * 第二个参数:关联的key,通过这个key获取对应的值
             */
            return objc_getAssociatedObject(self, &AssociateKeys.toNewPropertyKey) as! String
        }
    }

    // 测试这个新属性
    override func viewDidLoad() {
        super.viewDidLoad()

        // 这里可以设置成功
        newproperty = "newproperty"

        // 这里测试下打印获取
        print(newproperty)
    }
}

引深:

咱们常见的MJRefresh(OC)上拉下拉等刷新框架,就是通过这种措施,给tableView加多贰个mj_header、mj_footer

WeChat_1469247461.jpeg

事实表明:

在编写翻译阶段,OC可以调用任何函数,纵然这些函数并未有完结,只要注明过就不会报错。
— 在编写翻译阶段,C语言调用未落到实处的函数就能够报错。
Method :成员方法
Ivar : 成员变量

2、沟通方法

当系统自带的点子满意不断你的本性化供给时,那时候必要在保险系统方法原有的基础上,给其张开一些效果。

知足如此的须求有三种艺术:

  • 1、自定义一个子类,重写父类的法子,把需求的法力写在中间
  • 2、用runtime 交换系统的议程,在调用系统方法的时候实在是调用本身定义的措施,然后再在融洽定义的艺术里调用系统的极度格局

专程表明

换来方法的载体选拔,OC语言中山大学家兴许会挑选类情势load()或initialize()措施,不过在swift中,已经不容许行使load()方法了,只可以采取initialize()主意,那几个类方法会在对应的类初阶化的时候就能够调用

金玉锦绣思路

  • 1、用Runtime的动态增加方法函数将原生方法动态拉长到自定义的措施地址上
  • 2、假如1增添职业有成,再用Runtime的动态增加方法函数将自定义的法子加多到原生方法的地点上
  • 3、要是增加不成功,将那七个措施再用艺术沟通函数进行地址交流:method_exchangeImplementations

代码完结

extension UIViewController {

    // 初始这个类的时候进行处理:
    public override class func initialize() {

        // 只保证执行一次:initialize()这个方法,只要有UIViewController这个的子类,都会调用一次这个方法,因此在这里添加一个线程锁,让其只执行一次足够。
        struct Static {
            static var token: dispatch_once_t = 0
        }
        // 交换思路:
        // 1、将原生方法动态添加到自定义的方法地址上
        // 2、如果1添加成功,将自定义的方法添加到原生方法的地址上
        // 3、如果添加不成功,将这两个方法再用方法交换函数进行地址交换:method_exchangeImplementations
        dispatch_once(&Static.token) {

            // 获取两个方法
            let originalSelector = #selector(viewWillAppear)
            let swizzledSelector = #selector(nsh_viewWillAppear)

            // 通过Selector获取方法地址
            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

            // 将系统的方法动态添加到自定义方法的地址上
            // 参数说明:
            // 第一个参数:给哪个类添加方法
            // 第二个参数:添加方法的方法选择器
            // 第三个参数:添加方法的函数实现(函数地址)
            // 第四个参数:函数的类型
            let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

            // 上一步添加成功,再将自定义的添加到原生方法的地址上
            if didAddMethod {
                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
            } else {
                // 之前添加不成功,再交换两个方法的地址
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
    }

    // MARK: - Method Swizzling

    func nsh_viewWillAppear(animated: Bool) {
        // 调用自定义的方法去实现系统原生的方法,因为此时自定义的方法地址已经是系统对应方法的地址了
        self.nsh_viewWillAppear(animated)

        // TODO:自己想要添加的功能
        print("nsh_viewWillAppear: \(description)")
    }
}

Demo地址:https://github.com/slipawayleaon/runtime-Demo
先是次作文,若是有写的不到位的地点请大家建议。
您感到德姆o勉强接受的话请给个star,多谢大家。

二、常用方法

class_copyPropertyList : 获取属性列表
  class_copyMethodList : 获取成员方法列表
  class_copyIvarList:获取成员变量列表
  ivar_getName:获取变量名
  property_getName:获取属性名

利用示例

3、遍历获取属性名方法名

  • 获取属性名:

 // 记录属性的个数
 var count : UInt32 = 0
 // 获取所有属性、个数
 let ivarList = class_copyIvarList(UINavigationController().classForCoder, &count)
 // 遍历属性获取属性名
 for index in 0...count-1 {
     // 获取属性名的C(C语言的字符串)
     let propertyNameC = ivar_getName(ivarList[Int(index)])
     // 将C语言字符串转成Swift语言的字符串
     let propertyName = String.fromCString(propertyNameC)
     // 获取属性名的C(C语言的字符串)
     let propertyTypeC = ivar_getTypeEncoding(ivarList[Int(index)])
     // 将C语言字符串转成Swift语言的字符串
     let prorpertyType = String.fromCString(propertyTypeC)
     print(propertyName!,prorpertyType!)
 }

打字与印刷结果:

4858.com 3

Snip20160911_2.png

  • 获得格局名:

// 记录方法名的个数
var count : UInt32 = 0
// 获取所有的方法名
let methods = class_copyMethodList(UIView().classForCoder, &count)
// 遍历数组获取每一个方法名
for index in 0...count-1 {
    // 获取方法
    let sel = method_getName(methods[Int(index)])
    // 获取方法名称(C语言下的)
    let methodNameC = sel_getName(sel)
    // 将名称转为swift语言下
    let methodName = String.fromCString(methodNameC)
    print(methodName!)
}

打字与印刷结果(一部分):

4858.com 4

Snip20160911_4.png

不断更新中···

2.1.拿走成员变量list

        unsigned int ivarCount = 0; //成员变量数
        Ivar *ivarList = class_copyIvarList([self class], &ivarCount);//ivar数组

        for (int i = 0; i < ivarCount; i++) {//遍历
            Ivar ivar = ivarList[i]; //获取ivar
            const char *name = ivar_getName(ivar);//获取变量名
            NSString *key = [NSString stringWithUTF8String:name];
            NSLog(@"%@", key);

        }

      free(ivarList);

2.2.得到属性列表

unsigned int count = 0;
    objc_property_t *propertList = class_copyPropertyList([self class], &count);
    for (int i = 0; i < count; i++) {
        objc_property_t property = propertList[i];
        const char *name = property_getName(property);
        const char *attrs = property_getAttributes(property);
//        property_copyAttributeValue(,) 第一个参数为objc_property_t,第二个参数"V"获取变量名,"T"获取类型
        const char *value = property_copyAttributeValue(property, "V");
        NSLog(@"name = %s, attrs = %s, value = %s", name, attrs, value);
  /*
         各种符号对应类型,部分类型在新版SDK中有所变化,如long 和long long
         c char         C unsigned char
         i int          I unsigned int
         l long         L unsigned long
         s short        S unsigned short
         d double       D unsigned double
         f float        F unsigned float
         q long long    Q unsigned long long
         B BOOL
         @ 对象类型 //指针 对象类型 如NSString 是@“NSString”
         propertyType,你可以打印出来,看看它是什么。
         要判断某个属性的类型,只需要[propertyType hasPrefix:@"T@\"NSString\""]
          这代表它是NSString 类型。
         */
    }
    free(propertList);

2.3.得到格局列表

unsigned int count = 0;
    Method *methodList = class_copyMethodList([self class], &count);
    for (int i = 0 ; i < count; i++) {
        Method method = methodList[i];
        SEL selector = method_getName(method);//方法入口
        const char *sel_name = sel_getName(selector);
        NSLog(@"方法名 %s", sel_name);
    }
    free(methodList);

2.4.Runtime-动态成立类增添属性和办法

- (void)createClass
{
    Class MyClass = objc_allocateClassPair([NSObject class], "myclass", 0);
    //添加一个NSString的变量,第四个参数是对其方式,第五个参数是参数类型
    if (class_addIvar(MyClass, "itest", sizeof(NSString *), 0, "@")) {
        NSLog(@"add ivar success");
    }
    //myclasstest是已经实现的函数,"v@:"这种写法见参数类型连接
    class_addMethod(MyClass, @selector(myclasstest:), (IMP)myclasstest, "v@:");
    //注册这个类到runtime系统中就可以使用他了
    objc_registerClassPair(MyClass);
    //生成了一个实例化对象
    id myobj = [[MyClass alloc] init];
    NSString *str = @"asdb";
    //给刚刚添加的变量赋值
    //  object_setInstanceVariable(myobj, "itest", (void *)&str);在ARC下不允许使用
    [myobj setValue:str forKey:@"itest"];
    //调用myclasstest方法,也就是给myobj这个接受者发送myclasstest这个消息
    [myobj myclasstest:10];

}
//这个方法实际上没有被调用,但是必须实现否则不会调用下面的方法
- (void)myclasstest:(int)a
{

}
//调用的是这个方法
static void myclasstest(id self, SEL _cmd, int a) //self和_cmd是必须的,在之后可以随意添加其他参数
{

    Ivar v = class_getInstanceVariable([self class], "itest");
    //返回名为itest的ivar的变量的值
    id o = object_getIvar(self, v);
    //成功打印出结果
    NSLog(@"%@", o);
    NSLog(@"int a is %d", a);
}

详解Objective-C的meta-class:http://www.jianshu.com/p/a5ab8d998b9e

三、使用方向:归档、字典<—->模型、框架封装等

3.1. 贯彻归档

encode:编码  decode:解码
#define WKCodingImplementing 
- (void)encodeWithCoder:(NSCoder *)aCoder 
{ 
    unsigned int ivarCount = 0; 
    Ivar *ivarList = class_copyIvarList([self class], &ivarCount); 
    for (int i = 0; i < ivarCount; i++) { 
        Ivar ivar = ivarList[i]; 
        const char *name = ivar_getName(ivar); 
        const char *type = ivar_getTypeEncoding(ivar); 
        NSLog(@"%s-----%s", name, type); 
        NSString *key = [NSString stringWithUTF8String:name]; 
        id value = [self valueForKey:key]; 
        [aCoder encodeObject:value forKey:key]; 
    } 
    free(ivarList); 
} 
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder 
{ 
    if (self = [super init]) { 
        unsigned int ivarCount = 0; 
        Ivar *ivarList = class_copyIvarList([self class], &ivarCount); 
        for (int i = 0; i < ivarCount; i++) { 
            Ivar ivar = ivarList[i]; 
            const char *name = ivar_getName(ivar); 
            NSString *key = [NSString stringWithUTF8String:name]; 
            id value = [aDecoder decodeObjectForKey:key]; \
            NSLog(@"%@ %@", key, value); 
            [self setValue:value forKey:key]; 
        } 
    } 
    return self; 
}

3.2.什么高效生成Plist文件属性名

完结原理:通过遍历字典,剖断项目,拼接字符串

  // 拼接属性字符串代码
  NSMutableString *strM = [NSMutableString string];

  // 1.遍历字典,把字典中的所有key取出来,生成对应的属性代码
  [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

  NSString *type;

      if ([obj isKindOfClass:NSClassFromString(@"__NSCFString")]) {
          type = @"NSString";
      }else if ([obj isKindOfClass:NSClassFromString(@"__NSCFArray")]){
          type = @"NSArray";
      }else if ([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")]){
          type = @"int";
      }else if ([obj isKindOfClass:NSClassFromString(@"__NSCFDictionary")]){
          type = @"NSDictionary";
      }else if ([obj isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){
          type = @"BooL";
      }
      // 属性字符串
      NSString *str;
      if ([type containsString:@"NS"]) {
          str = [NSString stringWithFormat:@"@property (nonatomic, strong) %@ *%@;",type,key];
      }else{
          str = [NSString stringWithFormat:@"@property (nonatomic, assign) %@ %@;",type,key];
      }
      // 每生成属性字符串,就自动换行。
      [strM appendFormat:@"\n%@\n",str];  
  }];
  // 把拼接好的字符串打印出来,就好了。
  NSLog(@"%@",strM);

打字与印刷结果

4858.com 5

874828-7eb4ad3d25184d7a.png

3.3.KVC达成字典转模型

KVC弊端
模型中属性必得和字典的key一致,不然就报错
借使差异,系统会调用setValue: forUndefinedKey:
消除办法,只需求重写setValue: forUndefinedKey:就可以

- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{

}

3.4. RunTime贯彻字典转模型

贯彻思路:遍历模型中具备属性,遵照模型的质量名去字典中寻觅key,抽出对应的的值,给模型的性质赋值

3.4.1.拔尖调换

class_copyIvarList(self,
&count)该办法第二个参数是要获取哪个类中的成员属性,第二个参数是那几个类中有稍许成员属性,必要传入地址,再次回到值Ivar是个数组,会将具有成员属性归入那么些数组中

@implementation NSObject (Model)

+ (instancetype)modelWithDict:(NSDictionary *)dict
{
    // 思路:遍历模型中所有属性-》使用运行时

    // 0.创建对应的对象
    id objc = [[self alloc] init];

    // 1.利用runtime给对象中的成员属性赋值

    // class_copyIvarList:获取类中的所有成员属性
    // Ivar:成员属性的意思
    // 第一个参数:表示获取哪个类中的成员属性
    // 第二个参数:表示这个类有多少成员属性,传入一个Int变量地址,会自动给这个变量赋值
    // 返回值Ivar *:指的是一个ivar数组,会把所有成员属性放在一个数组中,通过返回的数组就能全部获取到。
    /* 类似下面这种写法

     Ivar ivar;
     Ivar ivar1;
     Ivar ivar2;
     // 定义一个ivar的数组a
     Ivar a[] = {ivar,ivar1,ivar2};

     // 用一个Ivar *指针指向数组第一个元素
     Ivar *ivarList = a;

     // 根据指针访问数组第一个元素
     ivarList[0];

     */
    unsigned int count;

    // 获取类中的所有成员属性
    Ivar *ivarList = class_copyIvarList(self, &count);

    for (int i = 0; i < count; i++) {
        Ivar ivar = ivarList[i];

        // 获取成员属性名
        NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];

        // 处理成员属性名->字典中的key 
        // (去掉 _ ,从第一个角标开始截取)
        NSString *key = [name substringFromIndex:1];

        // 根据成员属性名去字典中查找对应的value
        id value = dict[key];

3.4.2.二级调换

认清字典中是还是不是留存字典,如若存在,转为模型
字典属性生成的是@”@”xxxx””类型,要求减小为@”xxxx”

    if ([value isKindOfClass:[NSDictionary class]]) {
            // 获取成员属性类型
            NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
            // 生成的是这种@"@\"User\"" 类型 -》 @"User"  在OC字符串中 \" -> ",\是转义的意思,不占用字符
            // 裁剪类型字符串
            NSRange range = [type rangeOfString:@"\""];

            type = [type substringFromIndex:range.location + range.length];
            range = [type rangeOfString:@"\""];
            // 裁剪到哪个角标,不包括当前角标
            type = [type substringToIndex:range.location];
            // 根据字符串类名生成类对象
            Class modelClass = NSClassFromString(type); 
            if (modelClass) {
                value  =  [modelClass modelWithDict:value];
            }
        }

3.4.3.三级转变

因而给分类加多三个契约,来完结将数组中的字典转为模型

       // 三级转换:NSArray中也是字典,把数组中的字典转换成模型.
        // 判断值是否是数组
        if ([value isKindOfClass:[NSArray class]]) {
            // 判断对应类有没有实现字典数组转模型数组的协议
            if ([self respondsToSelector:@selector(arrayContainModelClass)]) {

                // 转换成id类型,就能调用任何对象的方法
                id idSelf = self;

                // 获取数组中字典对应的模型
                NSString *type =  [idSelf arrayContainModelClass][key];

                // 生成模型
               Class classModel = NSClassFromString(type);
                NSMutableArray *arrM = [NSMutableArray array];
                // 遍历字典数组,生成模型数组
                for (NSDictionary *dict in value) {
                    // 字典转模型
                  id model =  [classModel modelWithDict:dict];
                    [arrM addObject:model];
                }

                // 把模型数组赋值给value
                value = arrM;

            }
        }


        if (value) { // 有值,才需要给模型的属性赋值
            // 利用KVC给模型中的属性赋值
            [objc setValue:value forKey:key];
        }

    }

    return objc;
}

@end

3.5. 用到runtime完成情势的置换

3.5.1 前言

在支付进度中,大家常常会遇上一种难点:
即当我们选取系统自带的办法时,开采系统方法的法力不能满意我们的急需,那时候须要我们给系统的秘籍增多额外的功效.
上面以三个例证来兑现给系统自带的不二等秘书诀增多额外的功用.

品种背景 :
公司有个开采了比较久的类别,以前使用增多图片的主意用的是:imageName:方法,
今后的品类供给是给系统自带的imageName:增加一个功效:假若下载的图样不设有,那么就提示我们前段时间下载的图纸为空.

思路 : 给系统自带的法子增加效果的二种形式

  1. 自定义类,
    重写系统自带的imageName:方法,这种方法即便能够完结,可是它的坏处正是供给求运用本人的类,重视性强.
  2. 给UIImage增多三个分拣,
    退换系统类的兑现,给系统的类增加方法的时候调用(刚烈不推荐)
  3. 利用runtime的并行格局,给系统的措施增添成效. 具体落到实处 : 增添四个分类
    –> 在分拣中提供二个急需丰裕的功效的格局 –>
    将这么些艺术的贯彻和体系自带的方法的落到实处交互.

3.5.2.步骤

3.5.2.1. 新建一个接续自UIImage的归类,定义一个艺术实现给系统的自带的诀要加多作用.

#import <UIKit/UIKit.h>
@interface UIImage (WGImage)
// 声明方法
// 如果跟系统方法差不多功能,可以采取添加前缀,与系统方法区分
+ (UIImage *)wg_imageWithName:(NSString *)imageName;
@end

3.5.2.2. 落真实意况势的竞相

概念完结新点子后,需求弄清楚哪些时候达成与系统的法子交互?
答 :
既然是给系统的秘籍增添额外的效劳,换句话说,大家未来在开荒中都是应用本身定义的艺术,替代系统的艺术,所以,当程序一运营,就要求能接纳本人定义的效果与利益方法.说道这里:大家必得要弄驾驭一下多个措施
:
+(void)initialize(当类第一遍被调用的时候就能调用该措施,整个程序运维中只会调用一次)

  • (void)load(当程序运转的时候就能够调用该方法,换句话说,只要程序一运维就能够调用load方法,整个程序运营中只会调用一回)

+ (void)load {
/*
     self:UIImage
     谁的事情,谁开头 1.发送消息(对象:objc) 2.注册方法(方法编号:sel) 3.交互方法(方法:method) 4.获取方法(类:class)
     Method:方法名
     获取方法,方法保存到类
     Class:获取哪个类方法
     SEL:获取哪个方法
     imageName
*/
    // 获取imageName:方法的地址
    Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));
    // 获取wg_imageWithName:方法的地址
    Method wg_imageWithNameMethod = class_getClassMethod(self, @selector(wg_imageWithName:));
    // 交换方法地址,相当于交换实现方式
    method_exchangeImplementations(imageNameMethod, wg_imageWithNameMethod);
}

3.5.2.3. 加载图片, 判别当前图片是还是不是为空

// 加载图片, 判断是否为空
+ (UIImage *)wg_imageWithName:(NSString *)imageName
{
    // 这里调用imageWithName,相当于调用imageName
    UIImage *image = [UIImage wg_imageWithName:imageName];
    if (!image) {
        NSLog(@"Alex : 图片不存在");
    }
    return image;
}

3.5.2.4. 行使交互后的措施

#import "ViewController.h"
#import "WGStudent.h"
#import "UIImage+WGImage.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

  //  wg_imageWithName ---> imageNamed(底层的操作 : 1, 下载图片. 2, 判断图片是否存在 )
    [UIImage imageNamed:@"WilliamAlex.png"];
}

@end

3.5.2.5. 打字与印刷结果

2016-03-08 17:29:50.372 fdsfsdf[1545:96854] 亚历克斯 : 图片不设有
文化张开
无法在分拣中重写系统方法imageNamed,因为会把系统的效果给覆盖掉,并且分类中无法调用super.

runtime的那一点事儿(一)音讯机制
http://blog.csdn.net/jq2530469200/article/details/51880836
runtime的那点事儿(二)音信机制
http://blog.csdn.net/jq2530469200/article/details/51886532
runtime的那一点事情(三)新闻机制
http://blog.csdn.net/jq2530469200/article/details/51886578
runtime简单利用之方法的置换:
http://www.jianshu.com/p/d28abb706add
选拔RunTime落成字典转模型:
http://www.jianshu.com/p/cecfe78e9cd8

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有