來自:http://www.imlifengfeng.com/blog/?p=397 1、快速歸檔
-
(id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { unsigned int outCount; Ivar * ivars = class_copyIvarList([self class], &outCount); for (int i = 0; i < outCount; i ++) { Ivar ivar = ivars[i]; NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)]; [self setValue:[aDecoder decodeObjectForKey:key] forKey:key]; } } return self; }
-
(void)encodeWithCoder:(NSCoder *)aCoder { unsigned int outCount; Ivar * ivars = class_copyIvarList([self class], &outCount); for (int i = 0; i < outCount; i ++) { Ivar ivar = ivars[i]; NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)]; [aCoder encodeObject:[self valueForKey:key] forKey:key]; } }
2、Json到Model的轉化
-
(instancetype)initWithDict:(NSDictionary *)dict {
if (self = [self init]) { //(1)獲取類的屬性及屬性對應的類型 NSMutableArray * keys = [NSMutableArray array]; NSMutableArray * attributes = [NSMutableArray array]; /* * 例子 * name = value3 attribute = T@"NSString",C,N,V_value3 * name = value4 attribute = T^i,N,V_value4 */ unsigned int outCount; objc_property_t * properties = class_copyPropertyList([self class], &outCount); for (int i = 0; i < outCount; i ++) { objc_property_t property = properties[i]; //通過property_getName函數獲得屬性的名字 NSString * propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding]; [keys addObject:propertyName]; //通過property_getAttributes函數可以獲得屬性的名字和@encode編碼 NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding]; [attributes addObject:propertyAttribute]; } //立即釋放properties指向的內存 free(properties);
//(2)根據類型給屬性賦值for (NSString * key in keys) {if ([dict valueForKey:key] == nil) continue;[self setValue:[dict valueForKey:key] forKey:key];} 復制代碼
} return self; }
3、Category添加屬性并生成getter和setter方法 #import <Foundation/Foundation.h>
@interface NSArray (MyCategory) //不會生成添加屬性的getter和setter方法,必須我們手動生成 @property (nonatomic, copy) NSString *blog; @end
#import "NSArray+MyCategory.h" #import <objc/runtime.h>
@implementation NSArray (MyCategory)
// 定義關聯的key static const char *key = "blog";
/** blog的getter方法 */
- (NSString *)blog { // 根據關聯的key,獲取關聯的值。 return objc_getAssociatedObject(self, key); }
/** blog的setter方法 */
- (void)setBlog:(NSString *)blog { // 第一個參數:給哪個對象添加關聯 // 第二個參數:關聯的key,通過這個key獲取 // 第三個參數:關聯的value // 第四個參數:關聯的策略 objc_setAssociatedObject(self, key, blog, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end
4、Method Swizzling使用 #import "UIViewController+swizzling.h" #import <objc/runtime.h> @implementation UIViewController (swizzling)
- (void)load { // 通過class_getInstanceMethod()函數從當前對象中的method list獲取method結構體,如果是類方法就使用class_getClassMethod()函數獲取。 Method fromMethod = class_getInstanceMethod([self class], @selector(viewDidLoad)); Method toMethod = class_getInstanceMethod([self class], @selector(swizzlingViewDidLoad)); /**
- 我們在這里使用class_addMethod()函數對Method Swizzling做了一層驗證,如果self沒有實現被交換的方法,會導致失敗。
- 而且self沒有交換的方法實現,但是父類有這個方法,這樣就會調用父類的方法,結果就不是我們想要的結果了。
- 所以我們在這里通過class_addMethod()的驗證,如果self實現了這個方法,class_addMethod()函數將會返回NO,我們就可以對其進行交換了。 */ if (!class_addMethod([self class], @selector(swizzlingViewDidLoad), method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) { method_exchangeImplementations(fromMethod, toMethod); } }
// 我們自己實現的方法,也就是和self的viewDidLoad方法進行交換的方法。
- (void)swizzlingViewDidLoad { NSString *str = [NSString stringWithFormat:@"%@", self.class]; // 我們在這里加一個判斷,將系統的UIViewController的對象剔除掉 if(![str containsString:@"UI"]){ NSLog(@"統計打點 : %@", self.class); } [self swizzlingViewDidLoad]; } @end
5、Method Swizzling類簇 __NSArrayI才是NSArray真正的類 #import "NSArray+ MyArray.h" #import "objc/runtime.h" @implementation NSArray MyArray)
- (void)load {//是加載文件到內存執行的方法 跟類的生命周期沒有關系 Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:)); Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(my_objectAtIndex:)); method_exchangeImplementations(fromMethod, toMethod); }
- (id)my_objectAtIndex:(NSUInteger)index { if (self.count-1 < index) { // 這里做一下異常處理,不然都不知道出錯了。 @try { return [self my_objectAtIndex:index]; } @catch (NSException *exception) { // 在崩潰后會打印崩潰信息,方便我們調試。 NSLog(@"---------- %s Crash Because Method %s ----------\n", class_getName(self.class), func); NSLog(@"%@", [exception callStackSymbols]); return nil; } @finally {} } else { return [self my_objectAtIndex:index]; } } @end