iOS面試題·自整理·Two

只燈片箋發表於2016-06-26

——青燈素箋

  • 多執行緒的底層實現

1.首先搞清楚是什麼執行緒、什麼是多執行緒
2.Mach是第一個以多執行緒方式處理任務的系統,因此多執行緒的底層實現機制是基於Mach的執行緒
3.開發中很少用Mach級的執行緒,因為Mach級的執行緒沒有提供多執行緒的基本特徵,執行緒之間是獨立的
4.開發中實現多執行緒的方案

* C語言的POSIX介面:#include <pthread.h>
* OC的NSThread
* C語言的GCD介面(效能最好,程式碼更精簡)
* OC的NSOperation和NSOperationQueue(基於GCD)

  • weak和assign的區別

weak:用於各種UI控制元件以及代理(PS:weak是在用Xib或者StoryBord拖拽的時候的預設屬性,在自己用程式碼流定義控制元件的時候,在把控不好的情況下,用strong即可)
assign:用於基本資料型別(PS:比如:NSInteger、long、int、float、double、BOOL)


  • Objective-C支援多繼承麼?

Objective-C不支援多繼承。可以通過遵循多個協議來實現多繼承。


  • #import “XXX.h”;和@class + 類名;的區別

1.#import會包含這個類的所有資訊,包括實體變數和方法;而@class只是告訴編譯器,其後面宣告的名稱是類的名稱。相當於,@class對當前類說:這些類是如何定義的,你暫時不用考慮知道,後面會再告訴你的。
2.在標頭檔案中,一般只需要知道被引用的類的名稱就可以了。不需要知道其內部的實體變數和方法具體是啥。所以,在X的標頭檔案(即X.h)中一般使用@class來宣告這個名稱是類的名稱。而在X的實現類(即X.m)裡面,因為會用到這個引用類的內部的實體變數和方法。所以需要使用#import來包含這個被引用類的標頭檔案。
3.從編譯效率方面考慮,如果你有100個標頭檔案都#import了同一個標頭檔案,或者這些標頭檔案是屬於依次引用的關係,例如:A—>B,B—>C,C—>D,D—>E,……,這樣的引用關係。當最開始的那個標頭檔案有變化的話,後面所有引用它的類都需要重新編譯,而此時恰好你的類很多很多的話,那將會耗費大量的時間。而,使用@class則不會。
4.如果有迴圈依賴關係(即相互引用關係),例如:A—>B,B—>A,這樣的相互依賴關係,此時再使用#import來相互包含,那麼就會出現編譯錯誤;如果使用@class在兩個類的標頭檔案(即X.h)中相互宣告,則不會出現編譯錯誤,然後再在兩個類的實現檔案(即X.m)中使用#import包含彼此的標頭檔案,就可以用彼此類內部的實體變數和方法了。
So,一般來說,@class是放在interface中的,只是為了在interface中引用這個類,把這個類作為一個型別來用的。在實現這個介面的實現類中,如果需要引用這個類的實體變數或者方法之類的,還是需要#import那個在@class中宣告的類,放在實現類中。


  • 系統中有哪些物件是單例?請寫個單例。

系統中的單例物件是:NSNotification、UIApplication、NSUserDefaults、NSFileManager、NSURLCache、AVAudioSession

*自己實現單例需要注意:
1.不使用GCD時(即不考慮多執行緒安全時):
// 單例模式實現要點:
// 1. 廢掉構造方法(呼叫的時候丟擲異常)
// 2. 提供一個類方法向外界返回該類的唯一例項
-(instancetype)init {
    @throw [NSException exceptionWithName:@"CDSingleton" reason:@"不允許呼叫構造方法" userInfo:nil];
    // return nil;
}
// 此方法由於沒有在.h檔案中暴露介面相當於是私有方法
-(instancetype) initPrivate {
    if(self = [super init]) {
        _value = arc4random();
    }
    return self;
}
+(instancetype) sharedInstance {
    // static型別的變數擁有全域性的生命週期
    static CDSingleton *instance = nil;
    // 使用同步塊保證在多執行緒環境下仍然是單例
    //同步加鎖,在多執行緒中使用,可以使執行緒安全
    @synchronized(self) {
        if(!instance) {
            instance = [[self alloc] initPrivate];
        }
    }
    return instance;
}
2.使用GCD時(即考慮執行緒安全時):
+(instancetype)sharedInstance{
    static HCDSingleton *singleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        singleton = [[HCDSingleton alloc]init];
    });
    return singleton;
}

  • 簡單講一下你對協議的理解。

舉個簡單的例子吧。

A需要某樣物品,但是A由於某些原因沒法兒得到該物品,A委託B幫忙弄來這樣物品,A制定一項協議,B願意遵循A做的協議中的規定,這樣B就可以提供給A其需要的那樣物品。協議中包含了遵循方B所需要實現的方法,以及B能做的事情。換句話理解就是,B必須提供出這樣的物品,而且,必須是合法途徑。


  • 如何理解ARC自動引用計數機制?

ARC的自動引用計數機制,並不是類似於Java中的垃圾回收機制。ARC的自動引用計數機制,只是使引用計數消失掉,而是為我們的程式碼自動加上ratain、release、autorelease語句。


  • 如何理解retain、copy、assign、release、autorelease、dealloc關鍵字?

retain:呼叫retain函式,會讓物件引用計數+1;
release:呼叫release函式,會讓物件引用計數-1;
delloc:當物件引用計數為0時,會自動呼叫delloc將物件進行釋放掉。即,物件在銷燬的時候自動呼叫該函式,禁止手動呼叫。
copy:當你不想讓A與B共享一塊記憶體的時候,讓A和B有各自的記憶體。
assign:在使用基本資料型別的時候,需要使用assign,assign會直接賦值,不會引起物件的引用計數+1。
autorelease:自動釋放、延遲釋放。寫了autorelease的物件指標,並不會立即釋放,只是把這個物件指標放入到最近的autoreleasepool中,等這個池子釋放的時候,會給池子中的所有物件指標傳送一條真正的release訊息,然後將它們release掉。


  • 請簡述self.name = XXX與_name = XXX的區別。

self.name實際上是呼叫了set方法給變數賦值。
_name是直接給變數賦值。


  • 請簡述類別和繼承有什麼聯絡和區別。

類別和繼承都會使用父類中的原有方法和屬性,類別是對父類進行擴充套件。繼承是講父類中的屬性、方法等保留下來,根據自己的實際需求狀況進行實現。
繼承可以增加、修改、刪除方法,還可以增加屬性。
類別、類目、類的擴充套件,即category,只能增加方法。但是,通過runtime可以實現動態的增加屬性。也即是成員變數。


  • 請簡述你對strong和weak關鍵字的理解。

strong:相當於retain,讓物件引用計數+1,防止物件在異常情況下被提前釋放,導致crash。
weak:弱引用,防止產生迴圈引用導致無法釋放物件和產生野指標。
strong,強引用,在ARC中使用strong告訴編譯器幫我們自動插入retain關鍵字。
weak,弱引用,是普通賦值,相當於MRC中的assign。


  • 如何實現ARC和MRC的混合程式設計?

工程名—->Targets—->build settings—->Apple LLVM 7.0 – Language – Modules—->Objective-C Automatic Reference Counting—->YESARC模式/NOMRC模式/-fno-objc-arc~ARC和MRC混編模式


  • Objective-C中變數預設是私有的嗎?方法預設是私有的嗎?

Objective-C中變數預設是私有的,即private;
方法預設是公有的,即public。


  • 請簡述頁面傳值都有哪些實現方式?

Block、代理、通知、單例、NSUserDefaults、屬性


  • 請簡述 深拷貝 和 淺拷貝的區別。

舉個例子①:

往簡單了來說:淺拷貝就好比物體A的影子,物體A拿走了,物體A的影子也就沒了;深拷貝就好比又拿來一個跟物體A一模一樣的物體B,就算物體A被拿走了,物體B仍然存在。

舉個例子②:

大家都用過Windows,這裡就舉Windows下資料夾的操作來說:
淺拷貝就類似於存在於D盤內的X資料夾,建立到桌面快捷方式,如果D盤內的X資料夾存在,就可以通過桌面建立的X資料夾快捷方式開啟;如果不存在,則通過桌面建立的X資料夾快捷方式也無法開啟;
深拷貝就類似於存在於D盤內的X資料夾,拷貝到桌面,就算 D盤裡的X資料夾刪除了,桌面拷貝的X資料夾依然可以開啟,而且內容一模一樣。

淺析原理:

深拷貝會重新再堆上開闢一塊記憶體空間,是一個全新的物件,指標地址和原來的不一樣。淺拷貝不會重新開闢一塊記憶體空間,指標和原來是一樣的。
深拷貝和淺拷貝的本質區別是:如果地址相同,就是淺拷貝;如果地址不同,就是深拷貝。
淺拷貝操作後,並沒有進行真正的複製,而是另一個指標也指向了同一個地址。深拷貝操作後,是真正的複製了一份,另一個指標指向了拷貝後的地址。

備註:

retain:始終是淺複製。引用計數每次+1.返回物件是否可變與被複制的物件保持一致。
copy:對於可變物件為深複製,引用計數不改變;對於不可變物件是淺複製,引用計數每次+1。無論被複制的物件是可變還是不可變,最終都返回一個不可變物件。
mutableCopy:始終是深複製,引用計數不改變。始終返回一個可變物件。
不可變物件:值發生改變,其記憶體首地址隨之改變。
可變物件:無論值是否改變,其記憶體首地址都不隨之改變。
引用計數:為了讓使用者清楚的知道,該物件有多少個擁有者(即有多少個指標指向統一記憶體地址)。


  • 請簡述對MVC設計模式的理解。

MVC:

Model:負責儲存、定義、運算元據;
View:負責呈現畫面以及與使用者進行操作互動
Controller:Model和View的協調者,Controller把Model中的資料拿過來給View用。
Controller可以直接與Model和View進行通訊,而View不能和Controller直接通訊。View與Controller通訊需要利用代理協議的方式,當有資料更新時,Model也要與Controller進行通訊,這個時候就要用Notification和KVO,這個方式就像廣播一樣,Model發訊號,Controller設定監聽接收訊號,當有資料更新時就發訊號給Controller,Model和View不能直接進行通訊,這樣會違背MVC設計模式。


  • iOS中哪些技術符合觀察者模式?

首先,先說明一下,什麼是觀察者模式。
觀察者模式,即Key-Value Observing,它提供一種機制,當指定的物件的屬性被修改後,則物件就會接收到通知。每次指定的被觀察的物件的屬性被修改後,KVO自動通知相應的觀察者。

iOS中,通知(即NSNotification)符合觀察者模式的一種。

  • 什麼是代理模式?實現代理需要注意什麼?

代理模式:作為被委託方,幫助別人(即,委託方)完成別人(即,委託方)委託你完成的事情。
你需要注意遵守別人(即,委託方)給你定的約定,和你是否擁有完成這件事的能力。


  • 請簡述StoryBord和Xib的聯絡和區別。簡述手動編寫程式碼。

StoryBord可以在上面實現整個專案介面的搭建,可以清楚得看到各個試圖控制器之間的關係;Xib實現自定義要素和良好部件重用性複雜的UI。
StoryBoard,方便整個專案介面的搭建。優點:可以看到介面效果,能同時進行多個介面的互動。缺點:不能進行介面的定製,缺少靈活性。
Xib,方便對介面進行編輯。可以在Xib上直接以托拉拽的方式新增各種檢視。優點:直接看到介面的效果,操作簡單。缺點:不方便對檢視進行動態控制,不靈活。
手動編寫程式碼,繼承(主要是UIView、UIViewController)。優點:可以對檢視進行定製,靈活控制方便。缺點:不能馬上看到效果、複雜。


  • 請簡述UITableview對Cell的重用機制。

比如一個螢幕可以放下5個UITableViewCell 總共會建立6個。
設定CELL的重用標誌符 一旦可以重用就重用 不能重用再建立,減少記憶體的消耗。

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *cellIdentifier = @"healthNewsTableViewCell";
    healthNewsTableViewCell *cell = [myTableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
    if (!cell) {
        cell = (healthNewsTableViewCell*)[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier: @"healthNewsTableViewCell"];
    }
    return cell;
}
//再將資料繫結寫在WillDisPlayCell中
//讓UITableView稍微順滑點的方法  在顯示cell前被呼叫
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
    healthNewsTableViewCell *MyCell = (healthNewsTableViewCell *)cell;
    MyCell.model = dataArray[indexPath.row];
    MyCell.backgroundColor = [UIColor colorWithRed:0.936 green:0.941 blue:0.936 alpha:1.000];
}

  • 如何使用UIStrollView實現無限載入多張圖片?

1.新增並設定定時器
2.設定定時器的呼叫方法
①. 獲取當前正在展示的位置
②. 計算出下一個需要展示的位置
③. 通過動畫滾動到下一個位置

注意點:需要進行判斷。
定時器的說明:

當使用者在處理其他事情的時候,定時器會停止工作。應該吧定時器新增到runloop中,告訴系統在處理其他事情的時候分一部分空間給它。
3.新增頁碼控制元件
4.監聽collectionView的滾動,當手動觸控CollectionView,嘗試拖拽的時候,把定時器停掉,當手指移開的時候,重啟定時器。


  • 請簡述檢視控制器的生命週期。

viewController的生命週期是:①—⑨。

①. initWithNib viewController會進行alloc,並init。
②. loadView 在這裡會看它的子類是否有重寫這個函式,如果重寫了則呼叫子類的,否則就呼叫它自己的。 注意:這個時候檢視還是沒有載入進來的。
③. viewDidLoad 這個時候檢視已經存在了。可以在這裡新增你想要新增的UI控制元件。
④. viewWillAppear 檢視將出現在螢幕上。
⑤. viewDidAppear 檢視已經成功在螢幕上渲染完成了。
⑥. viewWillDisappear 檢視將要消失了。
⑦. viewDidDisappear 檢視從螢幕上消失了。
⑧. viewDidUnLoad 當發生記憶體警告的時候,如果本檢視不是當前正在顯示的檢視,則會執行這個函式。將子檢視釋放。
⑨. dealloc 釋放viewController。

而,view的生命週期則是:③—⑧。

  • 請簡述iOS中的事件傳遞機制。(即iOS中的響應者鏈的工作原理)

每一個應用有一個響應者鏈,我們的檢視結構是一個N叉樹(一個檢視可以有多個子檢視,一個子檢視同一時刻只有一個父檢視),而每一個繼承UIResponder的物件都可以在這個N叉樹中扮演一個節點。
當葉節點成為最高響應者的時候,從這個葉節點開始往其父節點開始追溯出一條鏈,那麼對於這一個葉節點來講,這一條鏈就是當前響應者鏈。響應者鏈將系統捕獲到的UIEvent與UITouch從葉節點開始層層向下分發,期間可以選擇停止分發,也可以選擇繼續向下分發。


  • UITableView有哪些必須要實現的方法?

必須要實現的2個資料來源方法,分別是:

1.-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
//這個方法返回每個分段的行數,不同的分段返回不同的行數可以用switch來做,如果是單個列表就直接返回單個你想要的函式即可。
2.-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
//這個方法返回我們呼叫的每一個單元格。通過我們索引的路徑的section和row來確定。

  • 請簡述HTTP協議中get請求和post請求的區別。

get請求:引數在地址後拼接,沒有請求資料,不安全(因為所有引數都拼接在地址後面),不適合傳輸大量資料(長度限制,為1024個位元組)。get提交、請求的資料會附在URL之後,即把資料放置在HTTP協議頭中。以?分割URL和傳輸資料,多個引數用&連線。如果資料時英文字母或數字,原樣傳送,如果是空格,轉換為+,如果是中文/其他字元,則直接把字串用BASE64加密。
post請求:引數在請求資料區放著,相對get請求更安全,並且資料大小沒有限制。把提交的資料放置在HTTP包的包體中。
get提交的資料會在位址列顯示出來,而post提交,位址列不會改變。
傳輸資料的大小:
get請求時,傳輸資料就會受到URL長度限制,POST由於不是通過URL傳智,理論上不受限。
安全性:
post的安全性要比get的安全性高;
通過get提交資料,使用者名稱和密碼將明文出現在URL上,比如登入介面有可能被瀏覽器快取。


  • 請簡述你對同步/非同步請求資料的理解。

1.同步請求可以從網路請求資料,一旦傳送同步請求,程式將停止與使用者互動,直到伺服器返回資料完成,才可以進行下一步操作;
2.非同步請求不會阻塞主執行緒,而會建立一個新的執行緒來操作,使用者發出非同步請求後,依然可以對UI進行操作,程式可以繼續執行;


  • iOS中都有那些技術可以實現開闢執行緒?它們的聯絡和區別是什麼?

NSThread、GCD、NSOperation。

三者抽象封裝度層次從低到高,抽象封裝度越高使用越簡單。
NSThread:每個NSThread物件對應一個執行緒,量級較輕(真正的多執行緒)
以下倆是蘋果專門開發的“併發”技術,使得程式設計師可以不再去關心執行緒的具體使用問題
NSOperation/NSOperationQueue:物件導向的執行緒技術
GCD——Grand Central Dispatch(派發):是基於C語言的框架,可以充分利用多核,是蘋果推薦使用的多執行緒技術。

NSThread:

優點:比其他兩種輕量級。
缺點:需要自己管理執行緒的生命週期、執行緒同步。執行緒同步對資料的加鎖會有一定的開銷。

Operation、GCD:

優點:不需要關心執行緒管理,資料同步的事情。
兩者區別:NSOperationQueue可以方便的管理併發、NSOperation之間的優先順序。GCD主要與block結合使用。程式碼簡潔高效。
1.效能:GCD更接近底層,而NSOperationQueue則更高階抽象,所以GCD在追求效能的底層操作來說,是速度最快的。這取決於使用Instruments進行程式碼效能分析,如果有必要的話。
2.從非同步操作之間的事務性、順序性、依賴關係。GCD需要自己寫更多的程式碼來實現,而NSOperationQueue已經內建了這些支援。
3.如果非同步操作的過程需要更多地被互動和UI呈現出來,NSOperationQueue回事一個更好的選擇。底層程式碼中,任務之間不太互相依賴,而需要更高的併發能力,GCD則更有優勢。
三種多執行緒技術的對比:

NSThread:

-優點:NSThread比其他兩個輕量級,使用簡單
-缺點:需要自己管理執行緒的生命週期、執行緒同步、加鎖、睡眠以及喚醒等。執行緒同步對資料的加鎖會有一定的系統開銷。

NSOperation:

-不需要關心執行緒管理,資料同步的事情,可以把精力放在自己需要執行的操作上
-NSOperation是物件導向的

GCD:

-Grand Central Dispatch是由蘋果開發的一個多核程式設計的解決方案。iOS4.0+才能使用,是替代NSThread,NSOperation的高效和強大的技術
-GCD是基於C語言的。


  • NSThread中執行緒之間是如何實現通訊的?

執行緒間通訊:在1個程式中,執行緒往往不是孤立存在的,多個執行緒之間需要經常進行通訊。
執行緒間通訊的體現:1個執行緒傳遞資料給另1個執行緒。在1個執行緒中執行完特定任務後,轉到另1個執行緒執行任務。
執行緒間通訊常用方法:

1.-(void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
該方法一般用於執行緒間相互通訊,即在一個執行緒中傳送訊息給另一個執行緒。
2.-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
注:每一個執行緒都有自己的Runloop,但非主執行緒的Runloop預設是關閉的,當需要進行非主執行緒的通訊時,需要確保通訊執行緒的Runloop是開啟的,否則傳送給通訊執行緒的訊息就不會被執行。

  • GCD中有哪些建立執行緒的方式?

1.主執行緒佇列:主執行緒佇列,在該佇列中放置的所有任務都在主執行緒執行

dispatch_get_main_queue();

2.全域性並行佇列:在該佇列上提交的每個任務,都會生成一個執行緒,並行的執行(不會等到另一個執行完才執行)

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);

3.序列佇列:在該佇列上提交的任務,生成一個執行緒,在該執行緒上順序執行,一個執行完後一個才能執行

dispatch_queue_create(“”,DISPATCH_QUEUE_SERIAL);

  • iOS中有哪些技術可以保證執行緒安全?

執行緒鎖、NSLock


  • ASIHttpRequest的父類是什麼?

NSOperation


  • 請簡述AFNetwork的實現原理。

基於NSURL.採用block的方法處理請求,直接返回的是json、xml資料。AFNetwork直接操作物件是AFHTTPClient,是一個實現了NSCoding和NSCoping協議的NSObject子類。AFHTTPClient是一個封裝了一系列操作方法的工具類。AFNetWorking預設沒有封裝同步請求,如果開發者需要使用同步請求,需要重寫相關的方法getPath:parameters:failure,對AFHTTPRequestOperation進行同步處理。


  • 請簡述TCP和UDP的區別。

TCP為傳輸控制層協議,為面向連線、可靠的、點到點的通訊;
UDP為使用者資料包協議,非連線不可靠的點到多點的通訊;
TCP側重可靠傳輸,UDP側重快速傳輸。


  • 請簡述SDWebImage的實現原理。

呼叫類別的方法:

從記憶體中(字典)找圖片(當這個圖片在本次程式載入過),找到直接用;
從沙盒中找,找到直接使用,快取到記憶體。
從網路上獲取,使用,快取到記憶體,快取到沙盒。


  • 請簡述執行緒和程式有什麼聯絡和區別。

一個程式至少要有一個程式,一個程式至少要有一個執行緒。

程式:

資源分配的最小獨立單元,程式是具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程式是系統進行資源分配和排程的一個獨立單位。

執行緒:

程式下的一個分支,是程式的實體,是CPU排程和分派的基本單元,它是比程式更小的能獨立執行的基本單位,執行緒自己基本不擁有系統資源,只擁有一點在執行中必不可少的資源(程式計數器、一組暫存器、棧),但是它可與同屬一個程式的其他執行緒共享程式所擁有的全部資源。
程式和執行緒都是由作業系統所提供的程式執行的基本單元,系統利用該基本單元實現系統對應用的併發性。
程式和執行緒的主要差別在於它們是不同的作業系統資源管理方式。程式有獨立的地址空間,一個程式崩潰後,在保護模式下不會對其他程式產生影響,而執行緒只是一個程式中的不同執行路徑。執行緒有自己的堆疊和區域性變數,但執行緒之間沒有單獨的地址空間,一個執行緒死掉就等於整個程式死掉,所以多執行緒的程式要比多執行緒的程式健壯,但在程式切換時,耗費資源比較大,效率要差一些。
但對於一些要求同時進行並且又要共享某些變數的併發操作,只有用執行緒,不能用程式。


  • 請簡述什麼是主鍵?什麼是外來鍵?

主鍵是本張表的主鍵,是唯一且非空的,而外來鍵是另一張表中與這張表的某個欄位的型別、欄位名相同的欄位,一般是用作關聯兩張或者兩張以上的資料表時用的。

以下面三張表為例:

有三張表,一張表是讀者資訊,有一個屬性為readno;一張表是圖書的資訊,有一個屬性是bookno;一張表是借閱關係,有兩個屬性分別以讀者資訊表中的readno,和圖書資訊表中的bookno為外來鍵。那麼,在借閱關係表中插入資料時需要寫入readno和bookno麼?這樣,設外來鍵還有什麼作用?
外來鍵取值規則:空值或參照的主鍵值。
1.插入非空值時,如果主鍵表中沒有這個值,則不能插入。
2.更新時,不能改為主鍵表沒有的值。
3.刪除主鍵表記錄時,你可以在建外來鍵時選定外來鍵記錄一起級聯刪除還是拒絕刪除。
4.更新主鍵記錄時,同樣有級聯更新和拒絕執行的選擇。
簡言之:
起約束作用,就是在借閱關係表中只能插入讀者/圖書資訊表中存在的值,不然會出錯。
作用在於,如果你插入的readno或者bookno在兩個表中沒有,就會插不進去。


  • 請簡述iOS的沙盒機制。(或者說,你對沙盒的理解)

每個iOS應用都被限制在“沙盒”中,沙盒相當於一個加了僅主人可見許可權的資料夾,既是在應用程式安裝過程中,系統為每個單獨的應用程式生成它的主目錄和一些關鍵的子目錄。

蘋果對沙盒有幾條限制:

1.應用程式在自己的沙盒中運作,但是不能訪問任何其他應用程式沙盒;
2.應用之間不能共享資料,沙盒裡的檔案不能被複制到其他應用程式的資料夾中,也不能把其他應用資料夾複製到沙盒中;
3.蘋果禁止任何讀寫沙盒以外的檔案,禁止應用程式將內容寫到沙盒以外的資料夾中;
4.沙盒目錄裡面有三個資料夾:Documents——儲存;應用程式的資料檔案,儲存使用者資料或其他定期備份的資訊;Library下有兩個資料夾,Caches儲存應用程式再次啟動所需的資訊,Preferences包含應用程式的偏好設定;temp存放臨時檔案即應用程式再次啟動不需要的檔案。
獲取沙河根目錄的方法,有幾種方法:用NSHomeDirectory獲取。
獲取Document路徑:

NSSearchPathForDirectotiesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)

  • 如何實現真機除錯?

(Xcode 7.0之後可以不用配置開發者證照直接進行真機測試。)

1.首先需要用鑰匙串建立一個鑰匙(key);
2.將鑰匙串上傳到官網,獲取iOS Development證照;
3.建立App ID即我們應用程式中的Boundle ID;
4.新增Device ID即UDID;
5.通過勾選前面所建立的證照:Apple ID、Device ID;
6.生成mobileprovision檔案;
7.先決條件:申請開發者賬號99美刀。


  • 如何查詢專案中的記憶體洩漏?

使用記憶體分析工具:
一、靜態分析(不用執行程式時就能分析)

使用Analyze工具:在Xcode選單欄中,點選Product–>Alalyze之後,Xcode就會幫你編譯一次,並且找出你工程中有缺陷的程式碼,這個工具在當年非ARC的時候,非常火,只是現在的作用雞毛蒜皮了。分析記憶體洩漏shift+command+b。

二、動態分析(執行程式時分析)

靜態有時候不能把所有的記憶體洩漏檢查出來,有的記憶體洩漏是在執行時,使用者操作時才產生的。那就需要用到Instruments了。
Instruments工具操作流程:在Xcode選單欄中,點選Product–>Profile–>build成功後跳出Instruments工具–>選擇Leaks選項–>choose–>選擇要檢測的app–>點選紅色按鈕開始執行,進行檢查。
程式跑起來之後,可以開始各種點選除錯試用。
紅色的圓圈裡的菱形表示記憶體洩漏了。

如何通過Instruments這個工具看到在哪出現記憶體洩漏了?

現在工具欄按下暫停按鈕,把工具監視記憶體的活動停下來。
選擇Leak Checks,然後選擇Call Tree(Details後面的那個選項)
選中右邊欄,中間的按鈕,選中中間的兩項,然後會在中間的地方顯示記憶體洩漏的地方,雙擊就可以跳轉到對應的程式碼。最後解決記憶體洩漏問題。


  • 專案中的支付環節如何實現的?

1.先與支付寶簽約,獲得商戶ID(partner)和賬號(seller);
2.下載相應的公鑰私鑰檔案(加密簽名用);
3.下載支付寶SDK;
4.生成訂單資訊;
5.呼叫支付寶客戶端,由支付寶客戶端跟支付寶安全伺服器打交道;
6.支付完畢後返回支付結果給商戶客戶端和服務,SDK裡有整合支付寶功能的一個Demo,整合支付功能的具體操作方式,可以參考Demo。

//生成訂單資訊及簽名請求引數沒有return_URL這個引數,商戶可以根據自身情況選擇簽名方法
//點選獲取product例項,並初始化訂單資訊
//訂單ID
//商品標題
//商品描述
//商品價格
//回撥URL

  • 如何實現專案上線到AppStore?

1.登入應用釋出網站新增應用資訊;
2.下載安裝釋出證照;
3.選擇釋出證照,使用Archive編譯釋出包,用Xcode將程式碼(釋出包)上傳到伺服器;
4.等待稽核通過;
5.生成IPA:選單欄–>Product–>Archive。


  • 請簡述你在專案中遇到過哪些問題,如何解決的?

舉個當初自己在專案中解決介面問題的例子:

當時,拿著提供的介面,在瀏覽器中用JSON解析的工具看資料,沒有任何問題。但是,放到工程中解析,第一次執行,沒問題,是最新的資料。若是,稍等半天,再去重新整理,依舊是第一次執行時的資料。但是,瀏覽器開啟介面,卻是最新的資料。後來,無論是列印,還是打斷點,一直找不到問題所在。
我就嘗試開始從介面的拼接中找問題。後來發現拼接中的一個數字如果是不斷變化的話,就會顯示出最新的資料。然後,就在介面的拼接過程中,將那個固定數字修改為隨著點選而隨機產生的數字。剛開始以為,能解決問題,後來發現,重新整理到一定次數後,就會出現依舊還是舊資料的問題。只好再作調整。就給數字以逐漸累加的形式,來變化不同的數字。如此,做嘗試,卻發現,每次變化範圍太小,依舊會出現資料不更新的情況。後來,最終確定一個大範圍值,才解決了資料不更新的問題。


  • 如何實現流媒體格式的視訊邊播邊放邊快取?

視訊播放器處理流程:

1.當開始播放視訊時,通過視訊url判斷本地cache中是否已經快取當前視訊;如果有,則直接播放本地cache中視訊;
2.如果本地cache中沒有視訊,則視訊播放器向代理請求資料;
3.載入視訊時展示正在載入的提示(動畫:如旋轉的小菊花);
4.如果可以正常播放視訊,則去掉載入提示,播放視訊;如果載入失敗,去掉載入提示並顯示失敗提示;
5.在播放過程中如果由於網路國漫或拖拽原因導致沒有播放資料時,要展示載入提示,跳轉到第4步;

代理物件處理流程:

1.當視訊播放器向代理請求dataRequest時,判斷代理是否已經向伺服器發起了請求,如果沒有,則發起下載整個視訊檔案的請求;
2.如果代理已經和伺服器建立連線,則判斷當前的dataRequest請求的offset是否大於當前已經快取的檔案的offset;如果大於,則取消當前與伺服器的請求,並從offset開始到檔案尾向伺服器發起請求(此時應該是由於播放器向後拖拽,並且超過了已快取的資料時才會出現);
3.如果當前的dataRequest請求的offset小於已經快取的檔案的offset,同事大於代理向伺服器請求的range的offset,說明有一部分已經快取的資料可以傳給播放器,則將這部分資料返回給播放器(此時應該是由於播放器向前拖拽,請求的資料已經快取過才會出現);
4.如果當前的dataRequest請求的offset小於代理向伺服器請求的range的offset,則取消當前與伺服器的請求,並從offset開始到檔案尾向伺服器發起請求(此時應該是由於播放器向前拖拽,並且超過了已快取的資料時才會出現);
5.只要代理重新想伺服器發起請求,就會導致快取的資料不連續,則載入結束後不用將快取的資料放入到本地cache;
6.如果代理和伺服器的連結超時,重試一次。如果還是錯誤,則通知播放器網路錯誤;
7.如果伺服器返回其它錯誤,則代理通知播放器網路錯誤;


  • 請簡述xml和json資料各有哪些優勢?分析json、xml的區別。json、xml解析方式的底層是如何處理的?

json:鍵值對,資料小,不復雜,便於解析,有框架支援,適合輕量級傳輸,作為資料包個數傳輸的時候效率更高;
xml:標籤套內容,xml資料比較大,比較複雜,適合大資料量的傳輸,xml有豐富的編碼工具,比如:Dom4j,JDom.解析方式有兩種,一是通過文芳模型解析,另外一種遍歷節點。

區別:

(1)可讀性方面:基本相同,xml的可讀性比較好

(2)可擴充套件性方面:都具有很好的擴充套件性

(3)編碼難度方面:相對而言:JSON的編碼比較容易
(4)解碼難度:json的解碼難度基本為零,xml需要考慮子節點和父節點
(5)資料體積方面:json相對於xml來講,資料體積小,傳遞的速度跟快些
(6)資料互動方面:json與JavaScript的互動更加方面,更容易解析處理,更好的資料互動
(7)資料描述方面:xml對資料描述性比較好

(8)傳輸速度方面:json的速度遠遠快於xml

JSON底層原理:

遍歷字串中的字元,最終根據格式規定的特殊字元,比如{}號,[]號, : 號 等進行區分,{}號是一個字典 的開始,[]號是一個陣列的開始, : 號是字典的鍵和值的分水嶺,最終乃是將json資料轉化為字典,字典中值可能是字典,數 組,或字串而已。

XML底層原理:

XML解析常用的解析方法有兩種:DOM解析和SAX解析。DOM 採用建立樹形結構的方式訪問 XML 文件,而 SAX 採用的事件模型。 。DOM 解析把 XML 文件轉化為一個包含其內容的樹,並可以對樹進行遍歷。使用 DOM 解析器的時候需 要處理整個 XML 文件,所以對效能和記憶體的要求比較高。SAX在解析 XML 文件的時候可以觸發一系列的事件,當發現給定的tag 的時候,它可以啟用一個回撥方法,告訴該方法制定的標籤已經找到。SAX 對記憶體的要求通常會比較低,因為它讓開發人員自己來決 定所要處理的tag。特別是當開發人員只需要處理文件中所包含的部分資料時,SAX 這種擴充套件能力得到了更好的體現。

延伸:
SAX與DOM的區別:

1、SAX處理的優點非常類似於流媒體的優點。分析能夠立即開始,而不是等待所有的資料被處理。而且由於應用程式只是 在讀取資料時檢查資料,因此不需要將資料儲存在記憶體中。這對於大型文件來說是個巨大的優點。事實上,應用程式甚至不 必解析整個文件;它可以在某個條件得到 滿足時停止解析。一般來說,SAX 還比它的替代者 DOM 快許多。另一方面,由 於應用程式沒有以任何方式儲存資料,使用 SAX 來更改資料或在資料流中往後移是不可能的。

2、DOM 以及廣義的基於樹的處理具有幾個優點。首先,由於樹在記憶體中是持久的,因此可以修改它以便應用程式能對數 據和結構作出更改。它還可以在任何時候在樹中上下 導航,而不是像 SAX 那樣是一次性的處理。DOM 使用起來也要簡單 得多。另一方面,在記憶體中構造這樣的樹涉及大量的開銷。大型檔案完全佔用系統記憶體容量的情況並不鮮見。此外,建立一 棵 DOM 樹可能是一個緩慢的過程。

3、選擇 DOM 還是選擇 SAX,這取決於下面幾個因素:
應用程式的目的:如果打算對資料作出更改並將它輸出為 XML,那麼在大多數情況下,DOM 是適當的選擇。並不是說使 用 SAX 就不能更改資料,但是該過程要複雜得多,因為您必須對資料的一份拷貝而不是對資料本身作出更改。
資料容量: 對於大型檔案,SAX 是更好的選擇。資料將如何使用:如果只有資料中的少量部分會被使用,那麼使用 SAX 來將該部分資料提取到應用程式中可能更好。 另一方面,如果您知道自己以後會回頭引用已處理過的大量資訊,那麼 SAX 也許不是恰當的選擇。

對速度的需要:SAX 實現通常要比 DOM 實現更快。

SAX 和 DOM 不是相互排斥的,記住這點很重要。您可以使用 DOM 來建立 SAX 事件流,也可以使用 SAX 來建立 DOM 樹。事實上,用於建立 DOM 樹的大多數解析器實際上都使用 SAX 來完成這個任務。



相關文章