1、ViewController生命周期
init
據(jù)經(jīng)驗(yàn),在同一個(gè)runloop運(yùn)行循環(huán)
loadView
ViewDidLoad
ViewWillAppear
ViewDidAppear
ViewWillDisappear
ViewDidlDisappear
2、fastlane (小團(tuán)隊(duì)的福音)
iOS中使用Fastlane實(shí)現(xiàn)自動(dòng)化打包和發(fā)布
官方文檔
- Ruby 2.0 以上
- Xcode Toolline(CLT)

3、Singleton 單例模式
- Objective-c單例模式的幾種寫法有什么不同
- Swift 單例的實(shí)現(xiàn)與解析
- What is a Singleton and How to create one in Swift
- Files and Initialization - Swift Blog - Apple Developper
- Avoiding singletons in Swift - John Sundell - Medium
簡單來說, 就是保證在你不主動(dòng)銷毀這個(gè)單例對(duì)象的情況下, 整個(gè)項(xiàng)目中都始終擁有這個(gè)單例對(duì)象, 并且這個(gè)單例對(duì)象在內(nèi)存中都是同一個(gè)內(nèi)存地址。 所以, 單例很重要的兩個(gè)特點(diǎn):
- (1) app生命周期中一直存在(除主動(dòng)銷毀外)
- (2) 在整個(gè)生命周期中, 都是同一個(gè)內(nèi)存地址
iOS 中的單例
- UIApplication.shard :每個(gè)應(yīng)用程序有且只有一個(gè)UIApplication實(shí)例,由UIApplicationMain函數(shù)在應(yīng)用程序啟動(dòng)時(shí)創(chuàng)建為單例對(duì)象。
- NotificationCenter.defualt:管理 iOS 中的通知
- FileManager.defualt:獲取沙盒主目錄的路徑
- URLSession.shared:管理網(wǎng)絡(luò)連接
- UserDefaults.standard:存儲(chǔ)輕量級(jí)的本地?cái)?shù)據(jù)
- SKPaymentQueue.default():管理應(yīng)用內(nèi)購的隊(duì)列。系統(tǒng)會(huì)用 StoreKit framework 創(chuàng)建一個(gè)支付隊(duì)列,每次使用時(shí)通過類方法 default() 去獲取這個(gè)隊(duì)列。
Objective-C 單例的標(biāo)準(zhǔn)實(shí)現(xiàn)
#import "Singleton.h"
@interface Singleton()<NSCopying,NSMutableCopying>
@end
@implementation Singleton
static Singleton* _instance = nil;
+(instancetype) shareInstance
{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:NULL] init] ;
//不是使用alloc方法,而是調(diào)用[[super allocWithZone:NULL] init]
//已經(jīng)重載allocWithZone基本的對(duì)象分配方法,所以要借用父類(NSObject)的功能來幫助出處理底層內(nèi)存分配的雜物
}) ;
return _instance ;
}
+(id) allocWithZone:(struct _NSZone *)zone
{
return [Singleton shareInstance] ;
}
-(id) copyWithZone:(NSZone *)zone
{
return [Singleton shareInstance] ;//return _instance;
}
-(id) mutablecopyWithZone:(NSZone *)zone
{
return [Singleton shareInstance] ;
}
@end
Swift 單例的標(biāo)準(zhǔn)實(shí)現(xiàn)
class MyManager {
// 全局變量
static let shared = MyManager(string: someString)
// Properties
let string: String
// private Initialization
private init(string: String) {
self.string = string
}
}
??為什么如此簡潔的代碼就能實(shí)現(xiàn)單例?其實(shí)要?dú)w功于Swift的新特性:
- 關(guān)于 Swift 中全局變量的懶加載
- 關(guān)于 Swift 中的
dispatch_once和 原子性 -
static關(guān)鍵字,用于限定變量的作用域?yàn)椤叭肿兞俊薄?/li> - 構(gòu)造器使用了 private 關(guān)鍵字,所以也保證了單例的原子性。
全局變量的懶加載在初始化時(shí)會(huì)使用 dispatch_once 以確保初始化的原子性。所以這是一個(gè)很酷地使用 dispatch_once 的方式:僅在定義全局變量時(shí)將其構(gòu)造器標(biāo)志為 private 就行。
3、觸摸事件傳遞過程
控件能接收事件的基本條件
(1) view.userInteractionEnabled == YES;
(2) view.hidden == NO;
(3) view.alpha > 0.01
(4) 該觸摸點(diǎn)是否落在該控件上
(5) hitTest它只負(fù)責(zé)找最合適的view來接受這個(gè)事件
(6) 如果要攔截事件必須實(shí)現(xiàn)touch方法,因?yàn)楦割惖哪J(rèn)處理是把事件拋給上一個(gè)響應(yīng)者
/**
* 從該View的層次結(jié)構(gòu)中尋找最佳的事件接收者,如果沒有則返回nil
*
* @param point 在該view上的坐標(biāo)系的點(diǎn)
* @param event 事件對(duì)象
*
* @return 最佳接收該事件的view nil 則沒有最佳接收該事件的人選,事件往上拋
*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
// 1. 判斷它 userInteractionEnabled == YES hidden == NO alpha > 0.01
if ( self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01 ) return nil;
// 2. 判斷觸摸點(diǎn)是否落在該控件上(在該控件的坐標(biāo)系中: x > 0 && y > 0)
if ( [self pointInside:point withEvent:event] == NO ) return nil;
// 3. 從后往前遍歷它的子控件,看它的子控件是否滿足以上條件
NSInteger count = self.subviews.count;
for (NSInteger i = count - 1; i >= 0; i--) {
UIView *subView = self.subviews[i];
CGPoint subP = [self convertPoint:point toView:subView];
UIView *target = [subView hitTest:subP withEvent:event];
if ( target != nil ) {
return target;
}
}
// 如果子控件沒有合適人選,來到這里就足以證明控件自身滿足接收該事件的人選
return self;
}
4、RunLoop( 運(yùn)行循環(huán))
- 在應(yīng)用程序啟動(dòng)的時(shí)候,系統(tǒng)首先會(huì)啟動(dòng)一個(gè)主運(yùn)行循環(huán)來給應(yīng)用程序與用戶交互,在這個(gè)過程中系統(tǒng)不斷重復(fù)這個(gè)運(yùn)行循環(huán)來跟用戶交互,當(dāng)用戶的與手機(jī)產(chǎn)生交互到手機(jī)作出相應(yīng)地反應(yīng)為一次運(yùn)行循環(huán)
1.1 運(yùn)行循環(huán)的作用 :
(1) 保證程序不退出
(2) 監(jiān)聽所有事件,例如:手勢觸摸,時(shí)鐘觸發(fā),網(wǎng)絡(luò)加載數(shù)據(jù)完成等
-
一個(gè)完整的運(yùn)行循環(huán)如下圖1377227-48a8ece4925f266d.png
- (1) 當(dāng)用戶觸摸屏幕時(shí)候,CocoaTouch會(huì)產(chǎn)生一個(gè)觸摸事件對(duì)象
- (2) 接著CocoaTouch會(huì)產(chǎn)生一個(gè)自動(dòng)釋放池,然后會(huì)把此觸摸事件對(duì)象發(fā)送給應(yīng)用來處理這個(gè)事件,通常我們要在這個(gè)環(huán)節(jié)來處理我們的事件
- (3) 當(dāng)我們處理完事件之后,給用戶做出了反應(yīng),那么此自動(dòng)釋放池就會(huì)被銷毀,銷毀前它會(huì)遍歷此釋放池中的所有對(duì)象給他們各發(fā)送一條release消息
- (4) 注意如果在子線程中需要用到autorelease的對(duì)象,需要我們自己創(chuàng)建自動(dòng)釋放池
注意:在 子線程中不會(huì)幫我們自動(dòng)創(chuàng)建自動(dòng)釋放池,特別在自定義 NSOperation 的 main 方法中,如果我們不自己添加 @autoreleasepool 的話,很容易會(huì)發(fā)生內(nèi)存泄露
5、簡述@selector的作用
Selector 是什么???
Selector/SEL又叫方法選擇器,SEL在objc.h中是這樣聲明的,而“@selector()”是取得一個(gè)SEL指針。說白了,方法選擇器僅僅是一個(gè)char *指針,表示它所代表的是方法的名字。 簡單來說: “@Selector 就是用字符串表示某個(gè)類的某個(gè)方法?!? 更加專業(yè)的說法是: “Selector就是OC的虛擬表(virtual table)中指向?qū)嶋H執(zhí)行的函數(shù)指針(function pointer)的一個(gè)C字符?!?/p>
我們一般用它來“因?yàn)閙ethod可以用字符串表示,因此,某個(gè)method就可以變成用來傳遞的參數(shù)。” 再說的透明一點(diǎn), 因?yàn)?selector 可以看做是函數(shù)的另一個(gè)名字,所以很多需要調(diào)用函數(shù)或者建立連接的地方,都可以用到,以下是一些具體的使用場景:
- Target/Action 模式
- 檢查 method 是否存在
- Timer
- 在線程中執(zhí)行方法
- 數(shù)組排序
- 代替 if else / switch
- 調(diào)用私有 API
