動(dòng)態(tài)給分類添加屬性
1.創(chuàng)建UIGestureRecognizer的類目 UIGestureRecognizer+Block.h
#import "UIGestureRecognizer+Block.h"
#import <objc/runtime.h>
static const int target_key;
@implementation UIGestureRecognizer (Block)
+ (instancetype) yj_gesterRrecognizerWithAction:(YJBlock)block
{
__weak typeof(self) weakself = self;
return [[weakself alloc] initWithActionBlock:block];
}
- (instancetype) initWithActionBlock:(YJBlock)block
{
self = [self init];
[self addActionBlock:block];
[self addTarget:self action:@selector(invoke:)];
return self;
}
- (void) invoke:(id)sender
{
YJBlock block = objc_getAssociatedObject(self, &target_key);
if (block){
block(sender);
}
}
- (void) addActionBlock:(YJBlock)block
{
if (block){
objc_setAssociatedObject(self, &target_key, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
- id object 給誰添加就是誰的對(duì)象
- const void *key 關(guān)聯(lián)對(duì)象的key
- id value 被關(guān)聯(lián)者(要添加的屬性),這里是一個(gè)block()
- objc_AssociationPolicy policy : 關(guān)聯(lián)時(shí)采用的協(xié)議偏塞,有assign筹燕,retain耙饰,copy等協(xié)議谬返,一般使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
2.在創(chuàng)建的類中進(jìn)行調(diào)用
UIView *viewM = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
viewM.backgroundColor = [UIColor grayColor];
[self.view addSubview:viewM];
[viewM addGestureRecognizer:[UITapGestureRecognizer yj_gesterRrecognizerWithAction:^(id gesterRecognizer) {
NSLog(@"點(diǎn)擊了view");
}]];
方法的交換
1.創(chuàng)建UIImage的類目UIImage+hook.h
#import "UIImage+hook.h"
#import <objc/runtime.h>
@implementation UIImage (hook)
+(void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class selfClass = object_getClass([self class]);
SEL oriSEL = @selector(imageNamed:);
Method oriMethod = class_getInstanceMethod(selfClass, oriSEL);
SEL cusSEL = @selector(myImageNamed:);
Method cusMethod = class_getInstanceMethod(selfClass, cusSEL);
BOOL addSuccess = class_addMethod(selfClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
if (addSuccess){
class_replaceMethod(selfClass, cusSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
}else{
method_exchangeImplementations(oriMethod, cusMethod);
}
});
}
+(UIImage *)myImageNamed:(NSString *)name
{
NSString *newName = [NSString stringWithFormat:@"%@%@",@"new_",name];
return [self myImageNamed:newName];
}
@end
//替換方法
class_replaceMethod(<#Class _Nullable __unsafe_unretained cls#>, <#SEL _Nonnull name#>, <#IMP _Nonnull imp#>, <#const char * _Nullable types#>)
- 第一個(gè)參數(shù) class: 給哪個(gè)類添加參數(shù)
- 第二個(gè)參數(shù) SEL : 被替換的那個(gè)方法
- 第三個(gè)參數(shù) IMP : A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.
- 第四個(gè)參數(shù) types :An array of characters that describe the types of the arguments to the method.
2.調(diào)用
UIImageView *subView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
//圖片的實(shí)際名字是 new_Cart
[subView setImage:[UIImage imageNamed:@"Cart"]];
[self.view addSubview:subView];
字典轉(zhuǎn)模型
1.創(chuàng)建NSObjec的類別 NSObject+hook.h
#import "NSObject+hook.h"
#import <objc/runtime.h>
@implementation NSObject (hook)
const char *kPeropertyListKey = "kkkkkPeropertyListKey";
+ (instancetype) modelWithdict:(NSDictionary *)dict
{
/* 實(shí)例化對(duì)象*/
id objc = [[self alloc] init];
/* 使用字典,設(shè)置對(duì)象信息*/
/* 1.或者self的屬性列表*/
NSArray *propertyList = [self yj_PropertyList];
/* 2.遍歷字典*/
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
/* 3.判斷 key是否 propertyList中*/
if ([propertyList containsObject:key]){
/* 說明屬性存在,可以使用kvc 設(shè)置數(shù)值*/
[objc setValue:obj forKey:key];
}
}];
/*返回對(duì)象*/
return objc;
}
- (NSArray *) yj_PropertyList
{
NSArray *ptyList = objc_getAssociatedObject(self, kPeropertyListKey);
/* 如果 ptyList有值,直接返回*/
if (ptyList){
return ptyList;
}
/* 調(diào)用運(yùn)行時(shí)方法, 取得類的屬性列表 */
/* 成員變量:
* class_copyIvarList(__unsafe_unretained Class cls, unsigned int *outCount)
* 方法:
* class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)
* 屬性:
* class_copyPropertyList(__unsafe_unretained Class cls, unsigned int *outCount)
* 協(xié)議:
* class_copyProtocolList(__unsafe_unretained Class cls, unsigned int *outCount)
*/
unsigned int outCount = 0;
/**
* 參數(shù)1: 要獲取得類
* 參數(shù)2: 類屬性的個(gè)數(shù)指針
* 返回值: 所有屬性的數(shù)組, C 語言中,數(shù)組的名字,就是指向第一個(gè)元素的地址
*/
/* retain, creat, copy 需要release */
objc_property_t *properrtyList = class_copyPropertyList([self class], &outCount);
NSMutableArray *mtArray = [NSMutableArray array];
/* 遍歷所有屬性*/
for (unsigned int i = 0; i < outCount; i++) {
/* 從數(shù)組中取得屬性 */
objc_property_t property = properrtyList[i];
/* 從 property 中獲得屬性名稱 */
const char *propertyName_C = property_getName(property);
/* 將 C 字符串轉(zhuǎn)化成 OC 字符串 */
NSString *propertyName_OC = [NSString stringWithCString:propertyName_C encoding:NSUTF8StringEncoding];
[mtArray addObject:propertyName_OC];
}
/* 設(shè)置關(guān)聯(lián)對(duì)象 */
/**
* 參數(shù)1 : 對(duì)象self
* 參數(shù)2 : 動(dòng)態(tài)添加屬性的 key
* 參數(shù)3 : 動(dòng)態(tài)添加屬性值
* 參數(shù)4 : 對(duì)象的引用關(guān)系
*/
objc_setAssociatedObject(self, kPeropertyListKey, mtArray.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
/* 釋放 */
free(properrtyList);
return mtArray.copy;
}
@end
2.創(chuàng)建模型
#import <Foundation/Foundation.h>
#import "NSObject+hook.h"
@interface Model : NSObject
@property (copy,nonatomic) NSString *name;
@property (copy,nonatomic) NSString *sex;
@property (copy,nonatomic) NSString *age;
@end
3.調(diào)用
NSDictionary *dic = @{@"name":@"我愛NBA",
@"sex":@"男",
@"age":@25
};
Model *model = [Model modelWithdict:dic];
NSLog(@"name:%@ sex:%@ ",model.name,model.sex);
2018-02-28 09:50:32.343396+0800 RunTime使用場(chǎng)景[18298:1609962] name:我愛NBA sex:男
對(duì)私有屬性進(jìn)行修改
#pragma mark - 獲取所有的屬性(包括私有的)
- (void) getAllIvar
{
unsigned int count = 0;
//Ivar: 定義對(duì)象的實(shí)例變量,包括類型和名字
//獲取所有的屬性(包括私有的)
Ivar *ivars = class_copyIvarList([NSString class], &count);
for (int i = 0; i< count; i++) {
//去除成員變量
Ivar ivar = ivars[i];
NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];
NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
NSLog(@"屬性->%@ 和 %@",name,type);
}
}
- (void) getAllMethod
{
unsigned int count = 0;
Method *methodList = class_copyMethodList([UIPageControl class], &count);
for (int i = 0 ; i< count; i ++) {
Method method = methodList[i];
NSString *methodName = NSStringFromSelector(method_getName(method));
NSLog(@"方法名 ->%@",methodName);
}
}
歸檔解檔
1.創(chuàng)建YYModel
#import <Foundation/Foundation.h>
@interface YYModel : NSObject <NSCoding>
@property(nonatomic,assign) NSInteger age;
@property(nonatomic,copy) NSString *name1;
@property(nonatomic,copy) NSString *name2;
@property(nonatomic,copy) NSString *name3;
@property(nonatomic,copy) NSString *name4;
@property(nonatomic,copy) NSString *name5;
@end
------------------------------.m文件
#import "YYModel.h"
#import <objc/runtime.h>
@implementation YYModel
//NSKeyedUnarchiver 從二進(jìn)制流讀取對(duì)象姐叁。
//NSKeyedArchiver 把對(duì)象寫到二進(jìn)制流中去航背。
// 讀取實(shí)例變量铺董,并把這些數(shù)據(jù)寫到coder中去巫击。序列化數(shù)據(jù)
//1)禀晓、如果是類 就用encodeObject: forKey:
//2)、如果是普通的數(shù)據(jù)類型就用 eg坝锰、encodeInt: forKey:
- (void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int count = 0;
//利用runtime獲取實(shí)例變量的列表
Ivar *ivarList = class_copyIvarList([self class], &count);
for (int i =0; i< count; i++) {
//讀出i位置對(duì)應(yīng)的實(shí)例變量
Ivar ivar =ivarList[i];
//查看實(shí)例變量的名字
const char *name = ivar_getName(ivar);
//c語言字符串轉(zhuǎn)化為nsstring
NSString *namestr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
//利用kvo取出屬性對(duì)應(yīng)的值
id value = [self valueForKey:namestr];
//歸檔
[aCoder encodeObject:value forKey:namestr];
}
//記住c語言copy出來的要進(jìn)行釋放
free(ivarList);
}
//從coder中讀取數(shù)據(jù)粹懒,保存到相應(yīng)的變量中,即反序列化數(shù)據(jù)
//1)顷级、如果是類 就用decodeObjectForKey:
//2)凫乖、如果是普通的數(shù)據(jù)類型就用 eg、decodeIntForKey:
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
unsigned int count = 0;
Ivar *ivarList = class_copyIvarList([self class], &count);
for (int i = 0 ; i< count; i++) {
Ivar ivar = ivarList[i];
const char *name = ivar_getName(ivar);
NSString *namestr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
id value = [aDecoder decodeObjectForKey:namestr];
//設(shè)置到成員變量身上
[self setValue:value forKey:namestr];
}
free(ivarList);
}
return self;
}
@end
2.調(diào)用
YYModel *model = [[YYModel alloc] init];
model.age = 18;
model.name1 = @"胡航";
model.name2 = @"梁靜茹";
model.name3 = @"女女生";
//創(chuàng)建路徑
NSString *docunmentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSLog(@"docunmentPath路徑:%@",docunmentPath);
NSString *filePath = [docunmentPath stringByAppendingString:@"/YYModel.data"];
//存儲(chǔ)用戶信息,歸檔
BOOL result = [NSKeyedArchiver archiveRootObject:model toFile:filePath];
if (result) {
NSLog(@"歸檔成功%@",filePath);
}else{
NSLog(@"歸檔失敗");
}
YYModel *yy = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
NSLog(@"年齡%@\nname1:%@\nname2:%@",@(yy.age),yy.name1,yy.name2);
動(dòng)態(tài)添加方法
1.創(chuàng)建類dog
#import "Dog.h"
#import <objc/runtime.h>
@implementation Dog
// 默認(rèn)方法都有兩個(gè)隱式參數(shù)
void eat(id self,SEL sel){
NSLog(@"%@ %@",self,NSStringFromSelector(sel));
NSLog(@"動(dòng)態(tài)添加了一個(gè)方法");
}
//當(dāng)一個(gè)對(duì)象調(diào)用未實(shí)現(xiàn)的方法,會(huì)調(diào)用這個(gè)方法處理,并且會(huì)把對(duì)應(yīng)的方法列表傳過來
//剛好可以用來判斷,未實(shí)現(xiàn)的方法是不是我們想要添加動(dòng)態(tài)添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == NSSelectorFromString(@"eat")) {
//注意:這里需要強(qiáng)轉(zhuǎn)成IMP類型
class_addMethod(self, sel, (IMP)eat, "v@:");
return YES;
}
//先恢復(fù),不然會(huì)覆蓋系統(tǒng)的方法
return [super resolveInstanceMethod:sel];
}
@end
2.實(shí)現(xiàn)
Dog *dog = [[Dog alloc] init];
//默認(rèn)dog,沒有實(shí)現(xiàn)eat方法,可以通過performSelector調(diào)用,但是會(huì)報(bào)錯(cuò)
//動(dòng)態(tài)添加方法就不會(huì)報(bào)錯(cuò)
[dog performSelector:@selector(eat)];