iOS中的事件響應鏈、單例模式、工廠模式、觀察者模式
學習內容
歡迎關注我的iOS學習總結——每天學一點iOS://github.com/practiceqian/one-day-one-iOS-summary
iOS中事件傳遞和相應機制
-
iOS中的事件(主要有三類)
- 觸摸事件(touch Event)
- 運動/加速計事件(motion Event)
- 遠程控制事件(remote-control Event)
-
UIResponder(響應者對象)
-
iOS中只有繼承了UIResponder的類才能接收並處理事件,稱之為響應者對象。
-
為什麼繼承了UIResponder的類都能夠接收並處理事件呢?
-
//UIResponder類提供了以下四個對象方法來處理觸摸事件 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
-
-
-
事件響應鏈
-
所有處理事件響應的類都是UIResponder的子類,響應者鏈是一個由不同對象組成的層次結構,其中的每個對象依次獲得響應事件消息的機會,事件將沿著響應者鏈一直向下傳遞,直到該事件被接收並且處理
-
事件的傳遞和響應鏈
//事件傳遞是從第一響應者->UIApplication View->ViewController->UIWindow->UIApplication->nil //事件的響應是從UIApplication->FirstResponder UIApplication->UIwindow->ViewController->View
- 可以通過[responder nextResponder]找到當前responder的下一個responder,持續這個過程,最後會找到UIApplication對象
- 通常情況下,在first responder(即用戶所點擊的view)就會處理事件請求,進入事件分發機制
-
幾種繼承關係
- UIWindow->UIView->UIResponder
- UIApplication->UIResponder
-
-
事件分發機制
- 第一響應者指的是當前接受觸摸的響應者對象(通常是一個UIView對象),表示當前對象正在與用戶進行交互,它是響應鏈的開端,響應鏈和事件分發機制都是為了找出第一響應者
- 當發生觸摸操作後,系統會將該操作打包成一個UIEvent對象,並將其放入當前活動Application的事件隊列(隊列的特點是先進先出,先發生的事件先處理)
- UIApplication會從事件隊列中取出事件並將其分發給當前應用的UIWindow對象
- UIwindow對象首先會使用hitTest:withEvent:方法尋找該觸摸事件發生時所在的視圖,histTest->view
- hitTest:withEvent:方法的處理流程
- 調用pointInside:withEvent:方法判斷觸摸點是否在當前視圖內
- 如果返回no,則hitTest方法返回nil,如果返回yes,則向當前視圖的所有子視圖發送hitTest:withEvent消息
- 如果第一次有子視圖返回非空對象,那麼UIWindow對象調用的histTest:withEvent(UIWindow繼承自UIView,UIView含有hitTest方法)方法返回該對象,如果所有的子視圖都返回nil,那麼histTest:withEvent方法返回自身
- 如果histTest:withEvent方法沒有找到第一響應者或者第一響應者沒有處理該事件,那麼該事件就會沿著響應者鏈向上回溯,如果UIWindow對象和UIApplication對象都不能處理該事件,那麼該事件就會被丟棄。
- 如果對事件響應需要有特殊的操作,那麼可以重寫hisTest:withEvent方法來實現
- UIView(或者繼承自UIView的子類)不能接收觸摸事件的三種情況
- UIView的userInteractionEnabled設置為NO(不可交互)
- UIView的hidden設置為YES(隱藏了UIView,父控制項隱藏的話子控制項也會被隱藏)
- alpha透明度<0.01(0~0.01)為透明
-
UIApplication的幾種狀態
- not Running(程式未啟動狀態)
- Inactive(未激活)程式在前台運行,但是沒有接收到事件,在沒有事件需要處理的情況下程式通常處於這個狀態
- active(激活)程式在前台運行,並且接收到了事件
- Background(後台),程式在後台運行並且可以執行程式碼,大多數程式掛起到後台都會在這個狀態停留一會,一段時間後會進入掛起(Suspended)狀態,經過特殊處理的請求可以長期處於這個狀態。
- Suspended(掛起),程式在後台運行但是不能執行程式碼,系統自動把程式變成這個狀態並且不會發出通知,但是還在記憶體中運行,當系統遇到記憶體壓力時,就會自動將程式從記憶體中清除,為前台程式提供更多的記憶體。
iOS中的設計模式
-
設計原則
- 單一職責原則
- 一個類只承擔一個職責,如果一個類擁有了兩種職責,那麼需要考慮是否將這個類拆分開來,比如UITableViewCell,如果有多重樣式的cell,那麼我們應該考慮的是分成幾種類型的cell去寫,而不是在一個cell中實現多種類型
- 開閉原則
- 對軟體實體的修改,最好使用擴展而非直接修改的方式
- 對類,函數,如果需要修改,盡量採用繼承的方式來擴展類的功能,而不是直接修改類的程式碼(如果工程不是特別複雜的情況下,那麼直接修改類的程式碼也可以)
- 里式替換原則
- 子類可以擴展父類的方法,但不應該重寫父類的方法
- 介面隔離原則
- 對象不應被強迫依賴它不使用的方法
- 依賴倒置原則
- 高層模組不應該依賴底層模組,二者都應該依賴其抽象,抽象不應該依賴細節,細節應該依賴抽象
- 迪米特法則
- 一個對象對另一個對象了解的越多,那麼他們的耦合度就越高,當修改一個對象時,對另一個對象的影響就越大(一個對象應該對另一個對象保持最少的了解,盡量實現低耦合高內聚)
- 組合/聚合復用原則
- 盡量使用合成/聚合,在一個新的對象裡面使用一些已有的對象,使之成為新對象的一部分,新的對象通過對這些對象的委派達到復用已有功能的目的(盡量使用合成/聚合,不要使用繼承)
- 單一職責原則
-
iOS開發中幾種常用的設計模式
-
單例模式(兩種實現方法)
-
//使用@synchronized保證執行緒安全的懶載入寫法,但是由於@synchronized是互斥鎖導致性能比較低 + (Singleton *)sharedInstance { @synchronized (self) { if (!instance) { instance = [[Singleton alloc] init]; } } return instance; } //使用GCD中的dispatch_once寫法,同時滿足了執行緒安全和靜態分析器的要求 + (Singleton *)sharedInstance { static dispatch_once_t predicate; dispatch_once(&predicate, ^{ instance = [[Singleton alloc] init]; }); return instance; }
-
以上兩種單例模式的實現都不能保證SingleTon是唯一的,因為通過[[Single alloc]init]方式創建仍然會創建出新的實例
-
創建絕對單例的方法
//通過攔截alloc方法來創建絕對單例 //new->alloc //alloc->allocWithZone //alloc方法的內部就是調用了allocWithZone方法,allocWithZone方法的作用就是申請空間創建對象並將創建的對象返回。 + (instancetype)shareInstance { if (instance == nil) { static dispatch_once_t once; dispatch_once(&once, ^{ instance = [[Singleton alloc] init]; }); } return instance; } + (instancetype)allocWithZone:(struct _NSZone *)zone { if (instance == nil) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super allocWithZone:zone]; }); } return instance; }
-
-
工廠模式
-
//一個工廠類需要執行多個方法,可以將每個方法衍生出一個類繼承自這個工廠類,實例化工廠類時根據傳入的參數創建對應方法的實例 @implementation OperationFactory + (Operation *) createOperat:(char)operate{ Operation *oper = nil; switch (operate) { case '+': { oper = [[OperationAdd alloc] init]; break; } case '-': { oper = [[OperationSub alloc] init]; break; } case '*': { oper = [[OperationMul alloc] init]; break; } case '/': { oper = [[OperationDiv alloc] init]; break; } default: break; } return oper; } @end
-
-
委託模式(這裡只列出使用步驟,A為委託對象,B為代理對象)
-
類A介面為文件中創建協議,聲明@requeired和@optional方法
-
類A添加一個屬性,使用weak修飾(否則會造成循環引用)
@property (nonatomic,wead) id<協議名>delegate
-
類B介面文件/類擴展中遵守協議,並在實現文件中實現協議的required/optional方法
-
類B中創建一個類A對象,類A對象的delegate設置為self(類B自身)
-
在類A對象中調用[self.delegate 方法]
-
-
觀察者模式(兩種方式)
- 使用NSNotification通知實現
- 使用KVO(key,value,observer)鍵值觀測實現
-