1.歸檔與反歸檔
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "Dog.h"
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *gender;
@property (nonatomic, strong) NSNumber *age;
@property (nonatomic, assign) NSInteger weight;
@property (nonatomic, strong) Dog *dog;
+ (Person *)personWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age weight:(NSInteger)weight;
- (void)getPersonMessage;
- (void)walkonTheStreet:(NSString *)str;
@end
#import "Person.h"
#import <objc/runtime.h>// 導(dǎo)入<objc/runtime.h>
@interface Person ()<NSCoding>
@end
@implementation Person
- (void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) { // 采用for循環(huán)遍歷屬性,無需一一歸檔
const char *cName = ivar_getName(ivarList[i]);
NSString *name = [NSString stringWithUTF8String:cName];
[aCoder encodeObject:[self valueForKey:name] forKey:name];
}
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) { // 采用for循環(huán)遍歷屬性,無需一一反歸檔
const char *cName = ivar_getName(ivarList[i]);
NSString *name = [NSString stringWithUTF8String:cName];
[self setValue:[aDecoder decodeObjectForKey:name] forKey:name];
}
}
return self;
}
如下方法
Ivar *class_copyIvarList(Class cls, unsigned int *outCount) //獲取所有成員變量
const char *ivar_getName(Ivar v) //獲取某個成員變量的名字
const char *ivar_getTypeEncoding(Ivar v) //獲取某個成員變量的類型編碼
Ivar class_getInstanceVariable(Class cls, const char *name) //獲取某個類中指定名稱的成員變量
id object_getIvar(id obj, Ivar ivar) //獲取某個對象中的某個成員變量的值
void object_setIvar(id obj, Ivar ivar, id value) //設(shè)置某個對象的某個成員變量的值
TypeEncoding:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1 // 編碼形式
打印實例變量
- (NSString *)description
{
/*
* class: 要獲取的某個類, outCount: 通過這一個函數(shù)執(zhí)行之后會將成員變量的個數(shù)賦值到此
*/
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i ++) {
// 每次獲取一個成員變量
Ivar ivar = ivarList[i];
// 打印成員變量的名字和類型編碼
NSLog(@"name = %s, type = %s",ivar_getName(ivar), ivar_getTypeEncoding(ivar));
}
return nil;
}
2.消息轉(zhuǎn)發(fā)
OC的消息發(fā)送機制根據(jù)方法名來尋找聲明完成的實例方法的實現(xiàn)方法,當(dāng)類中的方法只聲明而未實現(xiàn)時击敌,系統(tǒng)會在逐級父類中尋找方法的實現(xiàn)期丰,當(dāng)父類中均無方法的實現(xiàn)時, 系統(tǒng)會執(zhí)行以下方法柔逼,故可為未實行的方法進行消息轉(zhuǎn)發(fā)犯犁,添加實現(xiàn)
1 + resolveInstanceMethod:(SEL)sel // 為一個實例方法動態(tài)添加實現(xiàn)
+ resolveClassMethod:(SEL)sel // 為一個類方法動態(tài)添加實現(xiàn)
2 - (id)forwardingTargetForSelector:(SEL)aSelector
//為沒有實現(xiàn)的方法指定一個對象
3 - (void)forwardInvocation:(NSInvocation *)anInvocation
//子類重載這個方法為消息指定其他對象
a. 為一個實例方法動態(tài)添加實現(xiàn)
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// 將方法轉(zhuǎn)換為字符串
NSString *selString = NSStringFromSelector(sel);
if ([selString isEqualToString:@"walkonTheStreet:"]) {
// 為一個沒有實現(xiàn)的方法動態(tài)添加實現(xiàn)
/* cls: 類
name: 沒有實現(xiàn)的方法
IMP: 要添加的實現(xiàn)
types: 動態(tài)添加的實現(xiàn)的類型編碼*/
class_addMethod(self, @selector(walkonTheStreet:), (IMP)walkFunc, "V@:@"); // void的編碼為 V, SEL的編碼為 :
}
return [super resolveInstanceMethod:sel];
}
void walkFunc(id self,SEL sel, NSString *str){
NSLog(@"Person---%s------%@", __func__, str);
}
b. 為沒有實現(xiàn)的方法指定一個對象
方式1
- (id)forwardingTargetForSelector:(SEL)aSelector
{
NSString *selString = NSStringFromSelector(aSelector);
if ([selString isEqualToString:@"walkonTheStreet:"]) {
self.dog = [Dog new];
return self.dog;
}
return [super forwardingTargetForSelector:aSelector];
}
方式2
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([Dog instanceMethodSignatureForSelector:anInvocation.selector]) {
self.dog = [Dog new];
[anInvocation invokeWithTarget:self.dog];
}
}
// 給方法制定一個有效的簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
if (!methodSignature) {
methodSignature = [Dog instanceMethodSignatureForSelector:aSelector];
}
return methodSignature;
}
3.給類目添加實例變量
延展可為類添加屬性和方法, 但外界不可訪問; 類目可為類添加方法壁肋,但無法添加實例變量, 采用runtime可為類目添加外界可訪問的實例變量
#import <Foundation/Foundation.h>
@interface NSDictionary (Mydict)
@property (nonatomic,strong) NSString *name;
@end
#import "NSDictionary+Mydict.h"
#import <objc/runtime.h>
@implementation NSDictionary (Mydict)
/*
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) //為某個類關(guān)聯(lián)某個對象
id objc_getAssociatedObject(id object, const void *key)
//獲取到某個類的某個關(guān)聯(lián)對象
void objc_removeAssociatedObjects(id object) //移除已經(jīng)關(guān)聯(lián)的對象
*/
// 關(guān)聯(lián)后此屬性name在外界可以訪問号胚,并且通過移除對象方法隨時移除
- (void)setName:(NSString *)name
{
// objc: 要關(guān)聯(lián)的對象 key: 成員變量對應(yīng)的key值
// @selector(屬性名) value: value
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC); // set方法
}
- (NSString *)name
{
return objc_getAssociatedObject(self, @selector(name)); //get方法
}