关闭

Runtime的简单使用

标签: Runtime归档按钮绑定blockswift使用Runtime动态添加属性
514人阅读 评论(0) 收藏 举报
分类:

Runtime的简单使用

       Runtime一直都是iOS开发者讨论的比较多的问题,如果不知道一点点Runtime的使用的话,感觉都不好意思说自己是一个用OC来开发Apple应用的开发人员。虽然Runtime使用的这类博客在网上可以说是烂大街了,但是我还是想记录一下自己对Runtime的学习情况。

在OC中使用Runtime需要导入#import <objc/objc-runtime.h>,而在Swift中则不需要,系统已经为我们导入了

一、消息发送

objc_msgSend(<#id self#>, <#SEL op, ...#>)
要使用这个方法,在Xcode7以上需要修改下设置信息:targets --> Build settings --> 搜索 msg  修改为 NO 即可索引出该方法
- (void)viewDidLoad {
    [super viewDidLoad];
    objc_msgSend(self, @selector(msgSend:param2:), @"param1", @"param2");
}

- (void)msgSend:(NSString *)param1 param2:(NSString *)param2
{
    NSLog(@"param1 = %@, param2 = %@",param1, param2);
}
但是在swift中已经没有这个方法了

二、获取属性名、属性的值

获取成员属性名和值

- (NSDictionary *)getPropertyListAndValue
{
    NSMutableDictionary * dic = [NSMutableDictionary dictionary];
    
    unsigned int count = 0;
    Ivar * ivar = class_copyIvarList([self class], &count);
    
    for (int i = 0; i < count; i ++) {
        // 获取属性名字
        const char * name = ivar_getName(ivar[i]);
        NSString * propertyName = [NSString stringWithUTF8String:name];
        // 获取属性值
        NSString * value = [self valueForKey:propertyName];
        [dic setObject:value forKey:propertyName];
    }
    
    free(ivar);
    return dic;
}

打印结果如下

2016-05-31 17:00:21.781 Runtime[4323:209497] array = {
    "_IdCard" = 123;
    "_age" = 12234;
    "_name" = "\U5f20\U4e09";
    "_sex" = 12;
}
获取属性名和值
- (NSDictionary *)getPropertyListAndValue
{
    NSMutableDictionary * dic = [NSMutableDictionary dictionary];
    
    unsigned int count = 0;
    objc_property_t * property = class_copyPropertyList([self class], &count);
    
    for (int i = 0; i < count; i ++) {
        // 获取属性名字
        const char * name = property_getName(property[i]);
        NSString * propertyName = [NSString stringWithUTF8String:name];
        // 获取属性值
        NSString * value = [self valueForKey:propertyName];
        [dic setObject:value forKey:propertyName];
    }
    
    free(property);
    return dic;
}
2016-05-31 17:04:51.762 Runtime[4357:213684] array = {
    IdCard = 123;
    age = 12234;
    block = blnl;
    name = "\U5f20\U4e09";
    sex = 12;
}
Swift中获取属性名和属性值
func getAllPropetyAndValue() -> [String: AnyObject] {
        var count: UInt32 = 0
        let ivar = class_copyIvarList(Persion.self, &count)
        var dic: [String: AnyObject] = Dictionary()
        for index in 0..<Int(count) {
            // 获取属性名
            let propety = ivar_getName(ivar[index])
            let nameString = String.fromCString(propety)
            // 获取值
            let value = self.valueForKey(nameString!)
            if let value = value {
                dic[nameString!] = value
            }
        }
        return dic
    }
说明:class_copyPropertyList和property_getName都不能获取对应类父类的属性名,在OC中这两个方法获取的属性名存在一个"_"的差异,在Swift中则不存在

三、获取方法名
- (NSArray *)getMothodName
{
    NSMutableArray * mothodArray = [NSMutableArray array];
    
    unsigned int count = 0;
    Method * method = class_copyMethodList([self class], &count);
    for (int i = 0; i < count; i ++) {
        // 获取方法名字
        SEL methodName = method_getName(method[i]);
        const char * name = sel_getName(methodName);
        [mothodArray addObject:[NSString stringWithUTF8String:name]];
    }
    
    return mothodArray;
}
四、给OC的类目添加属性、把按钮的Action绑定Block

给OC的类目添加属性:

- (void)setParam:(NSString *)param
{
    objc_setAssociatedObject(self, @selector(param), param, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)param
{
    return objc_getAssociatedObject(self, _cmd);
}
Swift中添加属性
private var addressKey: UInt8 = 0
extension Persion {
    var address: String? {
        get {
            return objc_getAssociatedObject(self, &addressKey) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &addressKey,
                    newValue as NSString?,objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC
                )
            }
        }
    }
}
把按钮的Selector绑定Block:
typedef void(^ButtonBlock)();

@interface UIButton (block)

- (void)addTarget:(id)target events:(UIControlEvents)event block:(ButtonBlock)block;

@end
const void * buttonKey = @"buttonKey";

@implementation UIButton (block)

- (void)addTarget:(id)target events:(UIControlEvents)event block:(ButtonBlock)block
{
    objc_setAssociatedObject(self, buttonKey, block, OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self addTarget:target action:@selector(processButton) forControlEvents:event];
}

- (void)processButton
{
    objc_getAssociatedObject(self, buttonKey);
}

@end
调用:
- (void)viewDidLoad
{
    [self.button addTarget:self events:UIControlEventTouchDown block:^{
        NSLog(@"点击事件");
    }];
}

在swift中绑定:

private var ActionBlockKey: UInt8 = 0

typealias ButtonBlock = ((sender: UIButton)-> Void)?

class ActionBlockWrapper : NSObject {
    var block : ButtonBlock
    init(block: ButtonBlock) {
        self.block = block
    }
}

extension UIButton {
    func addTarget(controlEvents: UIControlEvents, blick: ButtonBlock) {
        objc_setAssociatedObject(self, &ActionBlockKey, ActionBlockWrapper.init(block: blick), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        addTarget(self, action: #selector(UIButton.processButton(_:)), forControlEvents: controlEvents)
    }
    
    func processButton(sender: UIButton) {
        let wrapper = objc_getAssociatedObject(self, &ActionBlockKey) as! ActionBlockWrapper
        wrapper.block!(sender: sender)
    }
}

四、方法交换

OC中的方法交换:

Method p1 = class_getInstanceMethod([Persion class], @selector(p1));
Method p2 = class_getInstanceMethod([Persion class], @selector(p2));
method_exchangeImplementations(p1, p2);
[p p1];
swift中的方法交换: 
let p1: Method = class_getInstanceMethod(ViewController.self, #selector(ViewController.mothodFirst))
let p2: Method = class_getInstanceMethod(ViewController.self, #selector(ViewController.mothodSecond))
method_exchangeImplementations(p1, p2)
mothodFirst()

五、解档、归档:当一个对象有很多属性需要进行解/归档的时候,不用一个个属性的去写解/归档操作

这里我定义了一个Persion类来说明

@interface Persion : NSObject
@property (copy, nonatomic) NSString * name;
@property (assign, nonatomic) int age;
@property (copy, nonatomic) NSNumber * height;
@end
实现:
- (void)encodeWithCoder:(NSCoder *)coder
{
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList([Persion class], &count);
    
    for (int i = 0; i < count; i++) {
        Ivar ivar = ivars[i];
        const char * name = ivar_getName(ivar);
        NSString * strName = [NSString stringWithUTF8String:name];
        // kvc 取值
        id value = [self valueForKey:strName];
        [coder encodeObject:value forKey:strName];
    }
    free(ivars);
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        unsigned int count = 0;
        // 获取类中所有成员变量名
        Ivar * ivars = class_copyIvarList([Persion class], &count);
        for (int i = 0; i < count; i++) {
            Ivar ivar = ivars[i];
            const char * name = ivar_getName(ivar);
            NSString * strName = [NSString stringWithUTF8String:name];
            // 进行减档
            id value = [coder decodeObjectForKey:strName];
            // 利用kvc对属性赋值
            [self setValue:value forKey:strName];
        }
        free(ivars);
    }
    return self;
}
这样是不是很方便了呢







0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:81038次
    • 积分:1439
    • 等级:
    • 排名:千里之外
    • 原创:61篇
    • 转载:4篇
    • 译文:1篇
    • 评论:19条
    最新评论