1, HTTP和HTTPS 區(qū)別,HTTPS證書驗證原理
區(qū)別
1,HTTP 明文傳輸,數(shù)據(jù)都是未加密的,安全性較差,HTTPS(SSL+HTTP) 數(shù)據(jù)傳輸過程是加密的,安全性較好。
2,使用 HTTPS 協(xié)議需要到 CA(Certificate Authority,數(shù)字證書認(rèn)證機構(gòu)) 申請證書,一般免費證書較少,因而需要一定費用。證書頒發(fā)機構(gòu)如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
3,HTTP 頁面響應(yīng)速度比 HTTPS 快,主要是因為 HTTP 使用 TCP 三次握手建立連接,客戶端和服務(wù)器需要交換 3 個包,而 HTTPS除了 TCP 的三個包,還要加上 ssl 握手需要的 9 個包,所以一共是 12 個包。
4,HTTP 和 HTTPS 使用的是完全不同的連接方式,用的端口也不一樣,前者是 80,后者是 443。
HTTPS 其實就是建構(gòu)在 SSL/TLS 之上的 HTTP 協(xié)議,所以,要比較 HTTPS 比 HTTP 要更耗費服務(wù)器資源
HTTPS證書驗證原理
1、客戶端發(fā)起 HTTPS 請求
這個沒什么好說的,就是用戶在瀏覽器里輸入一個 https 網(wǎng)址,然后連接到 server 的 443 端口。
2、服務(wù)端的配置
采用 HTTPS 協(xié)議的服務(wù)器必須要有一套數(shù)字證書,可以自己制作,也可以向組織申請,區(qū)別就是自己頒發(fā)的證書需要客戶端驗證通過,才可以繼續(xù)訪問,而使用受信任的公司申請的證書則不會彈出提示頁面(startssl 就是個不錯的選擇,有 1 年的免費服務(wù))。
這套證書其實就是一對公鑰和私鑰,如果對公鑰和私鑰不太理解,可以想象成一把鑰匙和一個鎖頭,只是全世界只有你一個人有這把鑰匙,你可以把鎖頭給別人,別人可以用這個鎖把重要的東西鎖起來,然后發(fā)給你,因為只有你一個人有這把鑰匙,所以只有你才能看到被這把鎖鎖起來的東西。
3、傳送證書
這個證書其實就是公鑰,只是包含了很多信息,如證書的頒發(fā)機構(gòu),過期時間等等。
4、客戶端解析證書
這部分工作是有客戶端的TLS來完成的,首先會驗證公鑰是否有效,比如頒發(fā)機構(gòu),過期時間等等,如果發(fā)現(xiàn)異常,則會彈出一個警告框,提示證書存在問題。
如果證書沒有問題,那么就生成一個隨機值,然后用證書對該隨機值進行加密,就好像上面說的,把隨機值用鎖頭鎖起來,這樣除非有鑰匙,不然看不到被鎖住的內(nèi)容。
5、傳送加密信息
這部分傳送的是用證書加密后的隨機值,目的就是讓服務(wù)端得到這個隨機值,以后客戶端和服務(wù)端的通信就可以通過這個隨機值來進行加密解密了。
6、服務(wù)端解密信息
服務(wù)端用私鑰解密后,得到了客戶端傳過來的隨機值(私鑰),然后把內(nèi)容通過該值進行對稱加密,所謂對稱加密就是,將信息和私鑰通過某種算法混合在一起,這樣除非知道私鑰,不然無法獲取內(nèi)容,而正好客戶端和服務(wù)端都知道這個私鑰,所以只要加密算法夠彪悍,私鑰夠復(fù)雜,數(shù)據(jù)就夠安全。
7、傳輸加密后的信息
這部分信息是服務(wù)段用私鑰加密后的信息,可以在客戶端被還原。
8、客戶端解密信息
客戶端用之前生成的私鑰解密服務(wù)段傳過來的信息,于是獲取了解密后的內(nèi)容,整個過程第三方即使監(jiān)聽到了數(shù)據(jù),也束手無策。
參考文章HTTP和HTTPS 區(qū)別 ,HTTP/HTTPS
2,常用的加密方式
常用加密算法
編碼方式 : Base64 Base58
哈希(散列)函數(shù) : MD5(消息摘要算法) SHA1 SHA256 SHA512
對稱加密算法 : DES AES
非對稱加密算法 : RSA(公鑰、私鑰) ECC
參考文章常用加密算法
3,isKindOfClass、isMemberOfClass區(qū)別,底層代碼實現(xiàn)差別
isKindOfClass 可判斷是否處于繼承鏈上的類
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
isMemberOfClass 只能判斷本身的類是否一致
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
區(qū)別是isKindOfClass 是for循環(huán)沿著繼承鏈,一級一級向上查找,isMemberOfClass只是判斷object_getClass((id)self),當(dāng)前objc是一個類對象,那么獲取的類就是當(dāng)前類的元類,如果objc是一個實例對象,那么獲取的就是當(dāng)前的類。
4,category,extension區(qū)別,從底層分析category為什么不能添加實例變量
Category是運行時決定生效的,Extension是編譯時就決定生效的
Category可以為系統(tǒng)類添加分類,Extension不能
Category是有聲明和實現(xiàn),Extension直接寫在宿主.m文件,只有聲明
Category只能擴充方法,不能擴充成員變量和屬性
如果Category聲明了聲明了一個屬性,那么Category只會生成這個屬性的set,get方法的聲明,也就不是會實現(xiàn)
Category底層結(jié)構(gòu)體 category_t 只有方法緩存,方法列表,協(xié)議列表以及屬性列表,并沒有存放成員變量的ivar,所以不支持添加成員變量,分析可參考這個文章 深入理解Category
5,objc_class , isa_t結(jié)構(gòu)
objc_class
/// OC 中對象的結(jié)構(gòu)體
struct objc_class : objc_object {
Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
// bits用于存儲類名、類版本號、方法列表、協(xié)議列表等信息,替代了Objective-C1.0中methodLists、protocols等成員變量。
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
// class_rw_t 表示 class 是readwrite的 class_ro_t 表示class是readonly的
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
// ....省略一些方法
}
// class_ro_t存放的是編譯期間就確定的;而class_rw_t是在runtime時才確定。class_ro_t是 class_rw_t中的一個屬性,所以可以說class_rw_t是class_ro_t的超集
struct class_rw_t {
uint32_t flags;
uint32_t version;
// 只讀class 結(jié)構(gòu)體
const class_ro_t *ro;
//方法列表
method_array_t methods;
//屬性列表
property_array_t properties;
//協(xié)議列表
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
}
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
uint32_t reserved;
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
};
isa_t
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct {
uintptr_t nonpointer : 1; // 代表是否開啟NONPOINTER isa指針優(yōu)化,之前的版本又叫index的其實一個意思蘋果后來給這類優(yōu)化方案起了名字NONPOINTER
uintptr_t has_assoc : 1; // 對象是否含有關(guān)聯(lián)引用
uintptr_t has_cxx_dtor : 1; // 對象是否含有 C++ 或者 Objc 的析構(gòu)器
uintptr_t shiftcls : 33; // 類的指針arm64下3bits,x86_64下44bits
uintptr_t magic : 6; // 判斷對象是否初始化完成 arm下0x16 ,x86_64下 0x3b
uintptr_t weakly_referenced : 1; //是否為弱引用的對象
uintptr_t deallocating : 1; //對象是否正在執(zhí)行析構(gòu)函數(shù)(是否在釋放內(nèi)存)
uintptr_t has_sidetable_rc : 1; // 判斷是否需要用sidetable去處理引用計數(shù),(extra_rc的大小影響到這個變量)
uintptr_t extra_rc : 19; // 存儲該對象的引用計數(shù)值減一后的結(jié)果
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
};
參考文章 objc_class ,isa_t
6,runloop相關(guān)內(nèi)容
7,自動釋放池相關(guān)內(nèi)容
8,dealloc釋放過程
對象內(nèi)存銷毀時刻表
1,調(diào)用-release 對象的引用計數(shù)為0
??a,對象正在被銷毀,生命周期結(jié)束
??b,不在有新的 __weak 弱引用,否則將指向nil
??調(diào)用[self dealloc]
2,子類調(diào)用 -dealloc
??a,繼承鏈最底層的子類調(diào)用 -dealloc
??b,MRC下則會手動釋放實例變量
??c,繼承關(guān)系中沒一層父類調(diào)用 -dealloc
3,NSObject 調(diào)用 -dealloc
??調(diào)用object_dispose()方法
4,調(diào)用object_dispose()
??為C++對象們(iVars)調(diào)用 destructors
??為ARC對象們(iVars)調(diào)用 -release
??解除所有runtime 方法關(guān)聯(lián)的對象
??解除所有 __weak 引用
??調(diào)用 free()

參考文章Dealloc還需要注意什么
9,如何動態(tài)替換實例對象的某個方法
- 可參考KVO的實現(xiàn)(動態(tài)創(chuàng)建一個子類,利用isa指針交換,在子類重寫該方法,進行消息轉(zhuǎn)發(fā))
- 使用class_replaceMethod/class_addMethod函數(shù)在運行時對函數(shù)進行動態(tài)替換或增加新函數(shù)
- 直接用_objc_msgForward 走消息轉(zhuǎn)發(fā)流程,然后在快轉(zhuǎn)過程中進行替換
10,重排鏈表
解題思路
1、通過雙指針,找到鏈表中間節(jié)點,然后將之前鏈表分為前后兩個鏈表(通過慢指針斷開))
2、反轉(zhuǎn)后鏈表
3、將前后兩個鏈表進行合并,先前鏈表內(nèi)容,然后再是后鏈表內(nèi)容
4、如果還有兩邊不為空,則直接添加單最終鏈表的尾部
代碼實現(xiàn)
/**
* Definition for singly-linked list.
* public class ListNode {
* public var val: Int
* public var next: ListNode?
* public init() { self.val = 0; self.next = nil; }
* public init(_ val: Int) { self.val = val; self.next = nil; }
* public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
* }
*/
class Solution {
func reorderList(_ head: ListNode?) {
if head == nil || head?.next == nil {
return
}
let node: ListNode? = head
var slow: ListNode? = head
var fast: ListNode? = head?.next
while fast != nil && fast?.next != nil {
slow = slow?.next
fast = fast?.next?.next
}
let halfNode: ListNode? = slow?.next
slow?.next = nil
let reverseNode: ListNode? = self.reverseReorderList(halfNode)
self.mergeNodeList(node, reverseNode)
}
//反轉(zhuǎn)鏈表
func reverseReorderList(_ head: ListNode?) -> ListNode?{
if head == nil {
return nil
}
let curNode: ListNode? = head
var nextNode: ListNode? = head
var frontNode: ListNode? = head
while curNode?.next != nil {
nextNode = curNode?.next
curNode?.next = nextNode?.next
nextNode?.next = frontNode
frontNode = nextNode
}
return frontNode
}
func mergeNodeList(_ n1: ListNode?, _ n2: ListNode?){
var beforeNode: ListNode? = n1 //i
var afterNode: ListNode? = n2 //j
var resultNode: ListNode? = ListNode.init(0);
while beforeNode != nil && afterNode != nil{
resultNode?.next = beforeNode
resultNode = resultNode?.next
beforeNode = beforeNode?.next
resultNode?.next = afterNode
resultNode = resultNode?.next
afterNode = afterNode?.next
}
resultNode?.next = beforeNode == nil ? afterNode : beforeNode
}
}
11,有序數(shù)組中刪除重復(fù)項
func removeDuplicates(_ nums: inout [Int]) -> [Int] {
if nums.count == 0 {
return 0
}
var left = 0
var right = 1
while right < nums.count {
if nums[left] != nums[right] {
left += 1
nums[left] = nums[right]
}
right += 1
}
return nums
}