東阿做網(wǎng)站網(wǎng)絡廣告宣傳怎么做
一、遍歷類的屬性,快速歸檔
在 iOS 中,可以使用 Runtime 遍歷類的屬性來實現(xiàn)快速的歸檔(Archiving)操作。歸檔是將對象轉換為數(shù)據(jù)流以便存儲或傳輸?shù)倪^程。下面是一個簡單的示例,展示如何使用 Runtime 遍歷類的屬性進行歸檔操作:
假設有一個名為 Person
的類,我們想要對其屬性進行歸檔操作:
#import <objc/runtime.h>@interface Person : NSObject <NSCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end@implementation Person- (void)encodeWithCoder:(NSCoder *)coder {unsigned int count;objc_property_t *properties = class_copyPropertyList([self class], &count);for (int i = 0; i < count; i++) {objc_property_t property = properties[i];NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];id propertyValue = [self valueForKey:propertyName];[coder encodeObject:propertyValue forKey:propertyName];}free(properties);
}- (instancetype)initWithCoder:(NSCoder *)coder {self = [super init];if (self) {unsigned int count;objc_property_t *properties = class_copyPropertyList([self class], &count);for (int i = 0; i < count; i++) {objc_property_t property = properties[i];NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];id propertyValue = [coder decodeObjectForKey:propertyName];[self setValue:propertyValue forKey:propertyName];}free(properties);}return self;
}@end
在上面的示例中,encodeWithCoder:
方法遍歷了 Person
類的所有屬性,并將屬性的值使用 NSCoder
進行歸桋操作。initWithCoder:
方法則對歸檔的數(shù)據(jù)進行解檔,恢復對象的狀態(tài)。
通過使用 Runtime 遍歷類的屬性,我們可以實現(xiàn)一個通用的歸檔和解檔方法,而無需手動編寫大量的歸檔代碼。這樣可以提高代碼的復用性和可維護性。
二、字典轉模型
1、創(chuàng)建一個NSObject的分類
@interface NSObject (Json)
+ (instancetype)dictToModel:(NSDictionary *)dict;
@end
2、實現(xiàn)分類中字典轉模型的方法
#import "NSObject+Json.h"
#import <objc/runtime.h>@implementation NSObject (Json)+ (instancetype)dictToModel:(NSDictionary *)dict
{id obj = [[self alloc] init];unsigned int count = 0;Ivar *ivars = class_copyIvarList([self class], &count);for (int i=0; i<count; i++) {Ivar ivar = ivars[i];NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];[name deleteCharactersInRange:NSMakeRange(0, 1)]; [obj setValue:dict[name] forKey:name];}return obj;
}
@end
3、調用字典轉模型的方法
- (void)viewDidLoad {[super viewDidLoad];NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];[dict setObject:@"張三" forKey:@"name"];[dict setObject:@"20" forKey:@"age"];[dict setObject:@"北京" forKey:@"address"];Student *student = [Student dictToModel:dict];NSLog(@"name:%@\n",student.name);NSLog(@"age:%@\n",student.age);NSLog(@"address:%@\n",student.address);
}
4、運行結果
2019-04-13 10:51:32.136568+0800 AppLife[19195:4640916] name:張三
2019-04-13 10:51:32.136707+0800 AppLife[19195:4640916] age:20
2019-04-13 10:51:32.136803+0800 AppLife[19195:4640916] address:北京
三 防止數(shù)組插入空值
1、創(chuàng)建一個NSMutableArray的分類
@interface NSMutableArray (Extension)@end
2、實現(xiàn)分類中方法的交換
#import "NSMutableArray+Extension.h"
#import <objc/runtime.h>@implementation NSMutableArray (Extension)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{Class cls = NSClassFromString(@"__NSArrayM");Method method1 = class_getInstanceMethod(cls, @selector(insertObject:atIndex:));Method method2 = class_getInstanceMethod(cls, @selector(cs_insertObject:atIndex:));method_exchangeImplementations(method1, method2);});
}- (void)cs_insertObject:(id)anObject atIndex:(NSUInteger)index {if (anObject == nil) {return;}[self cs_insertObject:anObject atIndex:index];
}@end
3、調用
#import "NSMutableArray+Extension.h"
#import <objc/runtime.h>@implementation NSMutableArray (Extension)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{Class cls = NSClassFromString(@"__NSArrayM");Method method1 = class_getInstanceMethod(cls, @selector(insertObject:atIndex:));Method method2 = class_getInstanceMethod(cls, @selector(cs_insertObject:atIndex:));method_exchangeImplementations(method1, method2);});
}- (void)cs_insertObject:(id)anObject atIndex:(NSUInteger)index {if (anObject == nil) {return;}[self cs_insertObject:anObject atIndex:index];
}@end
4、運行結果
2019-04-13 11:24:19.562363+0800 AppLife[20661:4661256] (Test
)
運用Rutime中交換方法的思想,還可以實現(xiàn)攔截所有按鈕的點擊時間和防止字典中插入空值等。
四、給分類添加屬性
1、在分類里聲明一個屬性
#import "Student.h"@interface Student (Test)
@property (nonatomic, copy) NSString *englishName;
@end
2、實現(xiàn)get和set方法
@implementation Student (Test)- (void)setEnglishName:(NSString *)englishName
{// 第一個參數(shù):給哪個對象添加關聯(lián)// 第二個參數(shù):關聯(lián)的key,通過這個key獲取// 第三個參數(shù):關聯(lián)的value// 第四個參數(shù):關聯(lián)的策略objc_setAssociatedObject(self, @"EnglishName", englishName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}- (NSString *)englishName
{return objc_getAssociatedObject(self, @"EnglishName");
}@end
五、其他
(1) 實現(xiàn)第一個場景:跟蹤程序每個ViewController展示給用戶的次數(shù),可以通過Method Swizzling替換ViewDidAppear初始方法。創(chuàng)建一個UIViewController的分類,重寫自定義的ViewDidAppear方法,并在其+load方法中實現(xiàn)ViewDidAppear方法的交換。
(2) 開發(fā)中常需要在不改變某個類的前提下為其添加一個新的屬性,尤其是為系統(tǒng)的類添加新的屬性,這個時候就可以利用Runtime的關聯(lián)對象(Associated Objects)來為分類添加新的屬性了。
(3) 實現(xiàn)字典的模型和自動轉換,優(yōu)秀的JSON轉模型第三方庫JSONModel、YYModel等都利用runtime對屬性進行獲取,賦值等操作,要比KVC進行模型轉換更加強大,更有效率。閱讀YYModel的源碼可以看出,YY大神對NSObject的內(nèi)容進行了又一次封裝,添加了許多描述內(nèi)容。其中YYClassInfo是對Class進行了再次封裝,而YYClassIvarInfo、YYClassMethodInfo、YYClPropertyInfo分別是對Class的Ivar、Method和property進行了封裝和描述。在提取Class的相關信息時都運用了Runtime。