新建一個(gè)OSX命令行項(xiàng)目,是一個(gè)然后看代碼加命令行,顯示結(jié)果
main.m文件
#import <Foundation/Foundation.h>
#import "TTSleep.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// OC的代碼
TTSleep *tt = [[TTSleep alloc] init];
/** 底層c的代碼
TTSleep *tt = ((TTSleep *(*)(id, SEL))(void *)objc_msgSend)((id)((TTSleep *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("TTSleep"), sel_registerName("alloc")), sel_registerName("init"));
*/
}
return 0;
}
命令行編譯OC語(yǔ)言
將OC編譯成c語(yǔ)言的東西:cd到此目錄下,然后:clang -rewrite-objc main.m
你就可以看到
文件名
runtime的兩個(gè)必要常識(shí):
1.Method :成員方法
2.Ivar:成員變量
快捷鍵:cmd+shift+0 :打開(kāi)官方文檔
runtime的函數(shù):
1.class_copyIvarList 拷貝出成員變量列表
2.class_copyMethodList 成員方法
message的函數(shù):
1.objc_msgSend:給某一個(gè)對(duì)象發(fā)送消息
2.objc_msgSendSuper:給對(duì)象父類(lèi)發(fā)送消息
兩者開(kāi)頭不同
Ivar的函數(shù)
ivar_getName:(<#Ivar v#>) :給我一個(gè)ivar給你一個(gè)名稱(chēng)
runtime的應(yīng)用場(chǎng)景:
1.歸檔
在Controllers中寫(xiě)一些方法含義和變量含義
#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "TTPerson.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
unsigned int count = 0;
/**
在controller中runtime實(shí)現(xiàn)
runtime是底層C的庫(kù),所以C用的最多的就是指針指向首地址
第一個(gè):class 第二個(gè):conut的指針地址(可以在內(nèi)部改變值)
*/
Ivar *ivars = class_copyIvarList([TTPerson class], &count);
NSLog(@"%d",count); /// 此時(shí)的count就是你這個(gè)類(lèi)里面的屬性列表
for (int i =0; i<count; i++) {
// 取出屬性
Ivar ivar = ivars[i]; ///C語(yǔ)言的指針就像OC中的數(shù)組,根據(jù)角標(biāo)獲取值
// 查看變量名稱(chēng)
const char *name = ivar_getName(ivar);
NSLog(@"%s",name); // 這里%s就是c里面的字符占位符
}
}
在自定義類(lèi)中實(shí)現(xiàn)歸檔
// Copyright ? 2016年 糖糖. All rights reserved.
/// 歸檔
#import "TTPerson.h"
#import <objc/runtime.h>
#import <objc/message.h>
@interface TTPerson ()<NSCoding> // 實(shí)現(xiàn)歸檔協(xié)議
@end
@implementation TTPerson
/// 歸檔
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.name forKey:@"name"];
/* 所有屬性寫(xiě)完:如果有N多個(gè)屬性,歸檔會(huì)寫(xiě)很多冗余的代碼*/
/** runtime實(shí)現(xiàn)歸檔
count:裝載成員屬性個(gè)數(shù),可以在runtime內(nèi)部改變
*/
unsigned int count = 0;
//取出成員屬性列表
Ivar *ivars = class_copyIvarList([TTPerson class], &count);
for (int i =0; i<count; i++) {
// 取出屬性
Ivar ivar = ivars[i]; ///C語(yǔ)言的指針就像OC中的數(shù)組,根據(jù)角標(biāo)獲取值
// 查看變量名稱(chēng)
const char *name = ivar_getName(ivar);
// 根據(jù)key-value獲取屬性
NSString *key = [NSString stringWithUTF8String:name];
// 歸檔
[aCoder encodeObject:[self valueForKey:key] forKey:key];
}
// 在C語(yǔ)言中 只要用到了 copy/new/creat 就一定要釋放(不然會(huì)造成內(nèi)存泄露)
free(ivars);
}
/// 解檔
- (instancetype)initWithCoder:(NSCoder *)coder
{
if (self = [super init]) {
unsigned int count = 0;
//取出成員屬性列表
Ivar *ivars = class_copyIvarList([TTPerson class], &count);
for (int i =0; i<count; i++) {
// 取出屬性
Ivar ivar = ivars[i]; ///C語(yǔ)言的指針就像OC中的數(shù)組,根據(jù)角標(biāo)獲取值
// 查看變量名稱(chēng)
const char *name = ivar_getName(ivar);
// 根據(jù)key-value獲取屬性
NSString *key = [NSString stringWithUTF8String:name];
// 解檔
id value = [coder decodeObjectForKey:key];
//設(shè)置到成員變量上面(KVC設(shè)置)
[self setValue:value forKey:key];
}
// 在C語(yǔ)言中 只要用到了 copy/new/creat 就一定要釋放(不然會(huì)造成內(nèi)存泄露)
free(ivars);
}
return self;
}
@end
2.KVO內(nèi)部實(shí)現(xiàn)原理:
東西有點(diǎn)多涉及到了三個(gè)類(lèi)
KVO原理
控制器
##控制器中
// Copyright ? 2016年 糖糖. All rights reserved.
//
#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "TTPerson.h"
#import "TTDog.h"
@interface ViewController ()
// 強(qiáng)引用
@property (nonatomic,strong)TTPerson *person;
@property (nonatomic,strong)TTDog *dog;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[TTPerson alloc] init];
self.dog = [[TTDog alloc] init];
/**注冊(cè)監(jiān)聽(tīng)
NSKeyValueObservingOptionNew:傳遞新值
KVO內(nèi)部實(shí)現(xiàn)原理:通過(guò)runtime動(dòng)態(tài)的傳遞了一個(gè)對(duì)象。
在運(yùn)行的時(shí)候給TTDog動(dòng)態(tài)的創(chuàng)建并重寫(xiě)了一個(gè) [NSKVONotifying_TTDog setAge]
*/
[self.dog addObserver:self.person forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.dog.age = 10;
}
Person類(lèi):只貼寫(xiě)了代碼的地方
// Copyright ? 2016年 糖糖. All rights reserved.
#import "TTPerson.h"
@interface TTPerson ()
@end
@implementation TTPerson
/// 監(jiān)聽(tīng)到object的keyPath屬性變化為change
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"監(jiān)聽(tīng)到%@的%@屬性變化為%@",object,keyPath,change);
}
@end
TTDog類(lèi)
// Copyright ? 2016年 糖糖. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface TTDog : NSObject
@property (nonatomic,assign)NSInteger age;
@end
創(chuàng)建一個(gè)dog的子類(lèi)解釋KVO原理
// Copyright ? 2016年 糖糖. All rights reserved.
//
#import "NSKVONotifying_TTDog.h"
@implementation NSKVONotifying_TTDog
-(void)setAge:(NSInteger)age{
[super setAge:age];
// 在子類(lèi)中調(diào)用兩個(gè)方法:內(nèi)部都會(huì)調(diào)用TTPerson的observeValueForKeyPath 方法
[self willChangeValueForKey:@"age"]; //即將改變的時(shí)候獲取舊值
[self didChangeValueForKey:@"age"]; // 完成改變時(shí)獲取新值
}
輸出的日志信息