以下筆記是邊看視頻課程邊記錄下來(lái)的,供以后自己查閱復(fù)習(xí)使用
Runtime學(xué)習(xí)筆記1
消息轉(zhuǎn)發(fā)
在OC中,調(diào)用方法其實(shí)是給對(duì)象發(fā)送消息
[[Person new] sendMessage:@"gelo"];
// 等價(jià)于
objc_msgSend([Person new], @selector(sendMessage:), "gelo");
通過(guò)對(duì)象的isa指針找到class,如果有方法的話(huà),直接調(diào)用。沒(méi)有找到的話(huà),通過(guò)繼承樹(shù)查找,進(jìn)入消息轉(zhuǎn)發(fā)機(jī)制

動(dòng)態(tài)方法解析,動(dòng)態(tài)添加方法實(shí)現(xiàn)
? resolveInstanceMethod
快速轉(zhuǎn)發(fā),當(dāng)前的類(lèi)或者繼承樹(shù)沒(méi)有該方法的實(shí)現(xiàn),在更加廣的范圍尋找
? forwardingTargetForSelector
慢速轉(zhuǎn)發(fā)
? methodSignatureForSelector
? forwardInvocation
doesNotRecognizeSelector:
方法交換 Method Swizzling
用自己寫(xiě)的方法替換系統(tǒng)方法,通過(guò)class_getInstanceMethod方法獲取,通過(guò)method_exchangeImplementations交換兩個(gè)函數(shù)
字典轉(zhuǎn)模型
遍歷字典獲取key和value
key作為屬性名,value作為屬性值
通過(guò)objc_msgSend發(fā)送set方法
模型轉(zhuǎn)字典
字典的key通過(guò)模型的屬性列表獲取
字典的value通過(guò)調(diào)用get方法獲取
實(shí)現(xiàn)KVO
KVO是基于runtime的
A監(jiān)聽(tīng)B 系統(tǒng)會(huì)為B創(chuàng)建一個(gè)子類(lèi)
B的isa指針指向B的子類(lèi)
在子類(lèi)中重新set方法
KVO底層實(shí)現(xiàn)
KVO的基礎(chǔ)使用
觀(guān)察某一個(gè)對(duì)象的某個(gè)屬性
options參數(shù)可以觀(guān)察一下幾個(gè)值
new 返回變化后的新值
old 返回變化前的舊值
init 注冊(cè)的時(shí)候就會(huì)發(fā)一次通知,改變后的值的時(shí)候也會(huì)發(fā)送
prior 新值和舊值都會(huì)返回
KVO默認(rèn)是自動(dòng)模式,每次修改值都會(huì)發(fā)送通知
手動(dòng)發(fā)送通知的時(shí)候,對(duì)象調(diào)用willchangeValueForKey,改變之后調(diào)用didchangeValueForKey
監(jiān)聽(tīng)屬性下面的屬性值,只需要在監(jiān)聽(tīng)path中通過(guò)點(diǎn)監(jiān)聽(tīng):"dog.age"(屬性依賴(lài))
KVO監(jiān)聽(tīng)的是set方法。比如監(jiān)聽(tīng)不到數(shù)組的add方法
要是需要監(jiān)聽(tīng)容器方法,需要結(jié)合KVC
需要監(jiān)聽(tīng)對(duì)象下多個(gè)屬性,只需要監(jiān)聽(tīng)對(duì)象本身,并實(shí)現(xiàn)keyPat***ForKey。返回需要的真正監(jiān)聽(tīng)的內(nèi)部屬性的NSSet
內(nèi)部實(shí)現(xiàn)
屬性是對(duì)成員變量和set、get方法的封裝
KVO觀(guān)察的是set方法(設(shè)置成員變量之后,外部通過(guò)person->name方法修改,KVO監(jiān)聽(tīng)不到)通過(guò)runtime創(chuàng)建一個(gè)觀(guān)察者的子類(lèi)(NSKVONotifying_Person)重寫(xiě)set方法。修改指針到子類(lèi)、在重寫(xiě)的方法里面調(diào)用willchangeValueForKey、superSetName、didchangeValueForKey。
在創(chuàng)建的子類(lèi)中,沒(méi)有父類(lèi)的set方法!需要重寫(xiě)set方法
OC的方法中包含SEL(方法編號(hào))、IMP(方法實(shí)現(xiàn))一一對(duì)應(yīng)。調(diào)用方法的時(shí)候發(fā)送的是SEL
OC的方法調(diào)用里面有兩個(gè)默認(rèn)參數(shù):id self,SEL _cmd。由于sendMsg傳遞了該參數(shù)(調(diào)用者以及SEL)
監(jiān)聽(tīng)容器類(lèi)(NSArray、NSDic)
通過(guò)KVO觀(guān)察容器屬性的變化,利用KVC
通過(guò)KVC的mutableArray**ForKey返回一個(gè)容器對(duì)象,向該對(duì)象添加元素可以實(shí)現(xiàn)KVO。內(nèi)部新建子類(lèi)、重寫(xiě)add方法。
KVO返回的NSDic中,kind類(lèi)型
觀(guān)察set方法 返回1
觀(guān)察插入方法 返回2
觀(guān)察刪除方法 返回3
觀(guān)察替換方法 返回4
數(shù)組中count
使用KVO中監(jiān)聽(tīng)不到數(shù)組中的count、使用KVC同樣取不到[array valueForKey:@"count"]
count是集合運(yùn)算符,KVC需要用@"@count"取值。
count是只讀屬性
數(shù)組(NSMutableArray)
關(guān)于數(shù)組的容量,容量不夠用的時(shí)候,會(huì)成倍的增加
對(duì)象本身是指針,指向該對(duì)象的結(jié)構(gòu)體
x/100xb arr 打印arr 100個(gè)內(nèi)存地址
找到count的內(nèi)存地址,修改內(nèi)存地址的值,進(jìn)而可以修改count的值
Runtime學(xué)習(xí)筆記2
消息機(jī)制
OC代碼會(huì)轉(zhuǎn)化為C語(yǔ)言執(zhí)行,使用runtime的時(shí)候,需要關(guān)閉代碼的嚴(yán)格檢測(cè)
調(diào)用函數(shù)的方法:
[p eat]
[p performSelector: SEL]
objc_msgSend()
使用runtime創(chuàng)建對(duì)象:
類(lèi)名.class即為對(duì)象 Person.class == objc_getClass("Person")
// 在目錄下執(zhí)行
clang --rewrite-objc main.m
// 手動(dòng)編譯OC代碼生成cpp文件
歸檔/解檔
歸檔和解檔對(duì)象,需要遵循NSCoding的協(xié)議,并且實(shí)現(xiàn)協(xié)議方法
KVC可以使用id類(lèi)型為屬性賦值
Ivar:成員變量
Method:成員方法
C語(yǔ)言 基本數(shù)據(jù)類(lèi)型的指針 函數(shù)內(nèi)部是為了修改外部的值
class_copyIvarList獲取所有屬性數(shù)量
關(guān)鍵字copy、new、creat代表著會(huì)在堆區(qū)域(malloc)開(kāi)辟空間
方法執(zhí)行完畢—>方法調(diào)用棧平衡—>內(nèi)部變量指針出?!?gt;但是指針指向的堆區(qū)的值還在—>內(nèi)存泄漏
在OC中使用C的代碼,要手動(dòng)釋放指針,防止內(nèi)存溢出
OC方法定位以及替換
OC的方法表:返回值類(lèi)型+參數(shù)類(lèi)型一樣 編號(hào)就一樣
? 類(lèi)
SEL 編號(hào) ————— IMP實(shí)現(xiàn)(地址指針)
SEL 編號(hào) ————— IMP實(shí)現(xiàn)(地址指針)
SEL 編號(hào) ————— IMP實(shí)現(xiàn)(地址指針)
用HOOK!鉤住系統(tǒng)方法,在調(diào)用之前修改方法的調(diào)用
在分類(lèi)中的load方法(由于預(yù)加載,比main更早執(zhí)行)中交換IMP
#import <objc/runtime.h>
+ (void)load {
// 獲取替換后的類(lèi)方法
Method otherMethod = class_getClassMethod([UIImage class], @selector(imageNameNextWith:));
// 獲取替換前的類(lèi)方法
Method method = class_getClassMethod([UIImage class], @selector(imageNamed:));
// 然后交換類(lèi)方法
method_exchangeImplementations(otherMethod, method);
}
+ (UIImage *)imageNameNextWith:(NSString *)nameString {
UIImage *image = nil;
image = [UIImage imageNameNextWith:[nameString stringByAppendingString:@"tupian.jpg"]];
return image;
}
關(guān)于在imageNameNextWith中調(diào)用自身,并不會(huì)引起循環(huán)引用。
交換之前
SEL(系統(tǒng)方法:ImageNamed) —————> IMP(系統(tǒng)方法:ImageNamed的實(shí)現(xiàn)地址指針)
SEL(自己的方法:ImageNamedNextWith) —————> IMP(自己的方法:ImageNamedNextWith的實(shí)現(xiàn)地址指針)
交換之后
SEL(系統(tǒng)方法:ImageNamed) —————> IMP(自己的方法:ImageNamedNextWith的實(shí)現(xiàn)地址指針)
SEL(自己的方法:ImageNamedNextWith) —————> IMP(系統(tǒng)方法:ImageNamed的實(shí)現(xiàn)地址指針)
交換之后,每當(dāng)再次調(diào)用imageNameNextWith方法的時(shí)候,實(shí)際上執(zhí)行的是系統(tǒng)方法ImageNamed指向的方法實(shí)現(xiàn),所以不會(huì)引起循環(huán)調(diào)用。
OC對(duì)象本質(zhì)上是指針占用8個(gè)字節(jié)
OC方法調(diào)用順序:消息發(fā)送——>SEL——>IMP——>代碼——>函數(shù)——>匯編
函數(shù)響應(yīng)式編程RAC
RAC的代理
RAC里面內(nèi)部實(shí)現(xiàn)類(lèi)似于通知
- 創(chuàng)建信號(hào) 提供外界訂閱
創(chuàng)建了一個(gè)容量為1的可變數(shù)組_subscribers
支持多個(gè)訂閱者訂閱該信號(hào)
RACSubject *subject = [RACSubject subject];
- 訂閱信號(hào)(注冊(cè)通知)
創(chuàng)建訂閱者對(duì)象
將Block放到訂閱者對(duì)象中
將訂閱者對(duì)象放入_subscribers里面
[subject subscribeNext:^(id){
// 函數(shù)式編程,免除了遵循協(xié)議,引用方法的步驟
}];
- 發(fā)送信號(hào)(發(fā)起通知)
遍歷_subscribers取出中的訂閱者對(duì)象
執(zhí)行訂閱者對(duì)象中的Block
[subject sentNext:@"hahha];
RAC中可以使用Selector通過(guò)方法名稱(chēng)創(chuàng)建信號(hào),直接訂閱
RAC中的KVO
RAC可以直接用Block回調(diào),在觀(guān)察多個(gè)屬性的時(shí)候,可以避免在回調(diào)函數(shù)中判斷。
RAC同樣不能觀(guān)察到數(shù)組的count
RAC監(jiān)聽(tīng)事件
將按鈕的點(diǎn)擊事件包裝成信號(hào),訂閱
RAC中的Timer
使用NSTimer的時(shí)候,創(chuàng)建完之后需要添加到NSRunLoop中
在NSTread子線(xiàn)程中需要手動(dòng)啟動(dòng)NSRunLoop
[[NSRunLoop currentRunLoop] run]
RAC中通過(guò)信號(hào)創(chuàng)建子線(xiàn)程并發(fā)Timer,底層使用GCD創(chuàng)建
RAC中的宏定義
當(dāng)輸入框內(nèi)容發(fā)生變化,相應(yīng)更新到_label上
RAC(_label, text) = _textField.rac_textSignal;
只要對(duì)象的屬性發(fā)生改變,就會(huì)產(chǎn)生信號(hào)
RACObserver(self, name) sub....
關(guān)于Block中的循環(huán)引用,但是在特殊情況下是允許循環(huán)應(yīng)用的出現(xiàn)
NSURLSession中的delegate是強(qiáng)引用,目的是發(fā)送請(qǐng)求的時(shí)候只需要一個(gè)對(duì)象。是單例
使用強(qiáng)引用,并不會(huì)銷(xiāo)毀,導(dǎo)致內(nèi)存泄漏
Socket探索
IP地址可以在網(wǎng)絡(luò)上定位到一臺(tái)終端設(shè)備
端口號(hào)可以訪(fǎng)問(wèn)到設(shè)備上的服務(wù):比如80端口為Apache端口服務(wù)
網(wǎng)絡(luò)的七層協(xié)議從上至下:應(yīng)用層、表示層、會(huì)話(huà)層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層、物理層
標(biāo)準(zhǔn)幀格式數(shù)據(jù)包
socket處于傳輸層、IP/TCP協(xié)議在網(wǎng)絡(luò)層
TCP與UDP協(xié)議的區(qū)別
UDP(用戶(hù)數(shù)據(jù)報(bào)協(xié)議)短信
? 只管發(fā)送,不確認(rèn)對(duì)方是否收到
? 將數(shù)據(jù)及源和目的封裝成數(shù)據(jù)包中,不需要建立連接
? 每個(gè)數(shù)據(jù)報(bào)大小限制在64k
? 因?yàn)闊o(wú)需連接,因此是不可靠協(xié)議
? 不需要連接,速度快
TCP(傳輸控制協(xié)議)電話(huà)
? 建立連接,形成傳輸數(shù)據(jù)通道
? 在連接中進(jìn)行大數(shù)據(jù)傳輸(數(shù)據(jù)大小不受限制)
? 通過(guò)三次握手連接,是可靠的協(xié)議,安全送達(dá)
? 必須建立連接,效率稍低
直播推流、游戲是UDP協(xié)議,下載的過(guò)程是TCP協(xié)議
Socket
類(lèi)比插座,socket需要兩端的IP+端口號(hào)建立連接
- 創(chuàng)建socket
/*
domain: 協(xié)議域 AF_INET = IPV4 IPV6
type: Socket類(lèi)型 SOCK_STREAM(TCP)/SOCK_DGRAM(UDP)
protocol: IPPROTO_TCP, 傳入0, 會(huì)自動(dòng)根據(jù)第二個(gè)值選擇合適的協(xié)議
*/
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
- 連接服務(wù)器
/*
客戶(hù)端socket
服務(wù)器IP地址結(jié)構(gòu)體指針
結(jié)構(gòu)體長(zhǎng)度
*/
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;//IPV4
serverAddr.sin_port = htons(80);//端口號(hào)
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");//IP地址
int connectResult = connect();
// 返回0代表連接成功
netcat工具,用于監(jiān)聽(tīng)本地端口
- 發(fā)送數(shù)據(jù)
/*
客戶(hù)端socket
發(fā)送內(nèi)容地址
發(fā)送內(nèi)容長(zhǎng)度
發(fā)送方式標(biāo)志,一般為0
返回值
發(fā)送成功之后返回發(fā)送字節(jié)長(zhǎng)度,失敗返回error
*/
send();
- 讀取數(shù)據(jù)
/*
客戶(hù)端socket
接受內(nèi)容緩沖區(qū)域地址
接受內(nèi)容緩沖區(qū)長(zhǎng)度
接受方式標(biāo)志,0表示阻塞,必須等待服務(wù)器返回?cái)?shù)據(jù)
返回值
接受成功之后返回發(fā)送字節(jié)長(zhǎng)度,失敗返回error
*/
uint8_t buffer[1024];
recv();
通過(guò)data數(shù)據(jù)讀取二進(jìn)制數(shù)組,解析返回字節(jié)流
- 關(guān)閉socket
close();
HTTP訪(fǎng)問(wèn)
通過(guò)向百度的IP地址,發(fā)送"GET HTTP/1.1\n Host: www.baidu.com\n\n"可以接收到百度服務(wù)器返回的百度首頁(yè)數(shù)據(jù)。
手寫(xiě)了一個(gè)HTTP協(xié)議
Connection被廢棄的原因
異步下載,無(wú)法回調(diào)數(shù)據(jù),因?yàn)镽unloop默認(rèn)在子線(xiàn)程不開(kāi)啟
線(xiàn)程管理
線(xiàn)程中有任務(wù)才有可能不被釋放
HTTPS協(xié)議
https本身不會(huì)對(duì)客戶(hù)端進(jìn)行驗(yàn)證
加密算法:RSA
RSA:公鑰和私鑰
明文+公鑰 = 密文
密文+私鑰 = 明文
第一次請(qǐng)求HTTPS服務(wù)器,客戶(hù)端安裝證書(shū)(下載公鑰并保存),通訊時(shí)通過(guò)該公鑰加密傳輸
登錄校驗(yàn)時(shí)隨機(jī)鹽可以提高安全性
加密詳解
Base64
base64是編碼方式,不屬于加密算法
可以將任意的二進(jìn)制數(shù)據(jù)進(jìn)行編碼 編碼成為65中字符的文本文件
0-9,a-z,A-Z,+ / =
對(duì)稱(chēng)加密:
DES
3DES
AES(高級(jí)密碼標(biāo)準(zhǔn))
數(shù)學(xué)算法:
哈希函數(shù)MD5
內(nèi)存釋放
free()以及CFRelease()的區(qū)別
單元測(cè)試
setup 初始化
tearDown 銷(xiāo)毀
所有的測(cè)試用例必須以test開(kāi)頭
given
when
then
架構(gòu)模式
MVC解耦
vc代碼過(guò)于沉重
代碼耦合性過(guò)高 UI與Model的通訊
MVP
面向協(xié)議編程---代理
@synchronized(self)多線(xiàn)程鎖
通過(guò)代理使UI與Model通訊
MVVM
雙向綁定:數(shù)據(jù)和UI的綁定,即修改一處另一處隨之修改
異步的一般處理:代理、通知、匿名函數(shù)(Block)
從數(shù)據(jù) -----> UI 通過(guò)Block進(jìn)行通訊
從UI -------> 數(shù)據(jù) 通過(guò)KVO監(jiān)聽(tīng)通訊
NSMutableArray是線(xiàn)程不安全的,在處理里面的數(shù)據(jù)的時(shí)候需要加鎖
多線(xiàn)程
進(jìn)程
線(xiàn)程
NSThread
- alloc init
+ detacNewThread
- self perform

線(xiàn)程的名稱(chēng)
線(xiàn)程的優(yōu)先級(jí)
多線(xiàn)程的共享資源
線(xiàn)程不安全:獲取的數(shù)據(jù)和預(yù)期可能不一樣
互斥鎖:線(xiàn)程同步,@synchronized 當(dāng)一個(gè)線(xiàn)程在操作數(shù)據(jù)的時(shí)候,其它線(xiàn)程不得操作該數(shù)據(jù)
原子屬性 atomic
原子屬性是線(xiàn)程安全的,自旋鎖
原子屬性的成員變量,在set方法中會(huì)添加@synchronized保護(hù)線(xiàn)程安全