定時器相關的問題
- 定時器的模式問題是被問的最多的
UIScrollView(UITableView)
拖動時執行的是 UITrackingRunLoopMode
,會導致暫停定時器,等恢復為 NSDefaultRunLoopMode
時才恢復定時器。
所以如果需要定時器在UIScrollView
拖動時也不影響的話,建議添加到UITrackingRunLoopMode
或 NSRunLoopCommonModes
中:
NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode: UITrackingRunLoopMode]; ///< 或者 NSRunLoopCommonModes
- 自動添加到當前
NSRunLoop
的方式,這種方式會導致滑動過程中定時器失效的問題,解決方式就是用(1)的方式設定NSRunLoop
模式
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(test) userInfo:nil repeats:YES];
- 定時器相關API的含義,沒用過的可能會誤解
[myTimer invalidate]; // 廢棄定時器 ,是永久的停止,移除定時器對象
[myTimer setFireDate:[NSDate distantFuture]]; // 關閉定時器;遙遠的將來才能觸發,功能相當于關閉
[myTimer setFireDate:[NSDate distantPast]]; // 開啟定時器;很久很久以前就觸發了,功能相當于開啟
-
GCD
中的延時執行,相當于定時效果
dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC);
dispatch_after(timer, dispatch_get_main_queue(), ^(void) {
NSLog(@"GCD-----%@",[NSThread currentThread]);
});
- 和
NSRunLoop
結合起來用,定時器是一種中斷源,知道這個的,基本上做得比較底層了,在實際工作中,還沒怎么遇到
@property (nonatomic ,strong)dispatch_source_t timer;// 注意:此處應該使用強引用 strong
{
//0.創建隊列
dispatch_queue_t queue = dispatch_get_main_queue();
//1.創建GCD中的定時器
/*
第一個參數:創建source的類型 DISPATCH_SOURCE_TYPE_TIMER:定時器
第二個參數:0
第三個參數:0
第四個參數:隊列
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//2.設置時間等
/*
第一個參數:定時器對象
第二個參數:DISPATCH_TIME_NOW 表示從現在開始計時
第三個參數:間隔時間 GCD里面的時間最小單位為 納秒
第四個參數:精準度(表示允許的誤差,0表示絕對精準)
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//3.要調用的任務
dispatch_source_set_event_handler(timer, ^{
NSLog(@"GCD-----%@",[NSThread currentThread]);
});
//4.開始執行
dispatch_resume(timer);
//
self.timer = timer;
}
此處注意一定要強引用定時器 ,否則定時器執行到}
后將會被釋放,無定時效果。
GCD
定時器時間非常精準,最小的定時時間可以達到1納秒,所以用在非常精確的定時場合。
多線程相關問題
- 串行隊列和并行隊列概念,同步執行和異步執行概念
NSLog(@"開始");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"進行中");
});
NSLog(@"結束");
這段代碼:只會打印第一句:開始,然后主線程就卡死了。
能回答這個問題并作出解釋,說明對這個問題了解比較透徹了。
相對基礎一點的問題:比較容易混淆
(1)dispatch_queue_t queue = dispatch_queue_create ( "com.dispatch.serial" , DISPATCH_QUEUE_SERIAL );
是串行隊列還是并行隊列?
dispatch_queue_t queue = dispatch_queue_create ( "com.dispatch.serial" , DISPATCH_QUEUE_CONCURRENT );
是串行隊列還是并行隊列?
(2)dispatch_get_main_queue()
是串行的還是并行的?
(3)dispatch_get_global_queue()
是串行的還是并行的?
(4)dispatch_sync()
是同步執行還是異步執行?
(5)dispatch_async()
是同步執行還是異步執行?
- n個異步任務都執行完畢后再執行下一步的場景
圖片很大,需要分3次下載,然后合并才能用,應該怎么做?
通過dispatch_group_t
來實現,將每部分圖片下載請求放入到Group
中,將合并圖片的操作放在dispatch_group_notify
中實現。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*下載圖片Part1 */ });
dispatch_group_async(group, queue, ^{ /*下載圖片Part2 */ });
dispatch_group_async(group, queue, ^{ /*下載圖片Part3 */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并圖片
});
- 任務間依賴的場景
有3 個任務:A: 從服務器上下載一張圖片,B:給這張圖片加個水印,C:把圖片返回給服務器。如何實現?
//1.任務一:下載圖片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下載圖片");
}];
//2.任務二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打水印");
}];
//3.任務三:上傳圖片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"上傳圖片");
}];
//4.設置依賴
[operation2 addDependency:operation1]; //任務二依賴任務一
[operation3 addDependency:operation2]; //任務三依賴任務二
//5.創建隊列并加入任務
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
- iOS中多線程技術的種類以及選擇
(1)NSOperation & NSOperationQueue
:是對GCD的對象化封裝,并且有cancel
功能,推薦使用
(2)CGD
:至少要知道模板型使用方式
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 耗時的操作
dispatch_async(dispatch_get_main_queue(), ^{
// 更新界面
});
});
(3)NSThread
:控制力更強一點,比較底層了,用得不多。一些常用的方法可以問問,比如start,cancel,sleepForTimeInterval
等等。
(4)NSObject
就有的方法performSelectorInBackground
,swift中這個方法被取消了
(5)pthread
,知道這個的,c應該不錯
- 線程同步方式,在實際編程中遇到不多,但是概念比較重要
(1)NSLock
方式
[xxxlock lock] //上鎖
同步代碼塊
[xxxlock unlock]//解鎖
(2)NSCondition
方式
[xxxCondition lock] //上鎖
同步代碼塊
[xxxCondition unlock]//解鎖
(3)@synchronized
( 同一對象) 一般是self
;這個使用方便,但是很耗資源
@synchronized(self){
線程執行代碼;
}
(4)OSSpinLock
自旋鎖,atomic
關鍵字,GCD
串行隊列,循環鎖NSRecursiveLock
,pthread
的mutex
,信號量等等
本地存儲,本地緩存
沙盒的目錄結構,使用場合
Application
:存放程序源文件,上架前經過數字簽名,上架后不可修改
Documents
: 保存應?運行時生成的需要持久化的數據,iTunes同步設備時會備份該目 錄。例如,游戲應用可將游戲存檔保存在該目錄
tmp
: 保存應?運行時所需的臨時數據,使?完畢后再將相應的文件從該目錄刪除。應用 沒有運行時,系統也可能會清除該目錄下的文件。iTunes同步設備時 不會備份該目錄
Library/Caches
: 保存應用運行時?成的需要持久化的數據,iTunes同步設備時不會備份 該目錄。?一般存儲體積大、不需要備份的非重要數據,比如網絡數據緩存存儲到Caches
下
Library/Preference
: 保存應用的所有偏好設置,如iOS的Settings
(設置) 應?會在該目錄中查找應?的設置信息。iTunes同步設備時會備份該目錄數據持久化方案
(1)plist
屬性列表存儲(如NSUserDefaults
)
(2)文件存儲(如二進制數據寫入文件存儲,通過NSFileManager
來操作將下載起來的二進制數據寫入文件中存儲)
(3)NSKeydeArchive
r歸檔存儲, === 這個要實現NSCoding
協議,model
要實現哪兩個函數?這點在實際使用中也可能忘記
(4)數據庫SQLite3
存儲(如FMDB、Core Data
)=== 直接用SQL
語句和CoreData
的區別,CoreData
的“坑”
(5)KeyChain
,用戶名密碼 === 代碼怎么實現?需要導入哪幾個系統framework
?SDWebImage
的原理,或者其他圖片緩存庫
(1)從內存中(字典)找圖片(當這個圖片在本次程序加載過),找到直接使用;
(2)從沙盒中找,找到直接使用,緩存到內存。
(3)從網絡上獲取,使用,緩存到內存,緩存到沙盒。YYCache
的原理,或者其他緩存庫的原理
(1)內存緩存
(2)硬盤緩存
(3)key-value
的方式,支持對象
(4)本質還是sqlite
數據庫和NSFile
文件系統;20K
閾值,內容少用數據庫,內容多用文件,綜合性能最高
(5)更新邏輯:設定時間和體積。隊列方式,最新使用的,新加入,需要優先的放隊列首部。更新時,先從隊列尾部刪除NSURLCache、NSURLRequest
本身的緩存機制,AFNetworking
用的是這一套。==== 這個用得不多,了解這些細節的不多,比較難
(1)獲得全局緩存對象(沒必要手動創建)
NSURLCache *cache = [NSURLCache sharedURLCache];
(2)設置內存緩存的最大容量(字節為單位,默認為512KB)
- (void)setMemoryCapacity:(NSUInteger)memoryCapacity;
(3)設置硬盤緩存的最大容量(字節為單位,默認為10M)
- (void)setDiskCapacity:(NSUInteger)diskCapacity;
(4)硬盤緩存的位置:沙盒/Library/Caches
(5)取得某個請求的緩存
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request;
(6)清除某個請求的緩存
- (void)removeCachedResponseForRequest:(NSURLRequest *)request;
(7)清除所有的緩存
- (void)removeAllCachedResponses;
NSURLRequestUseProtocolCachePolicy // 默認的緩存策略(取決于協議)
NSURLRequestReloadIgnoringLocalCacheData // 忽略緩存,重新請求
NSURLRequestReloadIgnoringLocalAndRemoteCacheData // 未實現
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData // 忽略緩存,重新請求
NSURLRequestReturnCacheDataElseLoad// 有緩存就用緩存,沒有緩存就重新請求
NSURLRequestReturnCacheDataDontLoad// 有緩存就用緩存,沒有緩存就不發請求,當做請求出錯處理(用于離線模式)
NSURLRequestReloadRevalidatingCacheData // 未實現
Http協議header字段,比如max-age,ETag,Last-Modified等字段的含義
-
UIWebView,WKWebView
清理緩存的機制?
WKWebView
從iOS8推出,但是清理緩存的API要從iOS9開始
屬性修飾符
block
中修飾外面變量的修飾符?__block
打破引用循環的關鍵字?
weak
;會自動設為nil
,防止崩潰;如果能解釋清楚自動設nil
的原理,是高手默認的關鍵字?
strong
nonatomic
? 非線程安全,加快速度。atomic
? 對setter
加鎖,用@synchronized
加鎖,耗性能;對getter
不加鎖,不能做到“真正的線程安全”assign、weak、unsafe_unretained
的區別?assign
用于基礎類型,“如果用于對象,不會設為nil
,會導致野指針,會帶來崩潰”copy?NSString,NSArray,NSDictionary,NSSet
等。引用計數對這些集合類型無意義
block引用循環
- 解決的方案
weakSelf
__weak __typeof(self)weakSelf = self;
[self.context performBlock:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doMoreThing];
} ];
strongSelf
的原因? 為了防止事情還沒做完,weakSelf
就變成了nil
block
不需要用weakSelf
的場合?
動畫的時候不需要,比如
self.alpha = 0;
[UIView animateWithDuration:0.2 animations:^ {
self.alpha = 1;
}]
runtime動態特性
-
NSString *obj = [[NSSData alloc]init] ,obj
在編譯時和運行時分別是什么類型的對象?
編譯時是NSString
, 運行時是NSSData
的一個實例
字典轉模型的原理?第三方庫?
YYModel
屬性列表,class_copyPropertyList
不埋點統計,怎么做到? 熱更新
JSPatch
的原理?
方法交換Method Swizzling class_getInstanceMethod() method_exchangeImplementations()
如何給類別
category
添加屬性?
關聯對象
objc_setAssociatedObject objc_getAssociatedObject
如何在不創建類的前提下調用類的方法?用
URL
處理函數調用
NSClassFromString()
這個函數可以把URL
中的字符串轉化為本地定義的類
用performSelector
方法執行相應的方法
Native和H5的交互方式
(1)截取URL
,定義scheme
,做相應處理
(2)JavaScriptCore
框架jsContext
,使用注入的方法
(3)WKWebView
的注入方式
第三方庫WebViewJavascriptBridge
使用的是截取URL
的方式,對UIWebView
和WKWebView
都適用
深復制,淺復制
NSArray *array = @[@"a", @"b", @"c", @"d"];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];
-
copyArray
與array
的地址是否一樣? 一樣 -
mCopyArray
和array
的地址又是否一樣? 不一樣 - 改變
mCopyArray
里面的元素內容,是否會刻變array
的內容? 不改變 -
copy
和mutableCopy
的拷貝操作有何不同?
copy
淺拷貝,只是指針的復制,而內容未復制;
mutableCopy
是深拷貝,復制內容,新分配一段內存;
iOS架構
MVC
MVVM
MVP
VIPER
NSArray的實現方式?
指針的數組
需要區分流量來自哪個渠道,怎么做?
提升表格性能的方法?
(1)無用的網絡請求及時取消
(2)表格cell
重用
(3)提前算好cell
的高度
(4)圓角不要用cornerRadius
Https和Http的區別?
Https == http + socket + TLS
iOS9開始,XCode默認用Https
如何繼續用Http
?在plist
中將某個字段打開
企業版賬號發布時,ipa
包可以http
的,但是那個plist
文件是需要https
的,不然不能自動安裝程序
bitCode
從iOS9開始
好處是降低安裝包的大小
蘋果后臺根據用戶手機,只下傳必要的圖片
在ViewDidLoad中設置frame有什么問題?
UIImageView實現圓角的方法?
(1)Qurarz
畫
(2)layer
的CornerRadius
(3)用path
畫
連接藍牙要注意些什么?
iOS中提供一個單例用于藍牙相關的函數
(1)廣播,用于掃描設備,選中特定設備
(2)建立點對點連接
(3)協議一般開頭是兼容微信的頭部,然后是自己的頭部,然后是數據
(4)數據要按照一定的大小進行分包,每次傳輸的大小是受限的
(5)數據是NSData
的,轉化為有意義的自定義類型時要注意大端和小端字節序的問題
(6)傳輸時有奇偶校驗的事情,要跟firmware
端的約定好
(7)丟包重傳,定時重連,空中升級等等都是比較令人頭疼的內容
Object-C的一些容易誤解的特性
- 下面的代碼輸出什么?
@implementation Son : Father
- (id)init {
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
// 輸出
NSStringFromClass([self class]) = Son
NSStringFromClass([super class]) = Son
這個題目主要是考察關于Objective-C中對self
和super
的理解。我們都知道:self
是類的隱藏參數,指向當前調用方法的這個類的實例。那super
呢?
很多人會想當然的認為super
和self
類似,應該是指向父類的指針吧!”。這是很普遍的一個誤區。其實super
是一個 Magic Keyword,它本質是一個編譯器標示符,和self
是指向的同一個消息接受者!他們兩個的不同點在于:super
會告訴編譯器,調用class
這個方法時,要去父類的方法,而不是本類里的。
上面的例子不管調用[self class]
還是[super class]
,接受消息的對象都是當前Son *xxx
這個對象。
當使用self
調用方法時,會從當前類的方法列表中開始找,如果沒有,就從父類中再找;而當使用super
時,則從父類的方法列表中開始找。然后調用父類的這個方法。