RumeTimeiOS 开发 iOS Developer

iOS Runtime的那些小事(持续更新中)

2016-04-07  本文已影响142人  奇董

runtime是动态语言的一个特征,初学者在编写程序的时候对这种运行时机制也是特别模糊。网上对这个东西的教程也是一大篇,所以具体的原理我在这里就不介绍了,我在这边学了实际开发中用到的几个小案例拿出来给童鞋找点感觉。

字典转模型

字典转模型是我们在实际开发中经常遇到的问题,我们可以自己一个一个把接口获取下来的json数据赋值给model里的属性,也可以采用网上流行的3方库来进行装换。
其实 实现这一个功能很简单(大牛的3方库,优化以及细节都考虑的很全面)。
我的基本思路是这样:我首先将字典的keys取出来,之后将model里面的成员变量获取到。对比key和成员变量的名称,如果相同就将value 赋值给成员变量。
实际代码:
声明一个NSObject的类目:

#import "Extension.h"
#import <objc/runtime.h>

@implementation NSObject(Extension)


+ (id)dicToModel:(NSDictionary *)dict {
    //创建调用对象
    id per = [self new];
    //要获取model类的属性
    unsigned int outCount;
    Ivar *vars = class_copyIvarList([self class], &outCount);
    //遍历传过来的数组
    for (id name1 in dict.allKeys) {
  
        NSString *name = [NSString stringWithFormat:@"_%@",name1];
        for (int i = 0; i < outCount; i++) {
            const char *varName = ivar_getName(vars[i]);
            NSString *runName = [NSString stringWithUTF8String:varName];
            if ([runName isEqualToString:name]) {
                //字典里的属性和model里面的属性 吻合则转换
                //用这个方法的话,基本上属性 得特殊处理
//              object_setIvar(per, vars[i], [dict objectForKey:name1]);
                [per setValue:[dict objectForKey:name1] forKey:runName];
            }
        }
    }
    
    return per;
    
}
@end

声明一个Person类:

@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger *age;
@end

实际使用:

 //字典转模型
    NSDictionary *dict = @{@"name":@"李雷",@"age":@18};
    Person *per = [Person dicToModel:dict];
    NSLog(@"%@=======%ld",per.name,per.age);

打印结果:

2016-03-07 16:10:07.068 DicToModel[3639:134187] 李雷=======18

使AlertView 像UIAlertViewController 一样初始化只有直接处理点击事件

我们在使用alertView的时候 如果想处理点击方法 必须要实现代理方法,在代理方法里面处理点击事件。如果在一个C上有多个alertView公用一个代理方法。这时候,对我们使用起来和阅读都有一些麻烦。
而UIAlertViewController 可以初始化之后 设置点击方法。我感觉这样对代码的阅读直观一些,就自己写了一个类目来处理这些东西。

//使用
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"22" message:@"hah" delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:@"sure", nil];

    [alert handleSureAction:^(NSInteger index) {
        if (index == 1) {
            NSLog(@"确定被点击");
        }else {
            NSLog(@"取消被点击");
        }
    }];

    [alert show];

为alertView 新加的类目

//
//  UIAlertView+ActionBlock.h
//  classCluster
//
//  Created by DQ on 16/4/8.
//  Copyright © 2016年 DQ. All rights reserved.
//

#import <UIKit/UIKit.h>
typedef void (^handleAction)(NSInteger index) ;

@interface UIAlertView (ActionBlock)<UIAlertViewDelegate>

- (void) handleSureAction:(handleAction) handle ;
@end
//
//  UIAlertView+ActionBlock.m
//  classCluster
//
//  Created by DQ on 16/4/8.
//  Copyright © 2016年 DQ. All rights reserved.
//

#import "UIAlertView+ActionBlock.h"
#import <objc/runtime.h>
static void *KAlertViewActionKey = "alertViewKey";

@implementation UIAlertView (ActionBlock)

- (void)handleSureAction:(handleAction)handle {
    self.delegate = self;
    objc_setAssociatedObject(self, KAlertViewActionKey, handle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    handleAction handle = objc_getAssociatedObject(self, KAlertViewActionKey);
    handle(buttonIndex);
    
}
@end

引入这个类目之后,就可以愉快的处理点击事件了。
======更新

http://www.jianshu.com/p/b9fdd17c525e 原文 可以瞅瞅

method swizzling 全局修改字体

//
//  UILabel+ChangeFont.m
//  methodSwizzling-changeFont
//
//  Created by DQ on 16/4/28.
//  Copyright © 2016年 DQ. All rights reserved.
//

#import "UILabel+ChangeFont.h"
#import <objc/runtime.h>

@implementation UILabel (ChangeFont)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL oriSEL = @selector(willMoveToSuperview:);
        SEL swizzlingSEL = @selector(myMovetoSuperView:);
        Method oriMethod = class_getInstanceMethod([self class], oriSEL);
        Method swizzlingMethod = class_getInstanceMethod([self class], swizzlingSEL);
        BOOL isadd = class_addMethod([self class], oriSEL,method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod));
        if (isadd) {
            class_replaceMethod([self class], swizzlingSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        }else {
            method_exchangeImplementations(oriMethod, swizzlingMethod);
        }
    });

}

- (void)myMovetoSuperView:(UIView *)superView  {
    [self myMovetoSuperView:superView];
    self.font = [UIFont fontWithName:@"Aladdin" size:30];


}

这边有一个疑问就是,为什么不是直接交换方法,而是判断有没有添加?
百度南峰子博客下面评论有答案
1.didAddMethod一直为NO,是因为你当前类重载了父类的viewWillAppear方法。如果当前类没有重写父类的方法class_addMethod会把新的IMP替换掉父类的IMP,也就是重写了父类方法,并且返回yes;如果当前类重写了父类方法,就不在替换IMP,直接返回NO。
这是oc原话:

如果返回 NO ,说明已经重写,就直接交换。

如果返回 YES, 说明添加成功,也就是你之前没有重写 viewWillAppear 方法。因为在添加方法里面是将 originalSelector 与 swizzledMethod 的 IMP 绑定在一起了,所以接下来只用将 swizzledSelector 与 originalMethod 的 IMP 绑定就可以了。也就实现了交换。

上一篇下一篇

猜你喜欢

热点阅读