iOS常見基礎面試題(附參考答案)

趁着開年的空閒時間,找了一些面試題寫寫, 水平渣,僅做參考!,歡迎指導討論,寫的不對的地方望及時提出! 原題在這裏html

中級篇請看這裏: iOS常見面試題(block,runtime,runloop,類結構)附參考答案ios

基礎部分

1.爲何說OC是一門動態的語言?

  • 動態和靜態是相對的,OC經過runtime運行時機制能夠作到純靜態語言作不到的事情:例如動態地增長、刪除、替換ivar或者方法等
  • Objective-C 使用的是「消息結構」並不是「函數調用」:使用消息結構的的語言,其運行時所應執行的代碼由運行期決定;而使用函數調用的語言,則由編譯器決定

2.講一下MVC和MVVM,MVP?

  • MVC
    • M:業務數據, V:視圖,負責展現 C:控制器,負責協調M、V
    • C做爲M和V之間的鏈接, 負責響應視圖事件,界面的跳轉,view的聲明週期,獲取業務數據, 而後將處理後的數據輸出到界面上作相應展現, 在數據有更新時, C須要及時提交相應更新到界面展現。View和Model之間沒有直接的聯繫,AppleMVC規範,理想的模型圖以下:
    • 在實際開發中,Model每每只有輕量級的數據,甚至.m中沒有任何實現,View和Controller成對出現,致使Controller中,愈來愈多的屬性、協議、網絡數據處理等,View和Controller牢牢耦合在一塊兒:
  • MVP
    • M:業務數據, V:視圖, P:協調器,業務處理層
    • P:業務邏輯的處理者,做爲M、V的橋樑。當獲取到數據後進行相應處理, 處理完成後會通知綁定的View數據有更新,View收到更新通知後從P獲取格式化好的數據進行頁面渲染。相比較MVC,MVP把業務邏輯和View的展現分離開:
  • MVVM

3.爲何代理要用weak?代理的delegate和dataSource有什麼區別?block和代理的區別?

  • 避免循環引用,weak表示該對象並不持有該delegate對象,delegate對象的銷燬由外部控制;若是用strong則該對象強引用delegate,外界不能銷燬delegate對象,會致使循環引用(Retain Cycles)
  • delegate是委託的意思,在OC中表示一個類委託另外一個類實現某個方法。當一個對象接受到某個事件或者通知的時候,會向它的delegate對象查詢它是否可以響應這個事件或者通知,若是能夠這個對象就會給它的delegate對象發送一個消息(執行一個方法調用)。 datasource字面是數據源,通常和delegate伴生,這時數據源處理的數據就是delegate中發送委託的類中的數據,並經過datasource發送給接受委託的類。 Instead of being delegated control of the user interface, a data source is delegated control of data.官網上這句話解釋的比較好,咱們能夠發現,delegate控制的是UI,是上層的東西;而datasource控制的是數據。他們本質都是回調,只是回調的對象不一樣。官網原文
  • delegateblock均可以實現回調傳值。block寫法簡練,能夠直接訪問上下文,代碼閱讀性好,適合與狀態無關的操做,更加面向結果,使用過程當中須要注意避免形成循環引用。delegate更像一個生產流水線,每一個回調方法是生產線上的一個處理步驟,一個回調的變更可能會引發另外一個回調的變更,其更加面向過程,當有多個相關方法時建議使用delegate

4.屬性的實質是什麼?包括哪幾個部分?屬性默認的關鍵字都有哪些?@dynamic關鍵字和@synthesize關鍵字是用來作什麼的?

  • 屬性@"property" = ivar + getter + setter
  • 原子性: nonatomicatomic
  • 讀寫特性: readwritereadonly
  • 內存管理特性: assign:修飾簡單數據類型。 weak:弱引用,多數用來修飾delegateoutletcopy:拷貝,多用於修飾NSStringblock等,其做爲屬性修飾符時是將_propertyrelease (_property release),而後拷貝參數內容(_property copy),建立一塊新的內存地址,最後_property = property。strong:強引用,其做爲屬性修飾符時是將_propertyrelease (_property release),而後將參數retain(_property retain),最後_property = propertyretain:MRC下特有,等同於strongunsafe_unretained:和weak 同樣,惟一的區別即是,對象即便被銷燬,指針也不會自動置空, 此時指針指向的是一個無用的野地址。若是使用此指針,程序會拋出 BAD_ACCESS 的異常。
  • @synthesize 讓編譯器自動生成getter/setter方法。當有自定義的存取方法時,會覆蓋該方法
  • @dynamic告訴編譯器,不自動生成getter/setter方法。由本身實現存取方法或存取方法在運行時動態建立綁定

5.屬性的默認關鍵字是什麼?

ARC下:面試

  • 基本數據類型默認關鍵字是 atomic,readwrite,assign
  • 其餘類型默認關鍵字是 atomic,readwrite,strong

MRC下:設計模式

  • 基本數據類型默認關鍵字是 atomic,readwrite,assign
  • 其餘類型默認關鍵字是 atomic,readwrite,retain

6.NSString爲何要用copy關鍵字,若是用strong會有什麼問題?(注意:這裏沒有說用strong就必定不行。使用copy和strong是看狀況而定的)

@interface Person : NSObject

@property(nonatomic ,copy)NSString *cpName;
@property(nonatomic ,strong)NSString *stName;

@end

@implementation Person
@end

main(){
    NSMutableString *string = [NSMutableString stringWithFormat:@"name"];
    
    Person *person = [[Person alloc]init];
    person.cpName = string;
    person.stName = string;
    
    [string appendString:@"name"];
    NSLog(@"cpName:%@ stName:%@",person.cpName,person.stName);
}
複製代碼
打印結果以下:
cpName:name stName:namename複製代碼

至於爲何要用copy, 大概是爲了防止mutableString被無心中修改。緩存

7.如何令本身所寫的對象具備拷貝功能?

  • 若想讓本身所寫的對象具備拷貝功能,則需實現 NSCopying 協議。若是自定義的對象分爲可變版本與不可變版本,那麼就要同時實現 NSCopyingNSMutableCopying 協議。
  • 要注意淺拷貝/深拷貝的不一樣。

8.可變集合類 和 不可變集合類的 copy 和 mutablecopy有什麼區別?若是是集合是內容複製的話,集合裏面的元素也是內容複製麼?

//不可變字符串
NSString *string = @"string";
NSString *cpString1 = [string copy];            //指針拷貝
NSString *mcpString1 = [string mutableCopy];    //內容拷貝,生成可變對象
NSMutableString *mstr = [string mutableCopy];   //同上
NSLog(@"%p %p %p %p",string,cpString1,mcpString1,mstr);
打印結果以下:
0x100001070 0x100001070 0x10051bbc0 0x100600e10

//可變字符串
NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"abcde"];
NSMutableString *mstr2 = [mstr1 copy];          //內容拷貝,生成不可變字符串
NSString *cpstring2 = [mstr1 copy];             //同上
NSMutableString *mstr3 = [mstr1 mutableCopy];   //內容拷貝
NSLog(@"%p %p %p %p",mstr1,mstr2, cpstring2,mstr3);
打印結果以下:
0x102063110 0x656463626155 0x656463626155 0x102063160複製代碼

NS* NSMutable*等集合類的copy、mutableCopy同上述同樣,須要注意的是,集合裏面的元素並無內容拷貝!若集合層級不少,且須要徹底內容拷貝,能夠利用NSKeyedArchiver實現。安全

9.爲何IBOutlet修飾的UIView也適用weak關鍵字?

  • 防止(Retain Cycles) 更新:感謝各位指出錯誤!網絡

  • 在storyboard或者xib中建立的UIView,自己會被它的superView強引用,以UILable爲例子:多線程

    UIViewController -> UIView -> subView -> UILable架構

    此時控件拖線會默認爲weak屬性,由於UIlable已經被UIView擁有,當UIViewController釋放的時候,UIView釋放,UILable才能夠釋放,因此正常狀況下UILable和UIView的生命週期是同樣的。設置成strong也沒什麼大問題, 可是當UILable從其父視圖UIView上remove掉,UIViewController對其還有一個strong強引用,UILable沒法釋放,這時就比較尷尬了...併發

10.nonatomic和atomic的區別?atomic是絕對的線程安全麼?爲何?若是不是,那應該如何實現?

  • nonatomic:表示非原子性,不安全,可是效率高。
  • atomic:表示原子性,安全,可是效率較低。
  • atomic:經過鎖定機制來確保其原子性,但只是讀/寫安全,不能絕對保證線程的安全,當多線程同時訪問的時候,會形成線程不安全。可使用線程鎖來保證線程的安全。

11.UICollectionView自定義layout如何實現?

  • UICollectionViewLayout是爲向UICollectionView提供佈局信息的類,包括cell的佈局信息等。
  • UICollectionView的自定義佈局能夠分爲三種方式:
    1. 初始化時傳入的UICollectionViewLayout對象,經過設置UICollectionViewLayout對象屬性的值能夠設置item的基本佈局,包括大小,間距等。
    2. 實現UICollectionViewLayoutDelegate協議對應的方法,返回佈局須要的值。
    3. 繼承UICollectionViewLayout類實現自定義的MyCollectionViewLayout,重寫相關方法返回自定義的佈局。

12.用StoryBoard開發界面有什麼弊端?如何避免?

  • 難以維護,難以定位問題。
  • ...

13.進程和線程的區別?同步異步的區別?並行和併發的區別?

  • 進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位
  • 進程中所包含的一個或多個執行單元稱爲線程thread
  • 同步:多個任務狀況下,一個任務A執行結束,才能夠執行另外一個任務B。
  • 異步:多個任務狀況下,一個任務A正在執行,同時能夠執行另外一個任務B。任務B不用等待任務A結束才執行。異步雖然具備開啓新線程的能力,可是並不必定開啓新線程,跟任務所指定的隊列類型有關。同步和異步的主要區別在於會不會阻塞當前線程
  • 並行:指兩個或多個事件在同一時刻發生。多核CUP同時開啓多條線程供多個任務同時執行,互不干擾。
  • 併發:指兩個或多個事件在同一時間間隔內發生。能夠在某條線程和其餘線程之間反覆屢次進行上下文切換,看上去就好像一個CPU可以而且執行多個線程同樣。實際上是僞異步。以下併發圖,在同一線程,任務A先執行了20%,而後A中止,任務B從新開始接管線程開始執行。
  • 併發的關鍵是你有處理多個任務的能力,不必定要同時。 並行的關鍵是你有同時處理多個任務的能力。

14.線程間通訊?

  • 在1個進程中,線程每每不是孤立存在的,多個線程之間須要常常進行通訊。能夠利用pthread,NSthread,GCD,NSOperation進行相關操做。如:
  • performSelector函數
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;複製代碼
  • GCD
dispatch_async(otherQueue, ^{
    // dosth
});
複製代碼
  • NSOperation
[otherQueue addOperationWithBlock:^{
    // dosth
}];複製代碼

15.GCD的一些經常使用的函數?(group,barrier,信號量,線程同步)

  • group : 當全部任務都執行完成以後,才執行dispatch_group_notify中的任務 dosthNotify。
- (void)gcdGroup{
    dispatch_group_t group =  dispatch_group_create();
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // dosth1;
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // dosth2;
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // dosthNotify;
    });
}複製代碼
  • barrier : 柵欄方法,當柵欄前一組操做執行完以後,才能開始執行後一組方法
- (void)barrier {
    dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        // dosth1;
    });
    dispatch_async(queue, ^{
        // dosth2;
    });
    dispatch_barrier_async(queue, ^{
        // doBarrier;
    });
    dispatch_async(queue, ^{
        // dosth4;
    });
    dispatch_async(queue, ^{
        // dosth5;
    });
}複製代碼
  • 信號量 : dispatch_semaphore
  • 主要做用:
    • 1.保持線程同步,將異步執行任務轉換爲同步執行任務
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
      dispatch_async(queue, ^{
          // dosth1
          // 使信號量+1並返回
          dispatch_semaphore_signal(semaphore);
      });
      // 若信號的信號量爲0,則會阻塞當前線程,直到信號量大於0或者通過輸入的時間值;若信號量大於0,則會使信號量減1並返回,程序繼續住下執行
      dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
      // dosth2 ,只有當dosth1執行完,信號量+1以後,纔會執行這裏
      複製代碼
    • 2.保證線程安全,爲線程加鎖:信號總量設爲 1 時也能夠看成鎖來用

16.如何使用隊列來避免資源搶奪?

  • 將須要訪問同一塊資源的任務添加到一個非異步並行隊列執行
  • 使用GCD的group,barrier,semaphore函數等
  • 線程加鎖,如 : @synchronized 關鍵字加鎖、NSLock 對象鎖、NSConditionLock條件鎖、NSRecursiveLock遞歸鎖、pthread_mutex 互斥鎖等。

17.數據持久化的幾個方案(fmdb用沒用過)

  • plist文件
  • preference偏好設置
  • NSKeyedArchiver
  • SQLite 3
  • CoreData
  • fmdb
  • realm

18.說一下AppDelegate的幾個方法?從後臺到前臺調用了哪些方法?第一次啓動調用了哪些方法?從前臺到後臺調用了哪些方法?

// 當應用程序啓動時(不包括已在後臺的狀況下轉到前臺),調用此回調。launchOptions是啓動參數,假如用戶經過點擊push通知啓動的應用,這個參數裏會存儲一些push通知的信息
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0);
– (void)applicationDidBecomeActive:(UIApplication *)application;

//應用即將從前臺狀態轉入後臺
- (void)applicationWillResignActive:(UIApplication *)application;
– (void)applicationDidEnterBackground:(UIApplication *)application NS_AVAILABLE_IOS(4_0);

//從後臺到前臺調用了:
– (void)applicationWillEnterForeground:(UIApplication *)application NS_AVAILABLE_IOS(4_0);
– (void)applicationDidBecomeActive:(UIApplication *)application;
複製代碼

App啓動過程以下:

19.NSCache優於NSDictionary的幾點?

  • NSCache線程安全,在多線程操做時,不須要手動加鎖
  • NSCache按照LRU規則,會對超出限制的數據進行自動清除,而且在系統發出低內存通知時,會自動刪減緩存
  • NSCache的Key只是對對象的strong引用,對象不須要實現NSCopying協議,NSCache也不會像NSDictionary同樣拷貝鍵。

20.知不知道Designated Initializer(指定初始化)?使用它的時候有什麼須要注意的問題?

  • 在OC中,對象的生成分爲兩步:內存分配,初始化實例變量
NSObject *object = [[NSObject alloc] init];複製代碼

類方法+ alloc,其根據要建立的實例對象對應的類來分配足夠的內存空間。除了分配內存空間,其實+ alloc方法還作了其餘事情,包括將對象的引用計數記爲1,將對象的isa指針指向對應的運行時類對象,以及將對象的成員變量置爲對應的0值(0、nil、NULL)。可是+ alloc方法返回的對象仍是不可用的,在以後完成初始化方法的調用後,對象的建立工做纔算完成。初始化方法會設置對象的成員變量爲一個正確的合理的值,以及獲取一些其餘額外的資源。

1.Designated Initializer 指定初始化方法

全部對象都是要初始化的,並且不少狀況下,對象在初始化時是須要接收額外的參數,這就可能會提供多個初始化方法。

- (instancetype)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTimeIntervalSinceNow:(NSTimeInterval)secs;
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)secs;
- (instancetype)initWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)date;複製代碼

根據規範,一般選擇一個接收參數最多的初始化方法做爲指定初始化方法,真正的數據分配和其餘相關初始化操做在這個方法中完成。而其餘的初始化方法則做爲便捷初始化方法去調用這個指定初始化方法。這樣當實現改變時,只要修改指定初始化方法就能夠了。便捷初始化方法接收的參數更少,它會在內部調用指定初始化方法時,直接設置未接收參數的默認值。便捷初始化方法也能夠不直接調用指定初始化方法,它能夠調用其餘便捷初始化方法,但無論調用幾層,最終是要調用到指定初始化方法的,由於真正的實現操做是在指定初始化方法中完成的。全部初始化方法統一以- init開始。如上例代碼所示,- initWithTimeIntervalSinceReferenceDate方法是一個指定初始化方法,而其餘初始化方法最終是要調用它的。

2.子類實現指定初始化方法

當子類繼承父類後實現了新的指定初始化方法,此時若是調用父類中的指定初始化方法則沒法調用到子類新實現的初始化邏輯,因此子類同時還要重寫父類的指定初始化方法,將其變爲一個便捷初始化方法,最終去調用子類本身的指定初始化方法。而爲了保證父類初始化邏輯的執行,在子類指定初始化方法中,首先要經過關鍵字super調用父類的指定初始化方法。 詳見正確編寫Designated Initializer的幾個原則

3.initWithCoder

若是父類也實現了協議,首先要調用父類的- initWithCoder:方法,若是父類沒有實現,則調用父類的指定初始化方法。

4.NS_DESIGNATED_INITIALIZER

當在接口中指定初始化方法的後面加上該宏,編譯器就會檢查咱們實現的初始化調用鏈是否符合規則,並提示相應的警告。

- (instancetype)init NS_DESIGNATED_INITIALIZER;複製代碼

21.實現description方法能取到什麼效果?

  • 當使用log打印該對象時,能夠詳細的知道該對象的信息,方便代碼調試。

22.objc使用什麼機制管理對象內存?

  • 1.MRC(MannulReference Counting)
  • 2.Xcode4.2+引入了ARC(Automatic Reference Counting)
  • 3.在ObjC中內存的管理是依賴對象引用計數器來進行的:在ObjC中每一個對象內部都有一個與之對應的整數(retainCount),叫「引用計數器」,當一個對象在建立以後它的引用計數器爲1,當調用這個對象的alloc、retain、new、copy、mutableCopy方法以後該對象retainCount+1(ObjC中調用一個對象的方法就是給這個對象發送一個消息),當調用這個對象的release方法以後它的引用計數器減1,若是一個對象的引用計數器爲0,則系統會自動調用這個對象的dealloc方法來銷燬這個對象。
  • 4.內存管理遵存這一規則:
    • 1.凡是用alloc,retain,new(或使用new開頭),copy(或使用copy開頭的方法),mutableCopy(或使用mutableCopy開頭的方法)「建立」對的對象都必須使用release或者autoRelease方法「釋放」。
    • 2.誰(在哪裏)建立誰釋放(哪一個類建立,哪一個類釋放;誰寫alloc,誰寫release)
  • 5.autorelease : 自動釋放。 當某對象調用autorelease方法後,在其所在的NSAutoreleasePool廢棄時,都將調用其release方法
  • 6.autoreleasePool : 自動釋放池。
相關文章
相關標籤/搜索