答的不對的地方,還請不吝指出 (陸續寫答案) !
1.如何應對APP版本升級,數據結構隨之變化?
若是是移動端, 視數據的重要性來定, 若是不重要, 那就忽視它. 若是重要, 就要額外作一個檢查Documents(我這裏假設你的數據文件放在Documents下)下的數據文件, 若是存在, 就SQL導出再加上按照新的數據結構導入到新的數據文件. 也就是兩句SQL的事, 在升級後第一次進入應用的時候作這個事.
若是是服務端, 正常狀況仍是須要作接口層(固然, 我也遇到沒作接口層, 直接遠程數據庫操做的, 對這種, 我無話可說), 接口層的變更幅度, 每每沒有數據層的變更大, 有時候, 哪怕數據結構變化了, 但接口層仍是同樣. 若是是碰到數據層變化逼迫接口層變化的狀況, 那就須要保留老接口的同時, 提供新接口服務, 直到使用老接口的app保有量低到必定程度, 再關閉老接口. 個人產品接口, 是在接口中加上一個v(version)參數做爲版本判斷標誌.
2.經常使用的設計模式
(一)代理模式
應用場景:當一個類的某些功能須要由別的類來實現,可是又不肯定具體會是哪一個類實現。
優點:解耦合
敏捷原則:開放-封閉原則
實例:tableview的 數據源delegate,經過和protocol的配合,完成委託訴求。
列表row個數delegate
自定義的delegate
(二)觀察者模式
應用場景:通常爲model層對,controller和view進行的通知方式,不關心誰去接收,只負責發佈信息。
優點:解耦合
敏捷原則:接口隔離原則,開放-封閉原則
實例:Notification通知中心,註冊通知中心,任何位置能夠發送消息,註冊觀察者的對象能夠接收。
kvo,鍵值對改變通知的觀察者,平時基本沒用過。
(三)MVC模式
應用場景:是一中很是古老的設計模式,經過數據模型,控制器邏輯,視圖展現將應用程序進行邏輯劃分。
優點:使系統,層次清晰,職責分明,易於維護
敏捷原則:對擴展開放-對修改封閉
實例:model-即數據模型,view-視圖展現,controller進行UI展示和數據交互的邏輯控制。
(四)單例模式
應用場景:確保程序運行期某個類,只有一份實例,用於進行資源共享控制。
優點:使用簡單,延時求值,易於跨模塊
敏捷原則:單一職責原則
實例:[UIApplication sharedApplication]。
注意事項:確保使用者只能經過 getInstance方法才能得到,單例類的惟一實例。
java,C++中使其沒有公有構造函數,私有化並覆蓋其構造函數。
object c中,重寫allocWithZone方法,保證即便用戶用 alloc方法直接建立單例類的實例,
返回的也只是此單例類的惟一靜態變量。
(五)策略模式
應用場景:定義算法族,封裝起來,使他們之間能夠相互替換。
優點:使算法的變化獨立於使用算法的用戶
敏捷原則:接口隔離原則;多用組合,少用繼承;針對接口編程,而非實現。
實例:排序算法,NSArray的sortedArrayUsingSelector;經典的鴨子會叫,會飛案例。
注意事項:1,剝離類中易於變化的行爲,經過組合的方式嵌入抽象基類
2,變化的行爲抽象基類爲,全部可變變化的父類
3,用戶類的最終實例,經過注入行爲實例的方式,設定易變行爲
防止了繼承行爲方式,致使無關行爲污染子類。完成了策略封裝和可替換性。
(六)工廠模式
應用場景:工廠方式建立類的實例,多與proxy模式配合,建立可替換代理類。
優點:易於替換,面向抽象編程,application只與抽象工廠和易變類的共性抽象類發生調用關係。
敏捷原則:DIP依賴倒置原則
實例:項目部署環境中依賴多個不一樣類型的數據庫時,須要使用工廠配合proxy完成易用性替換
注意事項:項目初期,軟件結構和需求都沒有穩定下來時,不建議使用此模式,由於其劣勢也很明顯,
增 加了代碼的複雜度,增長了調用層次,增長了內存負擔。因此要注意防止模式的濫用。
3.單例會有什麼弊端?
主要優勢:
一、提供了對惟一實例的受控訪問。
二、因爲在系統內存中只存在一個對象,所以能夠節約系統資源,對於一些須要頻繁建立和銷燬的對象單例模式無疑能夠提升系統的性能。
三、容許可變數目的實例。
主要缺點:
一、因爲單利模式中沒有抽象層,所以單例類的擴展有很大的困難。
二、單例類的職責太重,在必定程度上違背了「單一職責原則」。
三、濫用單例將帶來一些負面問題,如爲了節省資源將數據庫鏈接池對象設計爲的單例類,可能會致使共享鏈接池對象的程序過多而出現鏈接池溢出;若是實例化的對象長時間不被利用,系統會認爲是垃圾而被回收,這將致使對象狀態的丟失。
4.編程題:簡述「Snakes and Ladders」的實現思路
5.何時會使用Core Graphics,以及使用步驟?
Core Graphics是基於C的API,當使用繪圖操做的時候才能用到!
- 獲取上下文(畫布)
- 建立路徑(自定義或者調用系統的API)並添加到上下文中。
- 進行繪圖內容的設置(畫筆顏色、粗細、填充區域顏色、陰影、鏈接點形狀等)
- 開始繪圖(CGContextDrawPath)
- 釋放路徑(CGPathRelease)
6.你會如何存儲用戶的一些敏感信息,如登陸的token
使用keychain來存儲,也就是鑰匙串,使用keychain須要導入Security框架
iOS的keychain服務提供了一種安全的保存私密信息(密碼,序列號,證書等)的方式,每一個ios程序都有一個獨立的keychain存儲。相對於 NSUserDefaults、文件保存等通常方式,keychain保存更爲安全,並且keychain裏保存的信息不會因App被刪除而丟失,因此在 重裝App後,keychain裏的數據還能使用。從ios 3。0開始,跨程序分享keychain變得可行。
如何須要在應用裏使 用使用keyChain,咱們須要導入Security.framework ,keychain的操做接口聲明在頭文件SecItem.h裏。直接使用SecItem.h裏方法操做keychain,須要寫的代碼較爲複雜,爲減輕 我們程序員的開發,咱們能夠使用一些已經封裝好了的工具類,下面我會簡單介紹下我用過的兩個工具類:KeychainItemWrapper和 SFHFKeychainUtils。
自定義一個keychain的類
#import <Security/Security.h>
@implementation YCKKeyChain
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
service, (__bridge_transfer id)kSecAttrService,
service, (__bridge_transfer id)kSecAttrAccount,
(__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
nil];
}
+ (void)save:(NSString *)service data:(id)data {
得到搜索字典
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
添加新的刪除舊的
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
添加新的對象到字符串
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
查詢鑰匙串
SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}
+ (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
配置搜索設置
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
[keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", service, e);
} @finally {
}
}
return ret;
}
+ (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
在別的類實現存儲,加載,刪除敏感信息方法
用來標識這個鑰匙串
static NSString * const KEY_IN_KEYCHAIN = @"com.yck.app.allinfo";
用來標識密碼
static NSString * const KEY_PASSWORD = @"com.yck.app.password";
+ (void)savePassWord:(NSString *)password
{
NSMutableDictionary *passwordDict = [NSMutableDictionary dictionary];
[passwordDict setObject:password forKey:KEY_PASSWORD];
[YCKKeyChain save:KEY_IN_KEYCHAIN data:passwordDict];
}
+ (id)readPassWord
{
NSMutableDictionary *passwordDict = (NSMutableDictionary *)[YCKKeyChain load:KEY_IN_KEYCHAIN];
return [passwordDict objectForKey:KEY_PASSWORD];
}
+ (void)deletePassWord
{
[YCKKeyChain delete:KEY_IN_KEYCHAIN];
}
7.iOS Extension 是什麼?
Extension是擴展,沒有分類名字,是一種特殊的分類,類擴展能夠擴展屬性,成員變量和方法
8.Apple Pay 是什麼?它的大概工做流程是怎樣的?
是蘋果研製的一款用於支付的應用。
Apple Pay依靠NFC芯片,經過結合Touch ID,能夠便捷完成移動端支付,而且能夠經過拍照添加信用卡。Apple Pay全部存儲的支付信息都是通過加密的,用戶能夠經過Find my iPhone來關閉全部的支付功能。此外,iTunes用戶能夠使用iTunes中已經存儲的信用卡信息。
Apple Pay在消費支付流程裏是扮演的是支付通道的角色,把實物信用卡電子化。經過Apple Pay消費的時候,信用卡消費信息是經過蘋果的通道到銀聯,銀聯再跟相關的髮卡商結算。
9.iOS 的簽名機制大概是怎樣的?
10.block底層實現
block本質是指向一個結構體的一個指針
運行時機制 比較高級的特性 純C語言
平時寫的OC代碼 轉換成C語言運行時的代碼
指令:clang -rewrite-objc main.m(能夠打印驗證)
默認狀況下,任何block都是在棧裏面的,隨時可能被回收
只要對其作一次copy操做 block的內存就會放在堆裏面 不會釋放
只有copy才能產生一個新的內存地址 全部地址會發生改變
11.UIScrollView 大概是如何實現的,它是如何捕捉、響應手勢的?
UIScrollView在滾動過程中,實際上是在修改原點座標。當手指觸摸後, scroll view會暫時攔截觸摸事件,使用一個計時器。假如在計時器到點後沒有發生手指移動事件,那麼 scroll view 發送 tracking events 到被點擊的 subview。假如在計時器到點前發生了移動事件,那麼 scroll view 取消 tracking 本身發生滾動。
首先了解下UIScrollView對於touch事件的接收處理原理:
UIScrollView應該是重載了hitTest 方法,並總會返回itself 。因此全部的touch 事件都會進入到它本身裏面去了。內部的touch事件檢測到這個事件是否是和本身相關的,或者處理或者除遞給內部的view。
爲了檢測touch是處理仍是傳遞,UIScrollView當touch發生時會生成一個timer。
- 若是150ms內touch未產生移動,它就把這個事件傳遞給內部view
- 若是150ms內touch產生移動,開始scrolling,不會傳遞給內部的view。(例如, 當你touch一個table時候,直接scrolling,你touch的那行永遠不會highlight。)
- 若是150ms內touch未產生移動而且UIScrollView開始傳遞內部的view事件,可是移動足夠遠的話,且canCancelContentTouches = YES,UIScrollView會調用touchesCancelled方法,cancel掉內部view的事件響應,並開始scrolling。(例如, 當你touch一個table, 中止了一會,而後開始scrolling,那一行就首先被highlight,可是隨後就不在高亮了)
12.NSOperation 相比於 GCD 有哪些優點?
GCD是基於c的底層api,NSOperation屬於object-c類。ios 首先引入的是NSOperation,IOS4以後引入了GCD和NSOperationQueue而且其內部是用gcd實現的。
相對於GCD:
1,NSOperation擁有更多的函數可用,具體查看api。
2,在NSOperationQueue中,能夠創建各個NSOperation之間的依賴關係。
3,有kvo,能夠監測operation是否正在執行(isExecuted)、是否結束(isFinished),是否取消(isCanceld)。
4,NSOperationQueue能夠方便的管理併發、NSOperation之間的優先級。
GCD主要與block結合使用。代碼簡潔高效。
GCD也能夠實現複雜的多線程應用,主要是創建個個線程時間的依賴關係這類的狀況,可是須要本身實現相比NSOperation要複雜。
具體使用哪一個,依需求而定。 從我的使用的感受來看,比較合適的用法是:除了依賴關係儘可能使用GCD,由於蘋果專門爲GCD作了性能上面的優化。
13.如何訪問並修改一個類的私有屬性?
有兩種方法能夠訪問私有屬性,一種是經過KVC獲取,一種是經過runtime訪問並修改私有屬性
14.支付功能
支付寶是第三方支付平臺,簡單來講就是協調客戶,商戶,銀行三者關係的方便平臺
使用支付寶進行一個完整的支付功能,大體有如下步驟:
a 與支付寶進行簽約,得到商戶ID(partner)和帳號ID(seller)
b 下載相應的公鑰私鑰文件(加密簽名用)
c 下載支付寶SDK
d 生成訂單信息
e 調用支付寶客戶端,有支付寶客戶端跟支付寶安全服務器打交道
f 支付完畢後返回支付結果給客戶端和服務器
支付功能的實現 有兩種方式:
1 支付寶的應用能夠 用url 直接鏈接到 支付寶的官網 (固然後臺是要進行處理的)
2 第二種就是添加支付寶的第三方了 首先 下載支付寶的demo
支付寶的demo 通常的常見問題解決
1 No architecutures to compile for (ONLY_ACTIVE_ARCH = YES, active arch = x86_64,VALID_ARCHS = i386)
出現這樣的問題通常是 將 64 位編譯進去就能解決了(這個問題只要你下載的是最新的demo通常不多見了 )
解決方案:
targets -> Architectures 下面的Valid Architectures 添加上 arm64
2 將支付寶的第三方添加到項目中的時候 有時 會出現 openssl 文件中的.h 文件報錯 說此文件不能被找到出現這樣的問題是 的緣由通常是添加的路徑 不對
解決方案:
點擊項目名稱,點擊「Build Settings」選項卡,在搜索框中,以關鍵字「search」搜索,對「Header Search Paths」 增長頭文件路徑:$(SRCRCOT)/項目名稱 設置一下路徑 通常都能解決。
3 Cannot find interface declaration for "NSObject", supercalss of 'Base64'
解決方案 打開報錯的文件,增長頭文件
#import <Foundation/Foundation.h>
基本上支付寶中的demo 裏面的問題通常都會獲得解決。而後 看着demo 跟實際的項目結合一下就ok 了
正式開始 支付寶教程:
(由於申請的工做不是我作的 因此就此過程就略了 )
1 將須要的文件,靜態庫等拖入工程中,這裏有:include,libs,Utilities,libcrypto.a,libssl.a文件
2 添加 庫
Linked Frameworks and Libraries 中 添加
libssl.a libcrypto.a SystemConfiguration.framework
AlipaySDK.framework
3 若是商戶要在某個文件中使用給支付寶的SDK 類庫,須要增長引用頭文件
#import "Order.h"
#import "DataSigner.h"
#import <AlipaySDK/AlipaySDK.h>
4 後面的基本上都是 按照官方demo寫的
接口調用步驟:
1.封裝訂單模型將商品信息賦予AlixPayOrder的成員變量
Order *order = [[Order alloc] init];
應用註冊scheme,在項目的info.plist 定義URL types
NSString *appScheme = @"zhifu";
生成訂單描述
NSString *orderSpec = [order description];
2.簽名:獲取私鑰並將商戶信息簽名,外部商戶能夠根據狀況存放私鑰和簽名,只須要遵循RSA簽名規範,並將簽名字符串base64編碼和UrlEncode
idsigner = CreateRSADataSigner(@「私鑰key」);
NSString *signedString = [signer signString:orderSpec];
傳入訂單描述 進行 簽名
NSString *signedString = [signer signString:orderSpec];
3.生成訂單字符串
NSString *orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",orderSpec,signedString, @"RSA"];
4.調用支付接口
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) { }];
15.+[UIView animateWithDuration:animations:completion:] 內部大概是如何實現的?
animateWithDuration:這就等於建立一個定時器
animations:這是建立定時器須要實現的SEL
completion:是定時器結束之後的一個回調block
16.Toll-Free Bridging 是什麼?什麼狀況下會使用?
17.如何實現夜間模式?
1.準備兩套資源,分別對應日間模式和夜間模式。
2.在系統全局保存一個變量(BOOL isNight),根據用戶的操做改變這個變量的值;
3.把每一個須要被改變的view, viewcontroller加入通知中心中監聽(NeedTransferToNight和NeedTransferToDay)事件;
4.默認爲日間模式,isNight = YES.
5. 當用戶點擊夜間按鈕時,若是isNight == YES, 講此變量的值置爲NO,通知中心發佈NeedTransferToNight通知,全部須要被改變的view和viewcontroller在監聽到此事 件時使用夜間資源從新繪製自身。其餘view在初始化時若是發現isNight爲YES.則使用夜間資源初始化自身。(反之亦然)
6.運行程序,能夠看到夜間模式。
18.如何捕獲異常?
1> 在app啓動時(didFinishLaunchingWithOptions),添加一個異常捕獲的監聽。
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
2> 實現捕獲異常日誌並保存到本地的方法。
void UncaughtExceptionHandler(NSException *exception){
異常日誌獲取
NSArray *excpArr = [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSString *excpCnt = [NSString stringWithFormat:@"exceptionType: %@ \n reason: %@ \n stackSymbols: %@",name,reason,excpArr];
平常日誌保存(能夠將此功能單獨提煉到一個方法中)
NSArray *dirArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *dirPath = dirArr[0];
NSString *logDir = [dirPath stringByAppendingString:@"/CrashLog"];
BOOL isExistLogDir = YES;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:logDir]) {
isExistLogDir = [fileManager createDirectoryAtPath:logDir withIntermediateDirectories:YES attributes:nil error:nil];
}
if (isExistLogDir) {
此處可擴展
NSString *logPath = [logDir stringByAppendingString:@"/crashLog.txt"];
[excpCnt writeToFile:logPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
}
19.frame 與 center bounds的關係
1.frame屬性是相對於父容器的定位座標。
2.bounds屬性針對於本身,指明大小邊框,默認點爲(0,0),而寬和高與frame寬和高相等。
3.center屬性是針對與frame屬性的中心點座標。
4.當frame變化時,bounds和center相應變化。
5.當bounds變化時,frame會根據新bounds的寬和高,在不改變center的狀況下,進行從新設定。
6. center永遠與frame相關,指定frame的中心座標!
20.直接調用_objc_msgForward函數將會發生什麼?
_objc_msgForward是 IMP 類型,用於消息轉發的:當向一個對象發送一條消息,但它並無實現的時候,_objc_msgForward會嘗試作消息轉發。
直接調用_objc_msgForward是很是危險的事,若是用很差會直接致使程序Crash,可是若是用得好,能作不少很是酷的事。
一旦調用_objc_msgForward,將跳過查找 IMP 的過程,直接觸發「消息轉發」,若是調用了_objc_msgForward,即便這個對象確實已經實現了這個方法,你也會告訴objc_msgSend:「我沒有在這個對象裏找到這個方法的實現」
21.通知中心的實現原理?
推送通知的過程能夠分爲如下幾步:
- 應用服務提供商從服務器端把要發送的消息和設備令牌(device token)發送給蘋果的消息推送服務器APNs。
- APNs根據設備令牌在已註冊的設備(iPhone、iPad、iTouch、mac等)查找對應的設備,將消息發送給相應的設備。
- 客戶端設備接將接收到的消息傳遞給相應的應用程序,應用程序根據用戶設置彈出通知消息。
22.如何關閉默認的KVO的默認實現,KVO的實現原理?
所謂的「手動觸發」是區別於「自動觸發」:
自動觸發是指相似這種場景:在註冊 KVO 以前設置一個初始值,註冊以後,設置一個不同的值,就能夠觸發了。
想知道如何手動觸發,必須知道自動觸發 KVO 的原理:
鍵值觀察通知依賴於 NSObject 的兩個方法: willChangeValueForKey: 和 didChangevlueForKey: 。在一個被觀察屬性發生改變以前, willChangeValueForKey: 必定會被調用,這就 會記錄舊的值。而當改變發生後, didChangeValueForKey: 會被調用,繼而 observeValueForKey:ofObject:change:context: 也會被調用。若是能夠手動實現這些調用,就能夠實現「手動觸發」了。
當你觀察一個對象時,一個新的類會被動態建立。這個類繼承自該對象的本來的類,並重寫了被觀察屬性的 setter 方法。重寫的 setter 方法會負責在調用原 setter 方法以前和以後,通知全部觀察對象:值的更改。最後經過 isa 混寫(isa-swizzling) 把這個對象的 isa 指針 ( isa 指針告訴 Runtime 系統這個對象的類是什麼 ) 指向這個新建立的子類,對象就神奇的變成了新建立的子類的實例。我畫了一張示意圖,以下所示:
23.斷點續傳如何實現的?
斷點續傳的理解能夠分爲兩部分:一部分是斷點,一部分是續傳。斷點的由來是在下載過程當中,將一個下載文件分紅了多個部分,同時進行多個部分一塊兒的下載,當 某個時間點,任務被暫停了,此時下載暫停的位置就是斷點了。續傳就是當一個未完成的下載任務再次開始時,會從上次的斷點繼續傳送。
使用多線程斷點續傳下載的時候,將下載或上傳任務(一個文件或一個壓縮包)人爲的劃分爲幾個部分,每個部分採用一個線程進行上傳或下載,多個線程併發能夠佔用服務器端更多資源,從而加快下載速度。
在下載(或上傳)過程當中,若是網絡故障、電量不足等緣由致使下載中斷,這就須要使用到斷點續傳功能。下次啓動時,能夠從記錄位置(已經下載的部分)開始,繼續下載之後未下載的部分,避免重複部分的下載。斷點續傳實質就是能記錄上一次已下載完成的位置。
斷點續傳的過程
①斷點續傳須要在下載過程當中記錄每條線程的下載進度;
②每次下載開始以前先讀取數據庫,查詢是否有未完成的記錄,有就繼續下載,沒有則建立新記錄插入數據庫;
③在每次向文件中寫入數據以後,在數據庫中更新下載進度;
④下載完成以後刪除數據庫中下載記錄。
24.通知,代理,KVO的區別,以及通知的多線程問題
delegation
當咱們第一次編寫ios應用時,咱們注意到不斷的在使用「delegate」,而且貫穿於整個SDK。delegation模式不是IOS特有的模式,而是依賴與你過去擁有的編程背景。針對它的優點以及爲何常用到,這種模式可能不是很明顯的。
delegation的基本特徵是,一個controller定義了一個協議(即一系列的方法定義)。該協議描述了一個delegate對象爲了可以響應一個controller的事件而必須作的事情。協議就是delegator說,「若是你想做爲個人delegate,那麼你就必須實現這些方法」。實現這些方法就是容許controller在它的delegate可以調用這些方法,而它的delegate知道何時調用哪一種方法。delegate能夠是任何一種對象類型,所以controller不會與某種對象進行耦合,可是當該對象嘗試告訴委託事情時,該對象能肯定delegate將響應。
delegate的優點:
1.很是嚴格的語法。全部將聽到的事件必須是在delegate協議中有清晰的定義。
2.若是delegate中的一個方法沒有實現那麼就會出現編譯警告/錯誤
3.協議必須在controller的做用域範圍內定義
4.在一個應用中的控制流程是可跟蹤的而且是可識別的;
5.在一個控制器中能夠定義定義多個不一樣的協議,每一個協議有不一樣的delegates
6.沒有第三方對象要求保持/監視通訊過程。
7.可以接收調用的協議方法的返回值。這意味着delegate可以提供反饋信息給controller
缺點:
1.須要定義不少代碼:1.協議定義;2.controller的delegate屬性;3.在delegate自己中實現delegate方法定義
2.在釋放代理對象時,須要當心的將delegate改成nil。一旦設定失敗,那麼調用釋放對象的方法將會出現內存crash
3.在一個controller中有多個delegate對象,而且delegate是遵照同一個協議,但仍是很難告訴多個對象同一個事件,不過有可能。
notification
在IOS應用開發中有一個」Notification Center「的概念。它是一個單例對象,容許當事件發生時通知一些對象。它容許咱們在低程度耦合的狀況下,知足控制器與一個任意的對象進行通訊的目的。這種模式的基本特徵是爲了讓其餘的對象可以接收到在該controller中發生某種事件而產生的消息,controller用一個key(通知名稱)。這樣對於controller來講是匿名的,其餘的使用一樣的key來註冊了該通知的對象(即觀察者)可以對通知的事件做出反應。
通知優點:
1.不須要編寫多少代碼,實現比較簡單;
2.對於一個發出的通知,多個對象可以作出反應,即1對多的方式實現簡單
3.controller可以傳遞context對象(dictionary),context對象攜帶了關於發送通知的自定義的信息
缺點:
1.在編譯期不會檢查通知是否可以被觀察者正確的處理;
2.在釋放註冊的對象時,須要在通知中心取消註冊;
3.在調試的時候應用的工做以及控制過程難跟蹤;
4.須要第三方對喜好那個來管理controller與觀察者對象之間的聯繫;
5.controller和觀察者須要提早知道通知名稱、UserInfo dictionary keys。若是這些沒有在工做區間定義,那麼會出現不一樣步的狀況;
6.通知發出後,controller不能從觀察者得到任何的反饋信息
KVO
KVO是一個對象可以觀察另一個對象的屬性的值,而且可以發現值的變化。前面兩種模式更加適合一個controller與任何其餘的對象進行通訊,而KVO更加適合任何類型的對象偵聽另一個任意對象的改變(這裏也能夠是controller,但通常不是controller)。這是一個對象與另一個對象保持同步的一種方法,即當另一種對象的狀態發生改變時,觀察對象立刻做出反應。它只能用來對屬性做出反應,而不會用來對方法或者動做做出反應。
優勢:
1.可以提供一種簡單的方法實現兩個對象間的同步。例如:model和view之間同步;
2.可以對非咱們建立的對象,即內部對象的狀態改變做出響應,並且不須要改變內部對象(SKD對象)的實現;
3.可以提供觀察的屬性的最新值以及先前值;
4.用key paths來觀察屬性,所以也能夠觀察嵌套對象;
5.完成了對觀察對象的抽象,由於不須要額外的代碼來容許觀察值可以被觀察
缺點:
1.咱們觀察的屬性必須使用strings來定義。所以在編譯器不會出現警告以及檢查;
2.對屬性重構將致使咱們的觀察代碼再也不可用;
3.複雜的「IF」語句要求對象正在觀察多個值。這是由於全部的觀察代碼經過一個方法來指向;
4.當釋放觀察者時不須要移除觀察者。
總結:
從上面的分析中能夠看出3中設計模式都有各自的優勢和缺點。其實任何一種事物都是這樣,問題是如何在正確的時間正確的環境下選擇正確的事物。下面就講講如何發揮他們各自的優點,在哪一種狀況下使用哪一種模式。注意使用任何一種模式都沒有對和錯,只有更適合或者不適合。每一種模式都給對象提供一種方法來通知一個事件給其餘對象,並且前者不須要知道偵聽者。在這三種模式中,我認爲KVO有最清晰的使用案例,並且針對某個需求有清晰的實用性。而另外兩種模式有比較類似的用處,而且常常用來給controller間進行通訊。那麼咱們在什麼狀況使用其中之一呢?
根據我開發iOS應用的經歷,我發現有些過度的使用通知模式。我我的不是很喜歡使用通知中心。我發現用通知中心很難把握應用的執行流程。UserInfo dictionaries的keys處處傳遞致使失去了同步,並且在公共空間須要定義太多的常量。對於一個工做於現有的項目的開發者來講,若是過度的使用通知中心,那麼很難理解應用的流程。
我以爲使用命名規則好的協議和協議方法定義對於清晰的理解controllers間的通訊是很容易的。努力的定義這些協議方法將加強代碼的可讀性,以及更好的跟蹤你的app。代理協議發生改變以及實現均可經過編譯器檢查出來,若是沒有將會在開發的過程當中至少會出現crash,而不只僅是讓一些事情異常工做。甚至在同一事件通知多控制器的場景中,只要你的應用在controller層次有着良好的結構,消息將在該層次上傳遞。該層次可以向後傳遞直至讓全部須要知道事件的controllers都知道。
固然會有delegation模式不適合的例外狀況出現,並且notification可能更加有效。例如:應用中全部的controller須要知道一個事件。然而這些類型的場景不多出現。另一個例子是當你創建了一個架構並且須要通知該事件給正在運行中應用。
根據經驗,若是是屬性層的時間,無論是在不須要編程的對象仍是在牢牢綁定一個view對象的model對象,我只使用觀察。對於其餘的事件,我都會使用delegate模式。若是由於某種緣由我不能使用delegate,首先我將估計個人app架構是否出現了嚴重的錯誤。若是沒有錯誤,而後才使用notification。
25.JSON 轉對象的時候,一個NSString的屬性,若是後臺返回對應這個屬性的類型不是NSString,而是其餘的數據類型,怎麼辦?
26.蘋果是如何實現autorelesaepool的 ?
autoreleasepool以一個隊列數組的形式實現,主要經過下列三個函數完成.
- objc_autoreleasepoolPush
- objc_autoreleasepoolPop
- objc_aurorelease
27.說說iOS7以後, 藍牙的圍欄功能
28.無線滾動
29.如何實現相似 「Find My iPhone」 這樣功能,這個是咱實現的呢?
30.UIWebView 有哪些性能問題?有沒有可替代的方案?
31.爲何 NotificationCenter 要 removeObserver? 如何實現自動 remove?
32.深度遍歷和廣度遍歷使用場景
33.如何保證軟件質量, 怎麼分析Crash日誌
34.如何加密
iOS裏常見的幾種信息加密方法簡單總結
一.MD5加密
MD5加密是最經常使用的加密方法之一,是從一段字符串中經過相應特徵生成一段32位的數字字母混合碼。
MD5主要特色是 不可逆,相同數據的MD5值確定同樣,不一樣數據的MD5值不同(也不是絕對的,但基本是不能同樣的)。
MD5算法還具備如下性質:
一、壓縮性:任意長度的數據,算出的MD5值長度都是固定的。
二、容易計算:從原數據計算出MD5值很容易。
三、抗修改性:對原數據進行任何改動,哪怕只修改1個字節,所獲得的MD5值都有很大區別。
四、弱抗碰撞:已知原數據和其MD5值,想找到一個具備相同MD5值的數據(即僞造數據)是很是困難的。
五、強抗碰撞:想找到兩個不一樣的數據,使它們具備相同的MD5值,是很是困難的。
MD5雖說是不可逆的 可是因爲有網站http://www.cmd5.com的存在,專門用來查詢MD5碼 因此有的簡單的MD5碼是能夠在這裏搜到源碼的。
爲了讓MD5碼更加安全 涌現了不少其餘方法 如加鹽。 鹽要足夠長足夠亂 獲得的MD5碼就很難查到。
終端代碼:$ echo -n abc|openssl md5 給字符串abc加密
二.HMAC加密
此加密方法須要先生成密鑰,而後再對密碼進行MD5和HMAC加密,數據庫中須要存放當時使用的密鑰和密碼加密後的密文
在用戶登錄時 再次對填入的密碼用密鑰進行加密 而且還要加上當前時間(精確到分鐘) 再次HMAC加密,服務器裏也會拿出之前存放的密文加上時間再次加密。因此就算黑客在中途截取了密碼的密文 也在能在1分鐘只能破譯纔能有效,大大增強了安全性。服務器爲了考慮到網絡的延遲通常會多算一種答案,如23分過來的密碼 他會把23分和22分的都算一下和用戶匹配只要對上一個就容許登錄。
如圖 用戶註冊與用戶登陸
三.base64加密
在MIME格式的電子郵件中,base64能夠用來將binary的字節序列數據編碼成ASCII字符序列構成的文本。使用時,在傳輸編碼方式中指 定base64。使用的字符包括大小寫字母各26個,加上10個數字,和加號「+」,斜槓「/」,一共64個字符,等號「=」用來做爲後綴用途。
完整的base64定義可見RFC 1421和RFC 2045。編碼後的數據比原始數據略長,爲原來的4/3。
原理圖
終端指令
先cd 找到當前目錄
加密: $ base64 abc.png -o abc.txt
解密: $ base64 abc.txt -o 123.png -D
四.對稱加密算法
優勢:算法公開、計算量小、加密速度快、加密效率高、可逆
缺點:雙方使用相同鑰匙,安全性得不到保證
現狀:對稱加密的速度比公鑰加密快不少,在不少場合都須要對稱加密,
相較於DES和3DES算法而言,AES算法有着更高的速度和資源使用效率,安全級別也較之更高了,被稱爲下一代加密標準
nECB :電子代碼本,就是說每一個塊都是獨立加密的
nCBC :密碼塊鏈,使用一個密鑰和一個初始化向量 (IV)對數據執行加密轉換
ECB和CBC區別:CBC更加複雜更加安全,裏面加入了8位的向量(8個0的話結果等於ECB)。在明文裏面改一個字母,ECB密文對應的那一行會改變,CBC密文從那一行日後都會改變。
ECB終端命令:
$ openssl enc -des-ecb -K 616263 -nosalt -in msg1.txt -out msg1.bin
CBC終端命令:
$ openssl enc -des-cbc -K 616263 -iv 0000000000000000 -nosalt -in msg1.txt -out msg2.bin
五.RSA加密
RSA非對稱加密算法
非對稱加密算法須要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)
公開密鑰與私有密鑰是一對,若是用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;若是用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密
特色:
非對稱密碼體制的特色:算法強度複雜、安全性依賴於算法與密鑰可是因爲其算法複雜,而使得加密解密速度沒有對稱加密解密的速度快
對稱密碼體制中只有一種密鑰,而且是非公開的,若是要解密就得讓對方知道密鑰。因此保證其安全性就是保證密鑰的安全,而非對稱密鑰體制有兩種密鑰,其中一個是公開的,這樣就能夠不須要像對稱密碼那樣傳輸對方的密鑰了
基本加密原理:
(1)找出兩個「很大」的質數:P & Q
(2)N = P * Q
(3)M = (P – 1) * (Q – 1)
(4)找出整數E,E與M互質,即除了1以外,沒有其餘公約數
(5)找出整數D,使得E*D除以M餘1,即 (E * D) % M = 1
通過上述準備工做以後,能夠獲得:
E是公鑰,負責加密
D是私鑰,負責解密
N負責公鑰和私鑰之間的聯繫
加密算法,假定對X進行加密
(X ^ E) % N = Y
n根據費爾馬小定義,根據如下公式能夠完成解密操做
(Y ^ D) % N = X
可是RSA加密算法效率較差,對大型數據加密時間很長,通常用於小數據。
經常使用場景:
分部要給總部發一段報文,先對報文整個進行MD5獲得一個報文摘要,再對這個報文摘要用公鑰加密。而後把報文和這個RSA密文一塊兒發過去。
總部接收到報文以後要先肯定報文是否在中途被人篡改,就先把這個密文用私鑰解密獲得報文摘要,再和整個報文MD5一下獲得的報文摘要進行對比 若是同樣就是沒被改過。
35.作過支付功能沒
36.你通常是如何優化你的APP的?
1、首頁啓動速度
啓動過程當中作的事情越少越好(儘量將多個接口合併)
不在UI線程上做耗時的操做(數據的處理在子線程進行,處理完通知主線程刷新)
在合適的時機開始後臺任務(例如在用戶指引節目就能夠開始準備加載的數據)
儘可能減少包的大小
優化方法:
量化啓動時間
啓動速度模塊化
輔助工具(友盟,聽雲,Flurry)
2、頁面瀏覽速度
json的處理(iOS 自帶的NSJSONSerialization,Jsonkit,SBJson)
數據的分頁(後端數據多的話,就要分頁返回,例如網易新聞,或者 微博記錄)
數據壓縮(大數據也能夠壓縮返回,減小流量,加快反應速度)
內容緩存(例如網易新聞的最新新聞列表都是要緩存到本地,從本地加載,能夠緩存到內存,或者數據庫,根據狀況而定)
延時加載tab(好比app有5個tab,能夠先加載第一個要顯示的tab,其餘的在顯示時候加載,按需加載)
算法的優化(核心算法的優化,例若有些app 有個 聯繫人姓名用漢語拼音的首字母排序)
3、操做流暢度優化:
Tableview 優化(tableview cell的加載優化)
ViewController加載優化(不一樣view之間的跳轉,能夠提早準備好數據)
4、數據庫的優化:
數據庫設計上面的重構
查詢語句的優化
分庫分表(數據太多的時候,能夠分不一樣的表或者庫)
5、服務器端和客戶端的交互優化:
客戶端儘可能減小請求
服務端儘可能作多的邏輯處理
服務器端和客戶端採起推拉結合的方式(能夠利用一些同步機制)
通訊協議的優化。(減小報文的大小)
電量使用優化(儘可能不要使用後臺運行)
6、非技術性能優化
產品設計的邏輯性(產品的設計必定要符合邏輯,或者邏輯儘可能簡單,不然會讓程序員抓狂,有時候用了好大力氣,才能夠完成一個小小的邏輯設計問題)
界面交互的規範(每一個模塊的界面的交互儘可能統一,符合操做習慣)
代碼規範(這個能夠隱形帶來app 性能的提升,好比 用if else 仍是switch ,或者是用!仍是 ==)
code review(堅持code Review 持續重構代碼。減小代碼的邏輯複雜度)
平常交流(常常分享一些代碼,或者邏輯處理中的坑)
37.push Notification原理
- 本地推送:不須要聯網也能夠推送,是開發人員在APP內設定特定的時間來提醒用戶幹什麼
- 遠程推送:須要聯網,用戶的設備會於蘋果APNS服務器造成一個長鏈接,用戶設備會發送uuid和Bundle idenidentifier給蘋果服務器,蘋果服務器會加密生成一個deviceToken給用戶設備,而後設備會將deviceToken發送給APP的服務器,服務器會將deviceToken存進他們的數據庫,這時候若是有人發送消息給我,服務器端就會去查詢個人deviceToken,而後將deviceToken和要發送的信息發送給蘋果服務器,蘋果服務器經過deviceToken找到個人設備並將消息推送到個人設備上,這裏還有個狀況是若是APP在線,那麼APP服務器會於APP產生一個長鏈接,這時候APPF服務器會直接經過deviceToken將消息推送到設備上
38.爲何 NotificationCenter 要 removeObserver? 如何實現自動 remove?
- 若是不移除的話,萬一註冊通知的類被銷燬之後又發了通知,程序會崩潰.由於向野指針發送了消息
- 實現自動remove:經過自釋放機制,經過動態屬性將remove轉移給第三者,解除耦合,達到自動實現remove
若是不移除的話,萬一註冊通知的類被銷燬之後又發了通知,程序會崩潰.由於向野指針發送了消息
實現自動remove:經過自釋放機制,經過動態屬性將remove轉移給第三者,解除耦合,達到自動實現remove
39.當 TableView 的 Cell 改變時,如何讓這些改變以動畫的形式呈現?
@interface ViewController ()
@property (nonatomic, strong) NSIndexPath *index;
@end
@implementation ViewController
static NSString *ID = @"cell";
- (void)viewDidLoad {
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
cell.textLabel.text = [NSString stringWithFormat:@"%ld",(long)indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(self.index == indexPath){
return 120;
}
return 60;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.index = indexPath;
[tableView deselectRowAtIndexPath:indexPath animated:TRUE];
重點是這2句代碼實現的功能
[tableView beginUpdates];
[tableView endUpdates];
}
40.如何把一個包含自定義對象的數組序列化到磁盤?
自定義對象只須要實現NSCoding協議便可
- (void)viewDidLoad
{
[super viewDidLoad];
User *user = [User new];
Account *account = [Account new];
NSArray *userArray = @[user, account];
存到磁盤
NSData * tempArchive = [NSKeyedArchiver archivedDataWithRootObject: userArray];
}
代理方法
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
self.user = [aDecoder decodeObjectForKey:@"user"];
self.account = [aDecoder decodeObjectForKey:@"account"];
}
return self;
}
代理方法
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.user forKey:@"user"];
[aCoder encodeObject:self.account forKey:@"account"];
}
41.非對稱加密特性和用法
非對稱加密算法多是世界上最重要的算法,它是當今電子商務等領域的基石。簡而言之,非對稱加密就是指加密密鑰和解密密鑰是不一樣的,並且加密密鑰和 解密密鑰是成對出現。非對稱加密又叫公鑰加密,也就是說成對的密鑰,其中一個是對外公開的,全部人均可以得到,稱爲公鑰,而與之相對應的稱爲私鑰,只有這 對密鑰的生成者才能擁有。公私鑰具備如下重要特性:
- 對於一個私鑰,有且只有一個與之對應的公鑰。生成者負責生成私鑰和公鑰,並保存私鑰,公開公鑰
- 公鑰是公開的,但不可能經過公鑰反推出私鑰,或者說極難反推,只能窮舉,因此只要密鑰足夠長度,要經過窮舉而獲得私鑰,幾乎是不可能的
- 經過私鑰加密的密文只能經過公鑰解密,公鑰加密的密文只有經過私鑰解密
因爲上述特性,非對稱加密具備如下的典型用法:
- 對信息保密,防止中間人攻擊:將明文經過接收人的公鑰加密,傳輸給接收人,由於只有接收人擁有對應的私鑰,別人不可能擁有或者不可能經過公鑰推算出私鑰,因此傳輸過程當中沒法被中間人截獲。只有擁有私鑰的接收人才能閱讀。此用法一般用於交換對稱密鑰。
- 身份驗證和防止篡改:權限狗用本身的私鑰加密一段受權明文,並將受權明文和加密後的密文,以及公鑰一併發送出來,接收方只須要經過公鑰將密文解密後與受權明文對比是否一致,就能夠判斷明文在中途是否被篡改過。此方法用於數字簽名。
著名的RSA算法就是非對稱加密算法,RSA以三個發明人的首字母命名。
非對稱加密算法如此強大可靠,卻有一個弊端,就是加解密比較耗時。所以,在實際使用中,每每與對稱加密和摘要算法結合使用。對稱加密很好理解,此處略過1w字。咱們再來看一下摘要算法。