runtime

2018-08-14  本文已影响8人  西门淋雨

给NSObject增加属性

#import <Foundation/Foundation.h>

@interface NSObject (runtime)
@property(nonatomic,strong)NSString *myTitle;
@end
#import "NSObject+runtime.h"
#import <objc/runtime.h>
static NSString *const kName = @"kName";
static NSString *const kTitle = @"kTitle";

@implementation NSObject (runtime)

- (void)setMyTitle:(NSString *)myTitle{
    objc_setAssociatedObject(self, &kTitle, myTitle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)myTitle{
    return objc_getAssociatedObject(self, &kTitle);
}
@end

弹框

#import <UIKit/UIKit.h>
typedef void (^AlertCallBlock)(NSInteger buttonIndex);
@interface UIAlertView (runtime)
- (void)showAlertWithBlock:(AlertCallBlock)block;
@end
#import "UIAlertView+runtime.h"
#import <objc/runtime.h>
static NSString *const kBlockKey = @"kBlockKey";
@implementation UIAlertView (runtime)
- (void)showAlertWithBlock:(AlertCallBlock)block{
    self.delegate = self;
    objc_setAssociatedObject(self, &kBlockKey, block, OBJC_ASSOCIATION_COPY);
    [self show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
    //根据给定的键从某对象中获取相应的关联对象值
    AlertCallBlock alertCallBack = objc_getAssociatedObject(self, &kBlockKey);
    if (alertCallBack) {
        alertCallBack(buttonIndex);
        objc_setAssociatedObject(self, &kBlockKey, nil, OBJC_ASSOCIATION_COPY);
    }
}
@end

Method Swizzling方法交换封装

/*************NSObject+Swizzling.h******************/
#import <objc/runtime.h>
@interface NSObject (Swizzling) 

+ (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector
                         bySwizzledSelector:(SEL)swizzledSelector;
@end

/*************NSObject+Swizzling.m******************/
#import "NSObject+Swizzling.h"
@implementation NSObject (Swizzling)

+ (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector bySwizzledSelector:(SEL)swizzledSelector{
    Class class = [self class];
    //原有方法
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    //替换原有方法的新方法
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
/**
先尝试給源SEL添加IMP,这里是为了避免源SEL没有实现IMP的情况.
class_addMethod会添加一个覆盖父类的实现,但不会取代原有类的实现。
也就是说如果class_addMethod返回YES,说明子类中没有方originalSelector,
通过class_addMethod为其添加了方法originalSelector,并使其实现(IMP)为我们想要替换的实现。
*/
    BOOL didAddMethod = class_addMethod(class,originalSelector,
                                        method_getImplementation(swizzledMethod),
                                        method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {//添加成功:说明源SEL没有实现IMP,将源SEL的IMP替换到交换SEL的IMP
        class_replaceMethod(class,swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {//添加失败:说明源SEL已经有IMP,直接将两个SEL的IMP交换即可
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
@end

分类可以添加@property的属性,但是仅仅是自动生成了get和set方法,并没有带下划线的属性和方法实现生成,但是runtime可以实现。
原理:给一个类声明属性,本质是给这个类添加关联,并不是直接把这个值的内存空间添加到类存空间。

上一篇下一篇

猜你喜欢

热点阅读