一稻扬,成員變量和屬性
@interface Person : NSObject
{
NSString *_sex;
}
@property (nonatomic, copy) NSString *name;
@end
成員變量:
1. 成員變量的默認修飾是@protected攒巍。
2. 成員變量不會自動生成set和get方法嗽仪,需要自己手動實現(xiàn)。
3. 成員變量不能用點語法調用柒莉,因為沒有set和get方法闻坚,只能使用->調用。
屬性
1. 屬性的默認修飾是@protected兢孝。
2. 屬性會自動生成set和get方法。
3. 屬性用點語法調用,點語法實際上調用的是set和get方法违霞。
二射富,int??, long, NSInteger??????
32程序:NSInteger相當于int32_t,4個字節(jié)為int的別名魁袜。
64位程序:NSInteger相當于int64_t,8個字節(jié)為long long的別名。
NSInteger???????? 表示當前系統(tǒng)下整型所占的最大字節(jié)??????????????????,????32位 ??int4 long4,64位??int4,long8
三,全局變量座咆,靜態(tài)變量,局部變量
1. 全局變量
函數(shù)外面聲明
可以跨文件訪問
可以在聲明時賦上初始值
如果沒有賦初始值仓洼,系統(tǒng)自動賦值為0
存儲位置:既非堆介陶,也非棧,而是專門的【全局(靜態(tài))存儲區(qū)static】衬潦!
A 文件中
float lastNum;//僅聲明
float lastNum = 10.0;//聲明和定義
B文件中
extern float lastNum; // 引用
關于extern關鍵字
要注意的是斤蔓,全局變量可以在許多地方聲明 為extern,但定義(賦初值)只能一次镀岛。
而上面的代碼既聲明弦牡,也定義了一個全局變量lastNum。其中漂羊,定義的時候并不需要extern專門來修飾驾锰。
倒是在其他不需要定義該全局變量的地方,需要extern來修飾該全局變量走越,聲明要調用外部變量了椭豫。
注意:全局變量可以同一工程跨文件訪問,可能會引起嚴重的混淆問題旨指,名稱盡量特殊化赏酥。
2. 靜態(tài)變量
函數(shù)外面 或 內部聲明(即可修飾原全局變量亦可修飾原局部變量)
僅聲明該變量的文件可以訪問
可以在聲明時賦上初始值
如果沒有賦初始值,系統(tǒng)自動賦值為0
存儲位置:既非堆谆构,也非棧裸扶,而是專門的【全局(靜態(tài))存儲區(qū)static】!
static float lastNum;
static float lastNum = 10.0;
3. 局部變量(自動變量)
函數(shù)內部聲明
僅當函數(shù)執(zhí)行時存在
僅在本文件本函數(shù)內可訪問
存儲位置:自動保存在函數(shù)的每次執(zhí)行的【棧幀】中搬素,并隨著函數(shù)結束后自動釋放呵晨,另外,函數(shù)每次執(zhí)行則保存在【棸境撸】中
- (float)caculateResult{
float a = 1.0;
float b = 2.0;
return a + b;
}
4. 內存分區(qū)
堆和棧首先要清楚的是程序對內存的使用分為以下幾個區(qū):
棧區(qū)(stack):由編譯器自動分配和釋放摸屠,存放函數(shù)的參數(shù)值,局部變量的值等粱哼。操作方式類似于數(shù)據(jù)結構中的棧季二。
堆區(qū)(heap):一般由程序員分配和釋放,若程序員不釋放揭措,程序結束時可能由操作系統(tǒng)回收戒傻。與數(shù)據(jù)結構中的堆是兩碼事税手,分配方式類似于鏈表。
全局區(qū)(static):全局變量和靜態(tài)變量存放在此需纳。
文字常量區(qū):常量字符串放在此芦倒,程序結束后由系統(tǒng)釋放。
程序代碼區(qū):存放函數(shù)體的二進制代碼不翩。
import,include,@class
1. import和include都是包含某個文件
2. import可以防止重復包含
3. @class是聲明有這個類兵扬,具體怎么實現(xiàn)沒包括,防止循環(huán)引用頭文件
#import是OC導入頭文件的關鍵字,#include是C/C++倒入頭文件的關鍵字
使用#import導入頭文件只會導入一次口蝠,不會重復導入器钟。相當于#include和#pragma once;
@class只告訴編譯器某個類的聲明,當執(zhí)行時才去查看這個類的實現(xiàn)文件妙蔗,可以解決頭文件的相互包含傲霸。
category,extension眉反,Protocol昙啄,繼承
category
分類的使用:
第一,category的主要作用是為已經(jīng)存在的類添加方法寸五;
第二梳凛,把類的實現(xiàn)分開在幾個不同的文件里面。
把類的實現(xiàn)分開在幾個不同的文件里面的好處:
可以減少單個文件的體積
可以把不同的功能組織到不同的category里
可以由多個開發(fā)者共同完成一個類
可以按需加載想要的category
聲明私有方法
第三梳杏,模擬多繼承(另外可以模擬多繼承的還有protocol)
category的特點
-
category
只能給某個已有的類擴充方法韧拒,不能擴充成員變量。 -
category
中也可以添加屬性十性,只不過@property
只會生成setter
和getter
的聲明叛溢,不會生成setter
和getter
的實現(xiàn)以及成員變量。 - 如果
category
中的方法和類中原有方法同名劲适,運行時會優(yōu)先調用category
中的方法雇初。也就是,category
中的方法會覆蓋掉類中原有的方法减响。所以開發(fā)中盡量保證不要讓分類中的方法和原有類中的方法名相同。避免出現(xiàn)這種情況的解決方案是給分類的方法名統(tǒng)一添加前綴郭怪。比如category_
支示。 - 如果多個
category
中存在同名的方法,運行時到底調用哪個方法由編譯器決定鄙才,最后一個參與編譯的方法會被調用颂鸿。
extension
extension
被開發(fā)者稱之為擴展、延展攒庵、匿名分類嘴纺,和category
不同的是extension
不但可以聲明方法败晴,還可以聲明屬性、成員變量栽渴。extension
一般用于聲明私有方法尖坤,私有屬性,私有成員變量闲擦。
extension的存在形式
category
是擁有.h文件和.m文件的東西慢味。但是extension
不然。extension
只存在于一個.h文件中墅冷,或者extension
只能寄生于一個類的.m文件中纯路。比如,viewController.m
文件中通常寄生這么個東西寞忿,其實這就是一個extension
:
#import "ViewController.h"
@interface ViewController ()
{
NSString *_str;
}
@property (weak, nonatomic) IBOutlet UIButton *resultBtn;
- (NSString *)getString;
@end
注意:extension常用的形式并不是以一個單獨的.h文件存在驰唬,而是寄生在類的.m文件中。
category和extension的區(qū)別
extension可以添加實例變量腔彰,而category是無法添加實例變量的(因為在運行期叫编,對象的內存布局已經(jīng)確定,如果添加實例變量就會破壞類的內部布局萍桌,這對編譯型語言來說是災難性的)宵溅。
extension在編譯期決定,它就是類的一部分上炎,但是category則完全不一樣恃逻,它是在運行期決議的。extension在編譯期和頭文件里的@interface以及實現(xiàn)文件里的@implement一起形成一個完整的類藕施,它寇损、extension伴隨類的產(chǎn)生而產(chǎn)生,亦隨之一起消亡裳食。
extension一般用來隱藏類的私有信息矛市,你必須有一個類的源碼才能為一個類添加extension,所以你無法為系統(tǒng)的類比如NSString添加extension诲祸,除非創(chuàng)建子類再添加extension浊吏。而category不需要有類的源碼,我們可以給系統(tǒng)提供的類添加category救氯。
extension和category都可以添加屬性找田,但是category的屬性不能生成成員變量和getter、setter方法的實現(xiàn)着憨。
Category VS Extension 原理詳解
Protocol
利用繼承墩衙、多態(tài)可以很好的保持"對擴展開放,對更改封閉"(即上文提到的開放-封閉原則OCP
),這也是面向對象語言保持開放-封閉原則最常見的辦法漆改。OC中還有另外兩種語法來支持OCP:即Category和Protocol心铃。
Protocol
只是聲明一套接口,并不能提供具體實現(xiàn)挫剑,變相的也算是一種抽象基類的實現(xiàn)方式(OC本身語法并不支持抽象基類)去扣。
Protocol只能提供一套公用的接口聲明,并不能提供具體實現(xiàn)暮顺,它的行為是厅篓,我只負責聲明,而不管誰去實現(xiàn)捶码,去如何實現(xiàn)羽氮。 這樣的話,我定義一套接口惫恼,可以使任意的類都用不同的方式去實現(xiàn)接口中的方法档押,就是為遵守了protocol
的類提供了一些額外訪問這個類的一些接口,像delegate
和dataSource
用protocol
實現(xiàn)是最好的祈纯。
繼承
繼承令宿,它基于Protocol
和Category
之間,既可以像protocol
一樣只提供純粹的接口腕窥,也可以像Category
一樣提供接口的完整實現(xiàn)粒没,可以自由定義類的實例變量,而且繼承還可以對類以后的方法進行改寫簇爆,所以繼承的力量是最強大的癞松。
在iOS開發(fā)中,繼承是完全可以完成protocol
和category
的功能的入蛆,那么在開發(fā)過程中多多使用繼承體系可好响蓉?
使用繼承來進行擴展是一種耦合度很高的行為,對父類可以說是完全依賴哨毁,如果繼承體系太過復雜枫甲,會造成難以維護的問題。如果僅僅只是對類進行擴展扼褪,并不建議使用繼承想幻,畢竟使用protocol和category是很簡單、輕松的话浇。
category是可以被繼承的脏毯。在某個父類中定義了category,那么他所有的子類都具有該category凳枝。
==、 isEqualToString、isEqual區(qū)別
==
==
: 比較兩個指針的值 , 是判斷兩個對象的引用(reference
)是否一樣岖瑰,也就是內存地址是否一樣叛买。
isEqualToString
isEqualToString
: 比較兩個字符串是否相同
isEqual
Returns a Boolean value that indicates whether the receiver and a given object are equal.
官網(wǎng)解釋:返回一個bool
值判斷兩個對象是否相等
isEqual
: 是 NSObject
的方法, 如果兩個對象是相等的,那么他們必須有相同的哈希值, 包括判斷 指針的等同性蹋订,類的等同性率挣,最后調用對象的比較器進行比較。
nil, Nil, NULL,NSNull的區(qū)別
#### nil
nil 表示空對象露戒。
object = nil椒功,表示把這個對象釋放掉了,引用計數(shù)為0智什,如果對這個對象引用計數(shù)加1 的操作都會報錯动漾。
#### NSNull
NSNull 稱它為“值為空的對象”。
#### Nil
nil和Nil在使用上是沒有嚴格限定的荠锭,也就是說凡是使用nil的地方都可以用Nil來代替旱眯,反之亦然。
只不過從編程人員的規(guī)約中我們約定俗成地將nil表示一個空對象证九,Nil表示一個空類删豺。
#### NULL
NULL就是典型C語言的語法,它表示一個空指針愧怜。
參考代碼如下:
int *ponit = NULL;
loadView呀页、viewDidLoad、viewDidUnload區(qū)分
#### loadView
用來負責創(chuàng)建controller的view, 如果每次訪問controller的view(比如controller.view拥坛、self.view)且view為nil蓬蝶,loadView方法就會被調用。
創(chuàng)建view方式:
(1)它會先去查找與controller相關聯(lián)的xib文件渴逻,通過加載xib文件來創(chuàng)建controller的view
a.如果在初始化controller指定了xib文件名疾党,就會根據(jù)傳入的xib文件名加載對應的xib文件
[[SYViewController alloc] initWithNibName:@"SYViewController" bundle:nil];
b.如果沒有明顯地傳xib文件名,就會加載跟controller同名的xib文件
[[SYViewController alloc] init];
(2) 如果沒有找到相關聯(lián)的xib文件惨奕,就會創(chuàng)建一個空白的UIView雪位,然后賦值給controller的view屬性,大致如下:
- (void)loadView
{
self.view = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
}
#### viewDidLoad
無論你是通過xib文件還是重寫loadView方法創(chuàng)建controller的view梨撞,在view創(chuàng)建完畢后雹洗,最終都會調用viewDidLoad方法。
一般我們會在這里做界面上的初始化操作卧波,比如往view中添加一些子視圖时肿、從數(shù)據(jù)庫或者網(wǎng)絡加載模型數(shù)據(jù)裝配到子視圖中。
#### viewDidUnload
1港粱、調用時機
iOS設備的內存是極其有限的螃成,如果應用程序占用的內存過多的話旦签,系統(tǒng)就會對應用程序發(fā)出內存警告。controller就會收到didReceiveMemoryWarning消息寸宏。didReceiveMemoryWarning方法的默認實現(xiàn)是:如果當前controller的view不在應用程序的視圖層次結構(View Hierarchy)中宁炫,即view的superview為nil的時候,就會將view釋放氮凝,并且調用viewDidUnload方法羔巢。
2、作用
發(fā)出內存警告且view被釋放的時候就會調用viewDidUnload方法罩阵,所以一般在釋放資源竿秆,主要是釋放界面元素相關的資源,將相關的實例都賦值為nil稿壁。例如:
- (void)viewDidUnload {
[super viewDidUnload];
self.name = nil;
self.pwd = nil;
}
3幽钢、dealloc跟viewDidUnload的關系
當發(fā)出內存警告調用viewDidUnload方法時,只是釋放了view常摧,并沒有釋放controller搅吁,所以并不會調用dealloc方法。
即viewDidUnload和dealloc方法并沒有任何關系落午,dealloc方法只會在controller被釋放的時候調用谎懦。
程序啟動過程
打開程序 --> 執(zhí)行main函數(shù) --> 執(zhí)行并初始化UIAPPlicationMian函數(shù)(生成UIAPPlication對象,UIAppdelegate對象溃斋,創(chuàng)建RunLoop開啟事件循環(huán)界拦,加載資源(圖片,靜態(tài)文件梗劫,infoplist,storybord,xib等))-->監(jiān)聽和處理事件-> 結束程序
隱式動畫 和 顯式動畫
隱式動畫
隱式動畫是系統(tǒng)框架自動完成的享甸。蘋果對UIView添加了一種基于block的動畫方法:+animateWithDuration:animations:。這樣寫對做一堆的屬性動畫在語法上會更加簡單梳侨,但實質上它們都是在做同樣的事情蛉威。CATransaction
的+begin
和+commit
方法在+animateWithDuration:animations:
內部自動調用,這樣block
中所有屬性的改變都會被事務所包含走哺。
顯式動畫
Core Animation
提供的顯式動畫類型蚯嫌,顯式動畫是指用戶自己通過beginAnimations:context:
和commitAnimations
創(chuàng)建的動畫。我們經(jīng)常使用的CABasicAnimation丙躏,CAKeyframeAnimation择示,CATransitionAnimation,CAAnimationGroup等都是顯式動畫類型晒旅,這些CAAnimation類型可以直接提交到CALayer上栅盲。
無論是隱式動畫還是顯式動畫,提交到layer后废恋,經(jīng)過一系列處理谈秫,最后都經(jīng)過上文描述的繪制過程最終被渲染出來扒寄。
靜態(tài)鏈接庫 和 動態(tài)鏈接庫
靜態(tài)庫和動態(tài)庫的存在形式
靜態(tài)庫:.a 和 .framework
動態(tài)庫:.dylib 和 .framework
靜態(tài)庫和動態(tài)庫在使用上的區(qū)別
靜態(tài)庫:連接時,靜態(tài)庫會被完整的復制到可執(zhí)行文件中拟烫,被多次使用就有多份冗余拷貝
動態(tài)庫:連接時不復制旗们,程序運行時有系統(tǒng)動態(tài)加載到內存,提供程序調用构灸,系統(tǒng)只加載一次,多個程序共用岸梨,節(jié)省內存
注意:項目中使用了自制的動態(tài)庫喜颁,不能被上傳到AppStore
多態(tài)
不同對象以自己的方式去響應相同消息的能力叫做多態(tài),子類的指針可以指向父類
運行時
運行時機制是我們在運行時才確定這個對象的類曹阔,以及調用該類指定的方法
事件響應與響應者鏈
- 發(fā)生觸摸事件后半开,系統(tǒng)會將事件加入到一個由
UIAPPlication
管理的隊列事件中 -
UIAPPlication
會從事件對列中取出最前面的事件按照自下而上的響應原則 分發(fā)下去,通常最先發(fā)給主窗口(keyWindow
)赃份。 - 主窗口會在視圖中找到合適的響應視圖寂拆,來處理觸摸事件,調用視圖中的事件具體處理方法抓韩,如:
touchesBegin
,touchesMove
,touchesEnd
等纠永,事件在往上傳遞。
注意:事件是從父視圖傳遞給子視圖谒拴,如果父視圖不接受觸摸事件尝江,子視圖就不可能接收觸摸事件。
視圖不接收觸摸事件的三種情況:
- 不接受用戶交互:
userInteractionEnabled = NO;
- 隱藏:
hidden = YES;
- 透明度:
alpha = 0.0~0.01
大致觸發(fā)過程:application –> window –> root view –>......–>lowest view
如何判斷當前響應者的上一個響應者是誰呢英上?
- 判斷當前view是不是控制器ViewController控制的view炭序,如果是ViewController控制的view,上一個響應者就是控制器苍日,否則就是當前響應視圖的父視圖惭聂。
frame, bounds
frame指的是:該view在父view坐標系中的位置和大小。(參考系是父視圖坐標系)
bounds指的是:該View在自身坐標系中的位置和大小相恃。(參考系是本身坐標系)
循環(huán)引用
循環(huán)引用的實質:多個對象相互之間有強引用辜纲,不能施放讓系統(tǒng)回收
解決循環(huán)引用:一般是將 strong 引用改為 weak 引用。
場景一: 對象之間相互引用:
如:在使用UITableView 的時候豆茫,將 UITableView 給 Cell 使用侨歉,cell 中的 strong 引用會造成循環(huán)引用。
// controller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TestTableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:@"UITableViewCellId" forIndexPath:indexPath];
cell.tableView = tableView;
return cell;
}
// cell
@interface TestTableViewCell : UITableViewCell
@property (nonatomic, strong) UITableView *tableView; // strong 造成循環(huán)引用
@end
解決:strong 改為 weak
// cell
@interface TestTableViewCell : UITableViewCell
@property (nonatomic, weak) UITableView *tableView; // strong 改為 weak
@end
場景二:block
block在copy時都會對block內部用到的對象進行強引用的揩魂。
self.testObject.testCircleBlock = ^{
[self doSomething];
};
self將block作為自己的屬性變量幽邓,而在block的方法體里面又引用了 self 本身,此時就很簡單的形成了一個循環(huán)引用火脉。
應該將 self 改為弱引用
__weak typeof(self) weakSelf = self;
self.testObject.testCircleBlock = ^{
__strong typeof (weakSelf) strongSelf = weakSelf;
[strongSelf doSomething];
};
在 ARC 中牵舵,在被拷貝的 block 中無論是直接引用 self 還是通過引用 self 的成員變量間接引用 self柒啤,該 block 都會 retain self。
// weak obj
/#define WEAK_OBJ(type) __weak typeof(type) weak##type = type;
// strong obj
/#define STRONG_OBJ(type) __strong typeof(type) str##type = weak##type;
場景三畸颅,Delegate
delegate 屬性的聲明如下:
@property (nonatomic, weak) id <TestDelegate> delegate;
如果將 weak 改為 strong担巩,則會造成循環(huán)引用
// self -> AViewController
BViewController *bVc = [BViewController new];
bVc = self;
[self.navigationController pushViewController: bVc animated:YES];
// 假如是 strong 的情況
// bVc.delegate ===> AViewController (也就是 A 的引用計數(shù) + 1)
// AViewController 本身又是引用了 <BViewControllerDelegate> ===> delegate 引用計數(shù) + 1
// 導致: AViewController <======> Delegate ,也就循環(huán)引用啦
NSTimer
NSTimer
的 target
對傳入的參數(shù)都是強引用(即使是 weak
對象)
- (void)viewDidLoad {
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerClicked) userInfo:nil repeats:YES];
// 等同于 下面 RunLoop -> timer -> self
self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerClicked) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
- (void)timerClicked {
NSLog(@"timerClicked ----");
}
這段代碼發(fā)生內存泄露 頁面消失 timerClicked
函數(shù)一直執(zhí)行
解決辦法為 didMoveToParentViewController
函數(shù) 將timer
置為空 或在合適位置將其timer
取消
- (void)didMoveToParentViewController:(UIViewController *)parent {
if (nil == parent) {
[self.timer invalidate];
self.timer = nil;
}
}
NSString copy 或者用strong修飾的區(qū)別
(1)NSString的字符串的對象的值改變時没炒,會開辟一塊新的內存涛癌,NSMutableString的字符串的對象的值改變時,依舊是原地址送火。
(2)copy拷貝NSSting字符串時拳话,拷貝指針,既淺拷貝种吸;copy拷貝NSMutableString字符串時是重新生成一個新對象弃衍,即深拷貝。
(3)copy修飾的可變字符串屬性類型始終是NSString坚俗,而不是NSMutableString镜盯,如果想讓拷貝過來的對象是可變的,就要使用mutableCopy猖败。(所有copy修飾的NSSting字符串不會被外界影響)
(4)strong表示強引用速缆,對可變和不可變字符串都只有淺拷貝。對NSMutableString不存在深拷貝恩闻。
NSObject,id, instancetype
(1)OC
里面已經(jīng)有NSObject
了激涤,為啥還要用id
,所有對象不知道類型的時候用NSObject
代替不可以么判呕?
不可以倦踢,因為OC
里面,并不是所有的Foundation/Cocoa
對象都繼承息NSObject
比如NSProxy
就不從NSObject
繼承侠草。
所以你無法使用NSObject*
指向這個對象辱挥,
即使NSProxy
對象有release
和retain
這樣的通用方法。
(2)????用id
修飾的對象边涕,所有OC
的對象 id
都可以指向晤碘,編譯器不會做類型校驗,id
調用任何OC
中存在的方法都不會在編譯器報錯功蜓,說明id類型時運行時特性园爷。
(3)NSobject*
指向的必須都是NSObject
的子類,調用的也是NSObject
里面的方法否則會報錯
(4) instancetype
的作用式撼,就是使那些非關聯(lián)返回類型的方法返回所在類的類型童社!能夠確定對象的類型,能夠幫助編譯器更好的為我們定位代碼書寫問題著隆,
instancetype和 id 相同點: 都可以作為方法的返回類型
instancetype和 id 不相同點:
instancetype
可以返回和方法所在類相同類型的對象扰楼,id只能返回未知類型的對象呀癣;instancetype
只能作為返回值,不能像id那樣作為參數(shù)弦赖。不是所有的
OC
對象都是NSObject
的子類项栏,還有一些繼承自NSProxy(虛基類)
。NSObjec*
可以指向的類型是id
的子集蹬竖。
IOS 核心框架
CoreAnimation ,CoreGraphics ,CoreLocation ,AVFoundation ,Foundation
IOS 的核心機制
重用機制沼沈,
OC 內存管理機制,自動釋放池币厕,ARC
RunLoop
RunTime
Block
Responder Chain
NSOperation,GCD
delegate 庆冕,notification , block
delegate 是一對一的關系,接收者可以返回值發(fā)送者劈榨;
notification可以一對多的,接受者不可以返回值給發(fā)送者晦嵌。
block 使得代碼更加緊湊同辣,便于閱讀
對單例的理解
RSA 加密算法
我們發(fā)現(xiàn)服務器判斷用戶是否登錄, 完全依賴于sessionId
, 一旦其被截獲惭载, 黑客就能夠模擬出用戶的請求旱函。于是我們需要引入token
的概念: 用戶登錄成功后, 服務器不但為其分配了sessionId
, 還分配了token
描滔, token
是維持登錄狀態(tài)的關鍵秘密數(shù)據(jù)棒妨。在服務器向客戶端發(fā)送的token
數(shù)據(jù),也需要加密含长。于是一次登錄的細節(jié)再次擴展券腔。
- 客戶端向服務器第一次發(fā)起登錄請求(不傳輸用戶名和密碼)。
- 服務器利用RSA算法產(chǎn)生一對公鑰和私鑰拘泞。并保留私鑰纷纫, 將公鑰發(fā)送給客戶端。
- 客戶端收到公鑰后陪腌, 加密用戶密碼辱魁,向服務器發(fā)送用戶名和加密后的用戶密碼; 同時另外產(chǎn)生一對公鑰和私鑰诗鸭,自己保留私鑰, 向服務器發(fā)送公鑰染簇; 于是第二次登錄請求傳輸了用戶名和加密后的密碼以及客戶端生成的公鑰。
- 服務器利用保留的私鑰對密文進行解密锻弓,得到真正的密碼。 經(jīng)過判斷弥咪, 確定用戶可以登錄后,生成
sessionId
和token
聚至, 同時利用客戶端發(fā)送的公鑰酷勺,對token
進行加密扳躬。最后將sessionId
和加密后的token
返還給客戶端。
客戶端利用自己生成的私鑰對token
密文解密贷币, 得到真正的token
击胜。
+load 的執(zhí)行順序
規(guī)則一:父類先于子類調用
規(guī)則二:類先于分類調用
FatherClass(父類) -> SonClass(子類) -> SonClass+Load(分類) -> main -> appdelegate
同一個類的不同分類中相同方法的執(zhí)行順序
最后被加載進來的,也就是最后參加編譯的分類文件中的方法會被執(zhí)行役纹。不管各個頭文件的導入順序的先后順序
分類的方法,會覆蓋本類中的方法
[self class] 和 [super class] 的區(qū)別
self
調用方法事實際上是通過objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
函數(shù)進行消息的發(fā)送辰斋,其中第一個參數(shù)是消息接收者瘸味,第二個參數(shù)op是調用的具體類的方法的selector,后面是 selector 方法的可變參數(shù)藕夫。如上例所示[self returnSomething]
實際上是id _Nullable objc_msgSend(self, @selector(returnSomething))
而returnSomething
方法會從[self class]
類中查找枯冈。super
調用方法事實際上是通過id _Nullable objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
函數(shù)進行消息的發(fā)送,但是第一個參數(shù)是一個objc_super結構體嫩码。
struct objc_super {
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
};
此時這個結構體的第一個成員變量receiver
就是子類罪既,和 objc_msgSend 中的self相同。而第二個成員變量super_class就是指父類丢间,調用 objc_msgSendSuper 的方法時會將這個結構體和returnSomething的selector傳遞過去驹针。
在結構體函數(shù)里面做的事情類似這樣:從objc_super結構體指向的super_class的方法列表開始找 returnSomething的selector,找到后再用objc_super->receiver去調用這個selector饮六。找不到就會報錯。