那些著名或非著名的iOS面试题(中)
接上篇:那些著名或非著名的iOS面試題(上),本文繼續(xù)介紹一些著名或非著名的iOS面試題。
1. 反轉(zhuǎn)二叉樹,不用遞歸
/***?Definition?for?a?binary?tree?node.*?public?class?TreeNode?{*?????int?val;*?????TreeNode?left;*?????TreeNode?right;*?????TreeNode(int?x)?{?val?=?x;?}*?}*/遞歸方式:
public?class?Solution?{public?TreeNode?invertTree(TreeNode?root)?{if?(root?==?null)?{return?null;}root.left?=?invertTree(root.left);root.right?=?invertTree(root.right);TreeNode?tmp?=?root.left;root.left?=?root.right;root.right?=?tmp;return?root;} }Objective-C實現(xiàn):
/**?*?翻轉(zhuǎn)二叉樹(又叫:二叉樹的鏡像)?**?@param?rootNode?根節(jié)點**?@return?翻轉(zhuǎn)后的樹根節(jié)點(其實就是原二叉樹的根節(jié)點)?*/+?(BinaryTreeNode?*)invertBinaryTree:(BinaryTreeNode?*)rootNode?{if?(!rootNode)?{??return?nil;?}?if?(!rootNode.leftNode?&&?!rootNode.rightNode)?{??return?rootNode;?}?[self?invertBinaryTree:rootNode.leftNode];[self?invertBinaryTree:rootNode.rightNode];?BinaryTreeNode?*tempNode?=?rootNode.leftNode;?rootNode.leftNode?=?rootNode.rightNode;rootNode.rightNode?=?tempNode;?return?rootNode;}非遞歸方式:
+?(BinaryTreeNode?*)invertBinaryTree:(BinaryTreeNode?*)rootNode?{if?(!rootNode)?{??return?nil;?}if?(!rootNode.leftNode?&&?!rootNode.rightNode)?{??return?rootNode;?}NSMutableArray?*queueArray?=?[NSMutableArray?array];?//數(shù)組當成隊列[queueArray?addObject:rootNode];?//壓入根節(jié)點while?(queueArray.count?>?0)?{BinaryTreeNode?*node?=?[queueArray?firstObject];[queueArray?removeObjectAtIndex:0];?//彈出最前面的節(jié)點,仿照隊列先進先出原則BinaryTreeNode?*pLeft?=?node.leftNode;node.leftNode?=?node.rightNode;node.rightNode?=?pLeft;if?(node.leftNode)?{[queueArray?addObject:node.leftNode];}if?(node.rightNode)?{[queueArray?addObject:node.rightNode];}}return?rootNode; }示例代碼參考:二叉樹
2. 寫一個單例模式
+?(AccountManager?*)sharedManager {static?AccountManager?*sharedAccountManagerInstance?=?nil;static?dispatch_once_t?predicate;dispatch_once(&predicate,?^{sharedAccountManagerInstance?=?[[self?alloc]?init];?});return?sharedAccountManagerInstance; }3. iOS應用生命周期
應用程序的狀態(tài):
-
Not running未運行:程序沒啟動。
-
Inactive未激活:程序在前臺運行,不過沒有接收到事件。在沒有事件處理情況下程序通常停留在這個狀態(tài)。
-
Active激活:程序在前臺運行而且接收到了事件。這也是前臺的一個正常的模式。
-
Backgroud后臺:程序在后臺而且能執(zhí)行代碼,大多數(shù)程序進入這個狀態(tài)后會在在這個狀態(tài)上停留一會。時間到之后會進入掛起狀態(tài)(Suspended)。有的程序經(jīng)過特殊的請求后可以長期處于Backgroud狀態(tài)。
-
Suspended掛起:程序在后臺不能執(zhí)行代碼。系統(tǒng)會自動把程序變成這個狀態(tài)而且不會發(fā)出通知。當掛起時,程序還是停留在內(nèi)存中的,當系統(tǒng)內(nèi)存低時,系統(tǒng)就把掛起的程序清除掉,為前臺程序提供更多的內(nèi)存。
iOS的入口在main.m文件:
int?main(int?argc,?char?*argv[]) {@autoreleasepool?{return?UIApplicationMain(argc,?argv,?nil,?NSStringFromClass([AppDelegate?class]));} }main函數(shù)的兩個參數(shù),iOS中沒有用到,包括這兩個參數(shù)是為了與標準ANSI C保持一致。 UIApplicationMain函數(shù),前兩個和main函數(shù)一樣,重點是后兩個。
后兩個參數(shù)分別表示程序的主要類(principal class)和代理類(delegate class)。如果主要類(principal class)為nil,將從Info.plist中獲取,如果Info.plist中不存在對應的key,則默認為UIApplication;如果代理類(delegate class)將在新建工程時創(chuàng)建。
根據(jù)UIApplicationMain函數(shù),程序?qū)⑦M入AppDelegate.m,這個文件是xcode新建工程時自動生成的。下面看一下AppDelegate.m文件,這個關(guān)乎著應用程序的生命周期。
1、application didFinishLaunchingWithOptions:當應用程序啟動時執(zhí)行,應用程序啟動入口,只在應用程序啟動時執(zhí)行一次。若用戶直接啟動,lauchOptions內(nèi)無數(shù)據(jù),若通過其他方式啟動應用,lauchOptions包含對應方式的內(nèi)容。
2、applicationWillResignActive:在應用程序?qū)⒁苫顒訝顟B(tài)切換到非活動狀態(tài)時候,要執(zhí)行的委托調(diào)用,如 按下 home 按鈕,返回主屏幕,或全屏之間切換應用程序等。
3、applicationDidEnterBackground:在應用程序已進入后臺程序時,要執(zhí)行的委托調(diào)用。
4、applicationWillEnterForeground:在應用程序?qū)⒁M入前臺時(被激活),要執(zhí)行的委托調(diào)用,剛好與applicationWillResignActive 方法相對應。
5、applicationDidBecomeActive:在應用程序已被激活后,要執(zhí)行的委托調(diào)用,剛好與applicationDidEnterBackground 方法相對應。
6、applicationWillTerminate:在應用程序要完全推出的時候,要執(zhí)行的委托調(diào)用,這個需要要設(shè)置UIApplicationExitsOnSuspend的鍵值。
初次啟動:
iOS_didFinishLaunchingWithOptions iOS_applicationDidBecomeActive按下home鍵:
iOS_applicationWillResignActive iOS_applicationDidEnterBackground點擊程序圖標進入:
iOS_applicationWillEnterForeground iOS_applicationDidBecomeActive當應用程序進入后臺時,應該保存用戶數(shù)據(jù)或狀態(tài)信息,所有沒寫到磁盤的文件或信息,在進入后臺時,最后都寫到磁盤去,因為程序可能在后臺被殺死。釋放盡可能釋放的內(nèi)存。
-?(void)applicationDidEnterBackground:(UIApplication?*)application方法有大概5秒的時間讓你完成這些任務(wù)。如果超過時間還有未完成的任務(wù),你的程序就會被終止而且從內(nèi)存中清除。
如果還需要長時間的運行任務(wù),可以在該方法中調(diào)用:
[application?beginBackgroundTaskWithExpirationHandler:^{?NSLog(@"begin?Background?Task?With?Expiration?Handler");? }];程序終止
程序只要符合以下情況之一,只要進入后臺或掛起狀態(tài)就會終止:
①iOS 4.0以前的系統(tǒng)
②app是基于iOS 4.0之前系統(tǒng)開發(fā)的。
③設(shè)備不支持多任務(wù)
④在Info.plist文件中,程序包含了 UIApplicationExitsOnSuspend 鍵。
系統(tǒng)常常是為其他app啟動時由于內(nèi)存不足而回收內(nèi)存最后需要終止應用程序,但有時也會是由于app很長時間才響應而終止。如果app當時運行在后臺并且沒有暫停,系統(tǒng)會在應用程序終止之前調(diào)用app的代理的方法 - (void)applicationWillTerminate:(UIApplication *)application,這樣可以讓你可以做一些清理工作。你可以保存一些數(shù)據(jù)或app的狀態(tài)。這個方法也有5秒鐘的限制。超時后方法會返回程序從內(nèi)存中清除。
注意:用戶可以手工關(guān)閉應用程序。
4. 一工人給老板打7天工要求一塊金條 這金條只能切2次 工人每天要1/7金條 怎么分?
這道題解決的主要難點在于:不是給出去的就收不回來了,可以用交換的方法。
把金條分成三段(就是分兩次,或者切兩刀),分別是整根金條的1/7、2/7、 4/7。
第一天:給1/7的, 第二天:給2/7的,收回1/7的; 第三天,給1/7的; 第四天:給4/7的,收回1/7和2/7的 ;第五天:給1/7的 ;第六天:給2/7的,收回1/7的;第七天發(fā)1/7。
5. iOS中socket使用
Socket是對TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個調(diào)用接口(API),通過Socket,我們才能使用TCP/IP協(xié)議。
-
http協(xié)議:對應于應用層
-
tcp協(xié)議:對應于傳輸層
-
ip協(xié)議:對應于網(wǎng)絡(luò)層
三者本質(zhì)上沒有可比性。 何況HTTP協(xié)議是基于TCP連接的。
TCP/IP是傳輸層協(xié)議,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸;而HTTP是應用層協(xié)議,主要解決如何包裝數(shù)據(jù)。
我 們在傳輸數(shù)據(jù)時,可以只使用傳輸層(TCP/IP),但是那樣的話,由于沒有應用層,便無法識別數(shù)據(jù)內(nèi)容,如果想要使傳輸?shù)臄?shù)據(jù)有意義,則必須使用應用層 協(xié)議,應用層協(xié)議很多,有HTTP、FTP、TELNET等等,也可以自己定義應用層協(xié)議。WEB使用HTTP作傳輸層協(xié)議,以封裝HTTP文本信息,然 后使用TCP/IP做傳輸層協(xié)議將它發(fā)送到網(wǎng)絡(luò)上。
SOCKET原理
1、套接字(socket)概念
套接字(socket)是通信的基石,是支持TCP/IP協(xié)議的網(wǎng)絡(luò)通信的基本操作單元。它是網(wǎng)絡(luò)通信過程中端點的抽象表示,包含進行網(wǎng)絡(luò)通信必須的五種信息:連接使用的協(xié)議,本地主機的IP地址,本地進程的協(xié)議端口,遠地主機的IP地址,遠地進程的協(xié)議端口。
應 用層通過傳輸層進行數(shù)據(jù)通信時,TCP會遇到同時為多個應用程序進程提供并發(fā)服務(wù)的問題。多個TCP連接或多個應用程序進程可能需要通過同一個 TCP協(xié)議端口傳輸數(shù)據(jù)。為了區(qū)別不同的應用程序進程和連接,許多計算機操作系統(tǒng)為應用程序與TCP/IP協(xié)議交互提供了套接字(Socket)接口。應 用層可以和傳輸層通過Socket接口,區(qū)分來自不同應用程序進程或網(wǎng)絡(luò)連接的通信,實現(xiàn)數(shù)據(jù)傳輸?shù)牟l(fā)服務(wù)。
2、建立socket連接
建立Socket連接至少需要一對套接字,其中一個運行于客戶端,稱為ClientSocket,另一個運行于服務(wù)器端,稱為ServerSocket。
套接字之間的連接過程分為三個步驟:服務(wù)器監(jiān)聽,客戶端請求,連接確認。
服務(wù)器監(jiān)聽:服務(wù)器端套接字并不定位具體的客戶端套接字,而是處于等待連接的狀態(tài),實時監(jiān)控網(wǎng)絡(luò)狀態(tài),等待客戶端的連接請求。
客戶端請求:指客戶端的套接字提出連接請求,要連接的目標是服務(wù)器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務(wù)器的套接字,指出服務(wù)器端套接字的地址和端口號,然后就向服務(wù)器端套接字提出連接請求。
連 接確認:當服務(wù)器端套接字監(jiān)聽到或者說接收到客戶端套接字的連接請求時,就響應客戶端套接字的請求,建立一個新的線程,把服務(wù)器端套接字的描述發(fā)給客戶 端,一旦客戶端確認了此描述,雙方就正式建立連接。而服務(wù)器端套接字繼續(xù)處于監(jiān)聽狀態(tài),繼續(xù)接收其他客戶端套接字的連接請求。
3、SOCKET連接與TCP連接
創(chuàng)建Socket連接時,可以指定使用的傳輸層協(xié)議,Socket可以支持不同的傳輸層協(xié)議(TCP或UDP),當使用TCP協(xié)議進行連接時,該Socket連接就是一個TCP連接。
4、Socket連接與HTTP連接
由 于通常情況下Socket連接就是TCP連接,因此Socket連接一旦建立,通信雙方即可開始相互發(fā)送數(shù)據(jù)內(nèi)容,直到雙方連接斷開。但在實際網(wǎng)絡(luò)應用 中,客戶端到服務(wù)器之間的通信往往需要穿越多個中間節(jié)點,例如路由器、網(wǎng)關(guān)、防火墻等,大部分防火墻默認會關(guān)閉長時間處于非活躍狀態(tài)的連接而導致 Socket 連接斷連,因此需要通過輪詢告訴網(wǎng)絡(luò),該連接處于活躍狀態(tài)。
而HTTP連接使用的是“請求—響應”的方式,不僅在請求時需要先建立連接,而且需要客戶端向服務(wù)器發(fā)出請求后,服務(wù)器端才能回復數(shù)據(jù)。
很 多情況下,需要服務(wù)器端主動向客戶端推送數(shù)據(jù),保持客戶端與服務(wù)器數(shù)據(jù)的實時與同步。此時若雙方建立的是Socket連接,服務(wù)器就可以直接將數(shù)據(jù)傳送給 客戶端;若雙方建立的是HTTP連接,則服務(wù)器需要等到客戶端發(fā)送一次請求后才能將數(shù)據(jù)傳回給客戶端,因此,客戶端定時向服務(wù)器端發(fā)送連接請求,不僅可以 保持在線,同時也是在“詢問”服務(wù)器是否有新的數(shù)據(jù),如果有就將數(shù)據(jù)傳給客戶端。
6. 網(wǎng)絡(luò)請求中post和get的區(qū)別
GET是用于獲取數(shù)據(jù)的,POST一般用于將數(shù)據(jù)發(fā)給服務(wù)器之用。
普遍答案
1.GET使用URL或Cookie傳參。而POST將數(shù)據(jù)放在BODY中。
2.GET的URL會有長度上的限制,則POST的數(shù)據(jù)則可以非常大。
3.POST比GET安全,因為數(shù)據(jù)在地址欄上不可見。
不過也有文章說其實上面的是錯誤的,具體參考這篇文章。
7. 時間復雜度和空間復雜度
由于打不出數(shù)字符號,只能貼圖了。
時間復雜度
求時間復雜度
【1】如果算法的執(zhí)行時間不隨著問題規(guī)模n的增加而增長,即使算法中有上千條語句,其執(zhí)行時間也不過是一個較大的常數(shù)。此類算法的時間復雜度是O(1)。
x=91;?y=100;while(y>0)?if(x>100)?{x=x-10;y--;}?else?x++;解答:?T(n)=O(1)這段程序的運行是和n無關(guān)的,就算它再循環(huán)一萬年,我們也不管他,只是一個常數(shù)階的函數(shù)。
【2】當有若干個循環(huán)語句時,算法的時間復雜度是由嵌套層數(shù)最多的循環(huán)語句中最內(nèi)層語句的頻度f(n)決定的。
?x=1;? for(i=1;i<=n;i++)?for(j=1;j<=i;j++)for(k=1;k<=j;k++)x++;該程序段中頻度最大的語句是(5),內(nèi)循環(huán)的執(zhí)行次數(shù)雖然與問題規(guī)模n沒有直接關(guān)系,但是卻與外層循環(huán)的變量取值有關(guān),而最外層循環(huán)的次數(shù)直接與n有關(guān),因此可以從內(nèi)層循環(huán)向外層分析語句(5)的執(zhí)行次數(shù): 則該程序段的時間復雜度為
【3】算法的時間復雜度不僅僅依賴于問題的規(guī)模,還與輸入實例的初始狀態(tài)有關(guān)。
在數(shù)值A(chǔ)[0..n-1]中查找給定值K的算法大致如下:
i=n-1;???????????? while(i>=0&&(A[i]!=k))???????i--;???????? return?i;此算法中的語句(3)的頻度不僅與問題規(guī)模n有關(guān),還與輸入實例中A的各元素取值及K的取值有關(guān): ①若A中沒有與K相等的元素,則語句(3)的頻度f(n)=n; ②若A的最后一個元素等于K,則語句(3)的頻度f(n)是常數(shù)0。
空間復雜度
一個程序的空間復雜度是指運行完一個程序所需內(nèi)存的大小。利用程序的空間復雜度,可以對程序的運行所需要的內(nèi)存多少有個預先估計。一個程序執(zhí)行時除了需要存儲空間和存儲本身所使用的指令、常數(shù)、變量和輸入數(shù)據(jù)外,還需要一些對數(shù)據(jù)進行操作的工作單元和存儲一些為現(xiàn)實計算所需信息的輔助空間。程序執(zhí)行時所需存儲空間包括以下兩部分。
(1)固定部分。這部分空間的大小與輸入/輸出的數(shù)據(jù)的個數(shù)多少、數(shù)值無關(guān)。主要包括指令空間(即代碼空間)、數(shù)據(jù)空間(常量、簡單變量)等所占的空間。這部分屬于靜態(tài)空間。
(2)可變空間,這部分空間的主要包括動態(tài)分配的空間,以及遞歸棧所需的空間等。這部分的空間大小與算法有關(guān)。
一個算法所需的存儲空間用f(n)表示。S(n)=O(f(n)) 其中n為問題的規(guī)模,S(n)表示空間復雜度。
8. 支付寶SDK使用
使用支付寶進行一個完整的支付功能,大致有以下步驟:向支付寶申請, 與支付寶簽約,獲得商戶ID(partner)和賬號ID(seller)和私鑰(privateKey)。下載支付寶SDK,生成訂單信息,簽名加密調(diào)用支付寶客戶端,由支付寶客戶端跟支付寶安全服務(wù)器打交道。支付完畢后,支付寶客戶端會自動跳回到原來的應用程序,在原來的應用程序中顯示支付結(jié)果給用戶看。
集成之后可能遇到的問題
1)集成SDK編譯時找不到 openssl/asn1.h 文件
解決方案:Build Settings --> Search Paths --> Header Search paths : $(SRCROOT)/支付寶集成/Classes/Alipay
2)鏈接時:找不到 SystemConfiguration.framework 這個庫
解決方案:
打開支付寶客戶端進行支付(用戶沒有安裝支付寶客戶端,直接在應用程序中添加一個WebView,通過網(wǎng)頁讓用戶進行支付)
//?注意:如果是通過網(wǎng)頁支付完成,那么會回調(diào)該block:callback [[AlipaySDK?defaultService]?payOrder:orderString?fromScheme:@"jingdong"?callback:^(NSDictionary?*resultDic)?{?}];在AppDelegate.m
//?當通過別的應用程序,將該應用程序打開時,會調(diào)用該方法 -?(BOOL)application:(UIApplication?*)app?openURL:(NSURL?*)url?options:(NSDictionary?*)options{?//?當用戶通過支付寶客戶端進行支付時,會回調(diào)該block:standbyCallback? [[AlipaySDK?defaultService]?processOrderWithPaymentResult:url?standbyCallback:^(NSDictionary?*resultDic)?{?NSLog(@"result?=?%@",resultDic);?}];?return?YES;}9. 遠程推送
當服務(wù)端遠程向APNS推送至一臺離線的設(shè)備時,蘋果服務(wù)器Qos組件會自動保留一份最新的通知,等設(shè)備上線后,Qos將把推送發(fā)送到目標設(shè)備上。
遠程推送的基本過程:
1.客戶端的app需要將用戶的UDID和app的bundleID發(fā)送給apns服務(wù)器,進行注冊,apns將加密后的device Token返回給app
2.app獲得device Token后,上傳到公司服務(wù)器
3.當需要推送通知時,公司服務(wù)器會將推送內(nèi)容和device Token一起發(fā)給apns服務(wù)器
4.apns再將推送內(nèi)容送到客戶端上
創(chuàng)建證書的流程:
1.打開鑰匙串,生成CertificateSigningRequest.certSigningRequest文件
2.將CertificateSigningRequest.certSigningRequest上傳進developer,導出.cer文件
3.利用CSR導出P12文件
4.需要準備下設(shè)備token值(無空格)
5.使用OpenSSL合成服務(wù)器所使用的推送證書
本地app代碼參考
1.注冊遠程通知
-?(BOOL)application:(UIApplication?*)application?didFinishLaunchingWithOptions:(NSDictionary?*)launchOptions//中注冊遠程通知 {[[UIApplication?sharedApplication]?registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert?|?UIRemoteNotificationTypeBadge?|?UIRemoteNotificationTypeSound)]; }2,實現(xiàn)幾個代理方法:
//獲取deviceToken令牌?? -(void)application:(UIApplication?*)application?didRegisterForRemoteNotificationsWithDeviceToken:(NSData?*)deviceToken?? {??//獲取設(shè)備的deviceToken唯一編號??NSLog(@"deviceToken=%@",deviceToken);??NSString?*realDeviceToken=[NSString?stringWithFormat:@"%@",deviceToken];??//去除<>??realDeviceToken?=?[realDeviceToken?stringByReplacingOccurrencesOfString:@"<"?withString:@""];??realDeviceToken?=?[realDeviceToken?stringByReplacingOccurrencesOfString:@">"?withString:@""];??NSLog(@"realDeviceToken=%@",realDeviceToken);??[[NSUserDefaults?standardUserDefaults]?setValue:realDeviceToken?forKey:@"DeviceToken"];??//要發(fā)送給服務(wù)器 }??//獲取令牌出錯?? -(void)application:(UIApplication?*)application?didFailToRegisterForRemoteNotificationsWithError:(NSError?*)error?? {??//注冊遠程通知設(shè)備出錯??NSLog(@"RegisterForRemoteNotification?error=%@",error);?? }?? //在應用在前臺時受到消息調(diào)用?? -(void)application:(UIApplication?*)application?didReceiveRemoteNotification:(NSDictionary?*)userInfo?? {??//打印推送的消息??NSLog(@"%@",[[userInfo?objectForKey:@"aps"]?objectForKey:@"alert"]):?? }配置后臺模式
一般我們是使用開發(fā)版本的Provisioning做推送測試,如果沒有問題,再使用發(fā)布版本證書的時候一般也應該是沒有問題的。為了以防萬一,我們可以在越獄的手機上安裝我們的使用發(fā)布版證書的ipa文件(最好使用debug版本,并打印出獲取到的deviceToken),安裝成功后在;XCode->Window->Organizer-找到對應的設(shè)備查看console找到打印的deviceToken。
在后臺的推送程序中使用發(fā)布版制作的證書并使用該deviceToken做推送服務(wù).
使用開發(fā)和發(fā)布證書獲取到的deviceToken是不一樣的。
10. @protocol 和 category 中如何使用 @property
1)在protocol中使用property只會生成setter和getter方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對象能實現(xiàn)該屬性
2)category 使用 @property 也是只會生成setter和getter方法的聲明,如果我們真的需要給category增加屬性的實現(xiàn),需要借助于運行時的兩個函數(shù):
①objc_setAssociatedObject ②objc_getAssociatedObject總結(jié)
以上是生活随笔為你收集整理的那些著名或非著名的iOS面试题(中)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小学英语教学c语言,小学英语老师常用的课
- 下一篇: 收藏的JAVA面试题大全