iOS學(xué)習(xí)筆記

以下筆記是邊看視頻課程邊記錄下來(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ī)制

runtime-forwardflow.png

動(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)似于通知

  1. 創(chuàng)建信號(hào) 提供外界訂閱

創(chuàng)建了一個(gè)容量為1的可變數(shù)組_subscribers

支持多個(gè)訂閱者訂閱該信號(hào)

RACSubject *subject = [RACSubject subject];
  1. 訂閱信號(hào)(注冊(cè)通知)

創(chuàng)建訂閱者對(duì)象

將Block放到訂閱者對(duì)象中

將訂閱者對(duì)象放入_subscribers里面

[subject subscribeNext:^(id){
  // 函數(shù)式編程,免除了遵循協(xié)議,引用方法的步驟
}];
  1. 發(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)建立連接

  1. 創(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);
  1. 連接服務(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)本地端口

  1. 發(fā)送數(shù)據(jù)
/*
    客戶(hù)端socket
    發(fā)送內(nèi)容地址
    發(fā)送內(nèi)容長(zhǎng)度
    發(fā)送方式標(biāo)志,一般為0
    
    返回值
    發(fā)送成功之后返回發(fā)送字節(jié)長(zhǎng)度,失敗返回error
*/
send();
  1. 讀取數(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é)流
  1. 關(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
thread-status.png

線(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)程安全

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容