天天看點

iOS兩年前的面試題總結,現在的你掌握了嘛?

序言

這些面試題是兩年前的标準了,雖然跟現在的面試需求顯得相對簡單了點,但是也是可以幫着梳理一下基礎方面的知識的!

OC的了解與特性

  • OC作為一門面向對象的語言,自然具有面向對象的語言特性:封裝、繼承、多态。它既具有靜态語言的特性(如C++),又有動态語言的效率(動态綁定、動态加載等)。總體來講,OC确實是一門不錯的程式設計語言,
  • Objective-C具有相當多的動态特性,表現為三方面:動态類型(Dynamic typing)、動态綁定(Dynamic binding)和動态加載(Dynamic loading)。動态——必須到運作時(run time)才會做的一些事情。
  • 動态類型

    :即運作時再決定對象的類型,這種動态特性在日常的應用中非常常見,簡單來說就是id類型。事實上,由于靜态類型的固定性和可預知性,進而使用的更加廣泛。靜态類型是強類型,而動态類型屬于弱類型,運作時決定接受者。
  • 動态綁定

    :基于動态類型,在某個執行個體對象被确定後,其類型便被确定了,該對象對應的屬性和響應消息也被完全确定。
  • 動态加載

    :根據需求加載所需要的資源,最基本就是不同機型的适配,例如,在Retina裝置上加載@2x的圖檔,而在老一些的普通蘋裝置上加載原圖,讓程式在運作時添加代碼子產品以及其他資源,使用者可根據需要加載一些可執行代碼和資源,而不是在啟動時就加載所有元件,可執行代碼可以含有和程式運作時整合的新類。

簡述記憶體管理基本原則

  • 之前:OC記憶體管理遵循“誰建立,誰釋放,誰引用,誰管理”的機制,當建立或引用一個對象的時候,需要向她發送alloc、copy、retain消息,當釋放該對象時需要發送release消息,當對象引用計數為0時,系統将釋放該對象,這是OC的手動管理機制(MRC)。
  • 目前:iOS 5.0之後引用自動管理機制——自動引用計數(ARC),管理機制與手動機制一樣,隻是不再需要調用retain、release、autorelease;它編譯時的特性,當你使用ARC時,在适當位置插入release和autorelease;它引用strong和weak關鍵字,strong修飾的指針變量指向對象時,當指針指向新值或者指針不複存在,相關聯的對象就會自動釋放,而weak修飾的指針變量指向對象,當對象的擁有者指向新值或者不存在時weak修飾的指針會自動置為nil。
  • 如果使用

    alloc

    copy(mutableCopy)

    或者

    retian

    一個對象時,你就有義務,向它發送一條

    release

    autorelease

    消息。其他方法建立的對象,不需要由你來管理記憶體。
  • 向一個對象發送一條

    autorelease

    消息,這個對象并不會立即銷毀, 而是将這個對象放入了自動釋放池,待池子釋放時,它會向池中每一個對象發送 一條

    release

    消息,以此來釋放對象.
  • 向一個對象發送

    release

    消息,并不意味着這個對象被銷毀了,而是當這個對象的引用計數為0時,系統才會調用

    dealloc

    方法,釋放該對象和對象本身它所擁有的執行個體。

其他注意事項

  • 如果一個對象有一個_strong類型的指針指向着,找個對象就不會被釋放。如果一個指針指向超出了它的作用域,就會被指向nil。如果一個指針被指向nil,那麼它原來指向的對象就被釋放了。當一個視圖控制器被釋放時,它内部的全局指針會被指向nil。用法“:不管全局變量還是局部變量用_strong描述就行。
  • 局部變量:出了作用域,指針會被置為nil。
  • 方法内部建立對象,外部使用需要添加_autorelease;
  • 連線的時候,用_weak描述。
  • 代理使用unsafe_unretained就相當于assign;
  • block中為了避免循環引用問題,使用_weak描述;
  • 聲明屬性時,不要以

    new

    開頭。如果非要以

    new

    開頭命名屬性的名字,需要自己定制get方法名,如
    @property(getter=theString) NSString * newString;           
  • 如果要使用自動釋放池,用

    @autoreleasepool{}

  • ARC隻能管理Foundation架構的變量,如果程式中把Foundation中的變量強制換成COre Foundation中的變量需要交換管理權;
  • 在非ARC工程中采用ARC去編譯某些類:-fobjc-arc。
  • 在ARC下的工程采用非ARC去編譯某些類:-fno-fobjc-arc。

如何了解MVC設計模式

MVC是一種架構模式,M表示MOdel,V表示視圖View,C表示控制器Controller:

  • 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設計模式。

如何了解MVVM設計模式

  • ViewModel

    層,就是View和Model層的粘合劑,他是一個放置使用者輸入驗證邏輯,視圖顯示邏輯,發起網絡請求和其他各種各樣的代碼的極好的地方。說白了,就是把原來

    ViewController

    層的業務邏輯和頁面邏輯等剝離出來放到ViewModel層。
  • View層,就是ViewController層,他的任務就是從ViewModel層擷取資料,然後顯示。
  • 如需了解更多,請檢視 這篇文章

Objective-C 中是否支援垃圾回收機制?

  • OC是支援垃圾回收機制的(

    Garbage collection

    簡稱

    GC

    ),但是apple的移動終端中,是不支援GC的,Mac桌面系統開發中是支援的.
  • 移動終端開發是支援ARC(

    Automatic Reference Counting

    的簡稱),ARC是在IOS5之後推出的新技術,它與GC的機制是不同的。我們在編寫代碼時, 不需要向對象發送

    release

    autorelease

    方法,也不可以調用

    delloc

    方法,編譯器會在合适的位置自動給使用者生成

    release

    消息(

    autorelease

    ),ARC 的特點是自動引用技術簡化了記憶體管理的難度.

協定的基本概念和協定中方法預設為什麼類型

OC中的協定是一個方法清單,且多少有點相關。它的特點是可以被任何類使用(實作),但它并不是類(這裡我們需要注意),自身不會實作這樣方法, 而是又其他人來實作協定經常用來實作委托對象(委托設計模式)。如果一個類采用了一個協定,那麼它必須實作協定中必須需要實作的方法,在協定中的方法預設是必須實作(@required),添加關鍵字@optional,表明一旦采用該協定,這些“可選”的方法是可以選擇不實作的。

簡述類目

category

優點和缺點

優點:

  • 不需要通過增加子類而增加現有類的行為(方法),且類目中的方法與原始類方法基本沒有差別;
  • 通過類目可以将龐大一個類的方法進行劃分,進而便于代碼的日後的維護、更新以及提高代碼的閱讀性;

缺點:

  • 無法向類目添加執行個體變量,如果需要添加執行個體變量,隻能通過定義子類的方式;
  • 類目中的方法與原始類以及父類方法相比具有更高優先級,如果覆寫父類的方法,可能導緻

    super

    消息的斷裂。是以,最好不要覆寫原始類中的方法。

類别的作用

  • 給系統原有類添加方法,不能擴充屬性。如果類别中方法的名字跟系統的方法名一樣,在調用的時候類别中的方法優先級更高;
  • 分散類的實作:如:
    • (NSIndexPath *)indexPathForRow:(NSInteger)row

      inSection:(NSInteger)section

    原本屬于NSIndexPath的方法,但因為這個方法經常使用的表的時候調用、跟表的關系特别密切,是以把這個方法一類别的形式、聲明在UITableView.h中。
  • 聲明私有方法,某一個方法隻實作,不聲明,相當于私有方法。
  • 類别不能聲明變量,類别不可以直接添加屬性。

    property

    描述setter方法,就不會報錯。

循環引用的産生原因,以及解決方法

  • 産生原因:如下圖所示,對象A和對象B互相引用了對方作為自己的成員變量,隻有自己銷毀的時候才能将成員變量的引用計數減1。對象A的銷毀依賴于對象B的銷毀,同時對象B銷毀也依賴與對象A的銷毀,進而形成循環引用,此時,即使外界沒有任何指針通路它,它也無法釋放。

多個對象間依然會存在循環引用問題,形成一個環,在程式設計中,形成的環越大越不容易察覺,如下圖所示:

解決方法:

  • 事先知道存在循環引用的地方,在合理的位置主動斷開一個引用,是對象回收;
  • 使用 弱引用 的方法。

鍵路徑(keyPath)、鍵值編碼(KVC)、鍵值觀察(KVO)

鍵路徑
  • 在一個給定的實體中,同一個屬性的所有值具有相同的資料類型。
  • 鍵-值編碼技術用于進行這樣的查找—它是一種間接通路對象屬性的機制。 - 鍵路徑是一個由用點作分隔符的鍵組成的字元串,用于指定一個連接配接在一起的對象性質序列。第一個鍵的性質是由先前的性質決定的,接下來每個鍵的值也是相對于其前面的性質。
  • 鍵路徑使您可以以獨立于模型實作的方式指定相關對象的性質。通過鍵路徑,您可以指定對象圖中的一個任意深度的路徑,使其指向相關對象的特定屬性。
鍵值編碼KVC
  • 鍵值編碼是一種間接通路對象的屬性使用字元串來辨別屬性,而不是通過調用存取方法,直接或通過執行個體變量通路的機制,非對象類型的變量将被自動封裝或者解封成對象,很多情況下會簡化程式代碼;
  • KVC的缺點:一旦使用 KVC 你的編譯器無法檢查出錯誤,即不會對設定的鍵、鍵路徑進行錯誤檢查,且執行效率要低于合成存取器方法和自定的 setter 和 getter 方法。因為使用 KVC 鍵值編碼,它必須先解析字元串,然後在設定或者通路對象的執行個體變量。
鍵值觀察KVO
  • 鍵值觀察機制是一種能使得對象擷取到其他對象屬性變化的通知 ,極大的簡化了代碼。
  • 實作 KVO 鍵值觀察模式,被觀察的對象必須使用 KVC 鍵值編碼來修 改它的執行個體變量,這樣才能被觀察者觀察到。是以,KVC是KVO的基礎。
Demo

比如我自定義的一個button

[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil]; 
#pragma mark KVO 
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
     if ([keyPath isEqualToString:@"highlighted"] ) { 
      [self setNeedsDisplay]; 
} 
  } 
           

對于系統是根據keypath去取的到相應的值發生改變,理論上來說是和kvc機制的道理是一樣的。

KVC機制通過

key

找到

value

的原理
  • 當通過KVC調用對象時,比如:

    [self valueForKey:@”someKey”]

    時,程式會自動試圖通過下面幾種不同的方式解析這個調用。
  • 首先查找對象是否帶有

    someKey

    這個方法,如果沒找到,會繼續查找對象是否帶有

    someKey

    這個執行個體變量(

    iVar

    ),如果還沒有找到,程式會繼續試圖調用

    -(id) valueForUndefinedKey:

    這個方法。如果這個方法還是沒有被實作的話,程式會抛出一個

    NSUndefinedKeyException

    異常錯誤。
  • 補充:KVC查找方法的時候,不僅僅會查找someKey這個方法,還會查找getsomeKey這個方法,前面加一個get,或者_someKey以_getsomeKey這幾種形式。同時,查找執行個體變量的時候也會不僅僅查找someKey這個變量,也會查找_someKey這個變量是否存在。
  • 設計

    valueForUndefinedKey:

    方法的主要目的是當你使用

    -(id)valueForKey

    方法從對象中請求值時,對象能夠在錯誤發生前,有最後的機會響應這個請求。

在 Objective-C 中如何實作 KVO

  • 注冊觀察者(

    注意:觀察者和被觀察者不會被保留也不會被釋放

    )
    - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath 
    options:(NSKeyValueObservingOptions)options 
    context:(void *)context; 
               
  • 接收變更通知
    • (void)observeValueForKeyPath:(NSString *)keyPath

      ofObject:(id)object change:(NSDictionary )change context:(void )context;

  • 移除對象的觀察者身份
    • (void)removeObserver:(NSObject *)observer

      forKeyPath:(NSString *)keyPath;

  • KVO中

    誰要監聽誰注冊

    ,然後對響應進行處理,使得觀察者與被觀察者完全解耦。KVO隻檢測類中的屬性,并且屬性名都是通過NSString來查找,編譯器不會檢錯和補全,全部取決于自己。

代理的作用

  • 代理又叫委托,是一種設計模式,代理是對象與對象之間的通信互動,代了解除了對象之間的耦合性。
  • 改變或傳遞控制鍊。允許一個類在某些特定時刻通知到其他類,而不需要擷取到那些類的指針。可以減少架構複雜度。
  • 另外一點,代理可以了解為java中的回調監聽機制的一種類似。
  • 代理的屬性常是

    assign

    的原因:防止循環引用,以至對象無法得到正确的釋放。

NSNotification、Block、Delegate和KVO的差別

  • 代理是一種回調機制,且是一對一的關系,通知是一對多的關系,一個對向所有的觀察者提供變更通知;
  • 效率:Delegate比NSNOtification高;
  • Delegate和Block一般是一對一的通信;
  • Delegate需要定義協定方法,代理對象實作協定方法,并且需要建立代理關系才可以實作通信;
  • Block:Block更加簡潔,不需要定義繁瑣的協定方法,但通信事件比較多的話,建議使用Delegate;

Objective-C中可修改和不可以修改類型

  • 可修改不可修改的集合類,就是可動态添加修改和不可動态添加修改。
  • 比如

    NSArray

    NSMutableArray

    ,前者在初始化後的記憶體控件就是固定不可變的,後者可以添加等,可以動态申請新的記憶體空間

當我們調用一個靜态方法時,需要對對象進行 release 嗎?

  • 不需要,靜态方法(類方法)建立一個對象時,對象已被放入自動釋放池。在自動釋放池被釋放時,很有可能被銷毀。

當我們釋放我們的對象時,為什麼需要調用[super dealloc]方法,它的位置又是如何的呢?

  • 因為子類的某些執行個體是繼承自父類的,是以需要調用

    [super dealloc]

    方法, 來釋放父類擁有的執行個體,其實也就是子類本身的。一般來說我們優先釋放子類擁 有的執行個體,最後釋放父類所擁有的執行個體。

對謂詞的認識

  • Cocoa 中提供了一個

    NSPredicate

    的類,該類主要用于指定過濾器的條件, 每一個對象通過謂詞進行篩選,判斷條件是否比對。如果需要了解使用方法,請看 謂詞的具體使用

static、self、super關鍵字的作用

  • 函數體内

    static

    變量的作用範圍為該函數體,不同于

    auto

    變量,該變量的記憶體隻被配置設定一次,是以其值在下次調用時仍維持上次的值.
  • 在子產品内的

    static

    全局變量可以被子產品内所用函數通路,但不能被子產品外其它函數通路.
  • static

    函數隻可被這一子產品内的其它函數調用,這個函數的使用範圍被限制在聲明.
  • 在類中的

    static

    成員變量屬于整個類所擁有,對類的所有對象隻有一份拷貝.
  • self:目前消息的接收者。
  • super:向父類發送消息。

#include與#import的差別、#import 與@class 的差別

  • #include

    #import

    其效果相同,都是查詢類中定義的行為(方法);
  • #import

    不會引起交叉編譯,確定頭檔案隻會被導入一次;
  • @class

    的表明,隻定 義了類的名稱,而具體類的行為是未知的,一般用于.h 檔案;
  • @class

    #import

    編譯效率更高。
  • 此外

    @class

    #import

    的主要差別在于解決引用死鎖的問題。

@public、@protected、@private 它們的含義與作用

  • @public

    :對象的執行個體變量的作用域在任意地方都可以被通路 ;
  • @protected

    :對象的執行個體變量作用域在本類和子類都可以被通路 ;
  • @private

    :執行個體變量的作用域隻能在本類(自身)中通路 .

解釋 id 類型

任意類型對象,程式運作時才決定對象的類型。

switch 語句 if 語句差別與聯系

均表示條件的判斷,switch語句表達式隻能處理的是整型、字元型和枚舉類型,而選擇流程語句則沒有這樣的限制。但switch語句比選擇流程控制語句效率更高。

isMemberOfClass 和 isKindOfClass 聯系與差別

  • 聯系:兩者都能檢測一個對象是否是某個類的成員
  • 差別:

    isKindOfClass

    不僅用來确定一個對象是否是一個類的成員,也可以用來确定一個對象是否派生自該類的類的成員 ,而

    isMemberOfClass

    隻能做到第一點。
  • 舉例:如

    ClassA

    派 生 自

    NSObject

    類 ,

    ClassA *a = [ClassA alloc] init]

    ;,

    [a isKindOfClass:[NSObject class]]

    可以檢查出 a 是否是

    NSObject

    派生類 的成員,但

    isMemberOfClass

    做不到。

iOS 開發中資料持久性有哪幾種?

資料存儲的核心都是寫檔案。

  • 屬性清單:隻有NSString、NSArray、NSDictionary、NSData可writeToFile;存儲依舊是plist檔案。plist檔案可以存儲的7中資料類型:array、dictionary、string、bool、data、date、number。
  • 對象序列化(對象歸檔):對象序列化通過序列化的形式,鍵值關系存儲到本地,轉化成二進制流。通過runtime實作自動化歸檔/解檔,請參考 這個文章 。實作NSCoding協定必須實作的兩個方法:
    1.編碼(對象序列化):把不能直接存儲到plist檔案中得到資料,轉化為二進制資料,NSData,可以存儲到本地;
    2.解碼(對象反序列化):把二進制資料轉化為本來的類型。           
  • SQLite 資料庫:大量有規律的資料使用資料庫。
  • CoreData :通過管理對象進行增、删、查、改操作的。它不是一個資料庫,不僅可以使用SQLite資料庫來保持資料,也可以使用其他的方式來存儲資料。如:XML。

CoreData的介紹:

  • CoreData是面向對象的API,CoreData是iOS中非常重要的一項技術,幾乎在所有編寫的程式中,CoreData都作為資料存儲的基礎。
  • CoreData是蘋果官方提供的一套架構,用來解決與對象聲明周期管理、對象關系管理和持久化等方面相關的問題。
  • 大多數情況下,我們引用CoreData作為持久化資料的解決方案,并利用它作為持久化資料映射為記憶體對象。提供的是對象-關系映射功能,也就是說,CoreData可以将Objective-C對象轉換成資料,儲存到SQL中,然後将儲存後的資料還原成OC對象。

CoreData的特征:

  • 通過CoreData管理應用程式的資料模型,可以極大程度減少需要編寫的代碼數量。
  • 将對象資料存儲在SQLite資料庫已獲得性能優化。
  • 提供NSFetchResultsController類用于管理表視圖的資料,即将Core Data的持久化存儲在表視圖中,并對這些資料進行管理:增删查改。
  • 管理undo/redo操縱;
  • 檢查托管對象的屬性值是否正确。

Core Data的6成員對象

  • 1.NSManageObject:被管理的資料記錄Managed Object Model是描述應用程式的資料模型,這個模型包含實體(Entity)、特性(Property)、讀取請求(Fetch Request)等。
  • 2.NSManageObjectContext:管理對象上下文,持久性存儲模型對象,參與資料對象進行各種操作的全過程,并監測資料對象的變化,以提供對undo/redo的支援及更新綁定到資料的UI。
  • 3.NSPersistentStoreCoordinator:連接配接資料庫的Persistent Store Coordinator相當于資料檔案管理器,處理底層的對資料檔案的讀取和寫入,一般我們與這個沒有交集。
  • 4.NSManagedObjectModel:被管理的資料模型、資料結構。
  • 5.NSFetchRequest:資料請求;
  • 6.NSEntityDescription:表格實體結構,還需知道.xcdatamodel檔案編譯後為.momd或者.mom檔案。

Core Data的功能

  • 對于KVC和KVO完整且自動化的支援,除了為屬性整合KVO和KVC通路方法外,還整合了适當的集合通路方法來處理多值關系;
  • 自動驗證屬性(property)值;
  • 支援跟蹤修改和撤銷操作;
  • 關系維護,Core Data管理資料的關系傳播,包括維護對象間的一緻性;
  • 在記憶體上和界面上分組、過濾、組織資料;
  • 自動支援對象存儲在外部資料倉庫的功能;
  • 建立複雜請求:無需動手寫SQL語句,在擷取請求(fetch request)中關聯NSPredicate。NSPreadicate支援基本功能、相關子查詢和其他進階的SQL特性。它支援正确的Unicode編碼、區域感覺查詢、排序和正規表達式;
  • 延遲操作:Core Data使用 懶加載(lazy loading) 方式減少記憶體負載,還支援部分實體化延遲加載和複制對象的資料共享機制;
  • 合并政策:Core Data内置版本跟蹤和樂觀鎖(optimistic locking)來支援多使用者寫入沖突的解決,其中,樂觀鎖就是對資料沖突進行檢測,若沖突就傳回沖突的資訊;
  • 資料遷移:Core Data的Schema Migration工具可以簡化應對資料庫結構變化的任務,在某些情況允許你執行高效率的資料庫原地遷移工作;
  • 可選擇針對程式Controller層的內建,來支援UI的顯示同步Core Data在IPhone OS之上,提供NSFetchedResultsController對象來做相關工作,在Mac OS X上我們用Cocoa提供的綁定(Binding)機制來完成的。

對象可以被copy的條件

  • 隻有實作了

    NSCopying

    NSMutableCopying

    協定的類的對象才能被拷貝,分為不可變拷貝和可變拷貝, 具體差別戳這
  • NSCopying

    協定方法為:
    • (id)copyWithZone:(NSZone *)zone {

      MyObject *copy = [[[self class] allocWithZone: zone] init];

    copy.username = [self.username copyWithZone:zone];

    return copy;

    }

自動釋放池工作原理

  • 自動釋放池是

    NSAutorelease

    類的一個執行個體,當向一個對象發送

    autorelease

    消息時,該對象會自動入池,待池銷毀時,将會向池中所有對象發送一條

    release

    消息,釋放對象。
  • [pool release]、 [pool drain]

    表示的是池本身不會銷毀,而是池子中的臨時對象都被發送

    release

    ,進而将對象銷毀。

在某個方法中 self.name = _name,name = _name 它 們有差別嗎,為什麼?

  • 前者是存在記憶體管理的setter方法指派,它會對_name對象進行保留或者拷貝操作
  • 後者是普通指派
  • 一般來說,在對象的方法裡成員變量和方法都是可以通路的,我們通常會重寫Setter方法來執行某些額外的工作。比如說,外部傳一個模型過來,那麼我會直接重寫Setter方法,當模型傳過來時,也就是意味着資料發生了變化,那麼視圖也需要更新顯示,則在指派新模型的同時也去重新整理UI。

解釋self = [super init]方法

  • 容錯處理,當父類初始化失敗,會傳回一個nil,表示初始化失敗。由于繼承的關系,子類是需要擁有父類的執行個體和行為,是以,我們必須先初始化父類,然後再初始化子類

定義屬性時,什麼時候用 assign、retain、copy 以及它們的之間的差別

  • assign

    :普通指派,一般常用于基本資料類型,常見委托設計模式, 以此來防止循環引用。(我們稱之為弱引用).
  • retain

    :保留計數,獲得到了對象的所有權,引用計數在原有基礎上加1.
  • copy

    :一般認為,是在記憶體中重新開辟了一個新的記憶體空間,用來 存儲新的對象,和原來的對象是兩個不同的位址,引用計數分别為1。但是當

    copy

    對象為不可變對象時,那麼

    copy

    的作用相當于

    retain

    。因為,這樣可以節約記憶體空間

堆和棧的差別

  • 棧區(stack)

    由編譯器自動配置設定釋放 ,存放方法(函數)的參數值, 局部變量的值等,棧是向低位址擴充的資料結構,是一塊連續的記憶體的區域。即棧頂的位址和棧的最大容量是系統預先規定好的。
  • 堆區(heap)

    一般由程式員配置設定釋放, 若程式員不釋放,程式結束時由OS回收,向高位址擴充的資料結構,是不連續的記憶體區域,進而堆獲得的空間比較靈活。
  • 碎片問題

    :對于堆來講,頻繁的

    new/delete

    勢必會造成記憶體空間的不連續,進而造成大量的碎片,使程式效率降低。對于棧來講,則不會存在這個問題,因為棧是先進後出的隊列,他們是如此的一一對應,以至于永遠都不可能有一個記憶體塊從棧中間彈出.
  • 配置設定方式

    :堆都是動态配置設定的,沒有靜态配置設定的堆。棧有2種配置設定方式:靜态配置設定和動态配置設定。靜态配置設定是編譯器完成的,比如局部變量的配置設定。動态配置設定由alloca函數進行配置設定,但是棧的動态配置設定和堆是不同的,他的動态配置設定是由編譯器進行釋放,無需我們手工實作。
  • 配置設定效率

    :棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:配置設定專門的寄存器存放棧的位址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很複雜的。
  • 全局區(靜态區)(static)

    ,全局變量和靜态變量的存儲是放在一塊 的,初始化的全局變量和靜态變量在一塊區域, 未初始化的全局變量和未初始化的靜态變量在相鄰的另一塊區域。程式結束後有系統釋放。
  • 文字常量區

    —常量字元串就是放在這裡的。程式結束後由系統釋放。
  • 程式代碼區

    —存放函數體的二進制代碼

怎樣使用performSelector傳入3個以上參數,其中一個為結構體

  • 因為系統提供的

    performSelector

    的API中,并沒有提供三個參數。是以,我們隻能傳數組或者字典,但是數組或者字典隻有存入對象類型,而結構體并不是對象類型,我們隻能通過對象放入結構作為屬性來傳過去了.
    • (id)performSelector:(SEL)aSelector;
    • (id)performSelector:(SEL)aSelector withObject:(id)object;
    • (id)performSelector:(SEL)aSelector withObject:

      (id)object1 withObject:(id)object2;

  • 具體實作如下:

    typedef struct HYBStruct {

    int a;

    int b;

    } *my_struct;

    @interface HYBObject : NSObject
    
    @property (nonatomic, assign) my_struct arg3;
    @property (nonatomic, copy)  NSString *arg1;
    @property (nonatomic, copy) NSString *arg2;
    
    @end
    @implementation HYBObject
    
    // 在堆上配置設定的記憶體,我們要手動釋放掉
    - (void)dealloc {
    free(self.arg3);
    }
    
    @end
               
  • 測試:

    my_struct str = (my_struct)(malloc(sizeof(my_struct)));

    str->a = 1;

    str->b = 2;

    HYBObject *obj = [[HYBObject alloc] init];

    obj.arg1 = @"arg1";

    obj.arg2 = @"arg2";

    obj.arg3 = str;

    [self performSelector:@selector(call:) withObject:obj];

    // 在回調時得到正确的資料的

    • (void)call:(HYBObject *)obj {

      NSLog(@"%d %d", obj.arg3->a, obj.arg3->b);

UITableViewCell上有個UILabel,顯示NSTimer實作的秒表時間,手指滾動cell過程中,label是否重新整理,為什麼?

這是否重新整理取決于timer加入到Run Loop中的Mode是什麼。Mode主要是用來指定事件在運作循環中的優先級的,分為:

  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode)

    :預設,空閑狀态
  • UITrackingRunLoopMode

    :ScrollView滑動時會切換到該Mode
  • UIInitializationRunLoopMode

    :run loop啟動時,會切換到該mode
  • NSRunLoopCommonModes(kCFRunLoopCommonModes)

    :Mode集合
    蘋果公開提供的Mode有兩個:           
  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode)

  • NSRunLoopCommonModes(kCFRunLoopCommonModes)

  • 在程式設計中:如果我們把一個

    NSTimer

    對象以

    NSDefaultRunLoopMode(kCFRunLoopDefaultMode)

    添加到主運作循環中的時候, ScrollView滾動過程中會因為mode的切換,而導緻

    NSTimer

    将不再被排程。當我們滾動的時候,也希望不排程,那就應該使用預設模式。但是,如果希望在滾動時,定時器也要回調,那就應該使用common mode。

對于單元格重用的了解

  • 當螢幕上滑出螢幕時,系統會把這個單元格添加到重用隊列中,等待被重用,當有新單元從螢幕外滑入螢幕内時,從重用隊列中找看有沒有可以重用的單元格,若有,就直接用,沒有就重新建立一個。

解決cell重用的問題

  • UITableView通過重用單元格來達到節省記憶體的目的,通過為每個單元格指定一個重用标示(reuseidentifier),即指定了單元格的種類,以及當單元格滾出螢幕時,允許恢複單元格以便複用。對于不同種類的單元格使用不同的ID,對于簡單的表格,一個标示符就夠了。
  • 如一個TableView中有10個單元格,但螢幕最多顯示4個,實際上iPhone隻為其配置設定4個單元格的記憶體,沒有配置設定10個,當滾動單元格時,螢幕内顯示的單元格重複使用這4個記憶體。實際上配置設定的cell的個數為螢幕最大顯示數,當有新的cell進入螢幕時,會随機調用已經滾出螢幕的Cell所占的記憶體,這就是Cell的重用。
  • 對于多變的自定義Cell,這種重用機制會導緻内容出錯,為解決這種出錯的方法,把原來的
    UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:defineString]
    修改為:UITableViewCell *cell = [tableview cellForRowAtIndexPath:indexPath];
    這樣就解決掉cell重用機制導緻的問題。
               

有a、b、c、d 4個異步請求,如何判斷a、b、c、d都完成執行?如果需要a、b、c、d順序執行,該如何實作?

  • 對于這四個異步請求,要判斷都執行完成最簡單的方式就是通過GCD的group來實作:
    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, ^{ /*任務a */ });
    dispatch_group_async(group, queue, ^{ /*任務b */ });
    dispatch_group_async(group, queue, ^{ /*任務c */ });
    dispatch_group_async(group, queue, ^{ /*任務d */ });
    dispatch_group_notify(group,dispatch_get_main_queue(), ^{
    // 在a、b、c、d異步執行完成後,會回調這裡
    });           
  • 當然,我們還可以使用非常老套的方法來處理,通過四個變量來辨別a、b、c、d四個任務是否完成,然後在runloop中讓其等待,當完成時才退出runloop。但是這樣做會讓後面的代碼得不到執行,直到Run loop執行完畢。
  • 解釋:要求順序執行,那麼可以将任務放到串行隊列中,自然就是按順序來異步執行了。

使用block有什麼好處?使用NSTimer寫出一個使用block顯示(在UILabel上)秒表的代碼

  • 代碼緊湊,傳值、回調都很友善,省去了寫代理的很多代碼。
  • NSTimer封裝成的block, 具體實作
  • 實作方法:
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
    repeats:YES
    callback:^() {
    weakSelf.secondsLabel.text = ...
    }
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
               

一個view已經初始化完畢,view上面添加了n個button,除用view的tag之外,還可以采用什麼辦法來找到自己想要的button來修改button的值

有2種方法解決:

  • 第一種:如果是點選某個按鈕後,才會重新整理它的值,其它不用修改,那麼不用引用任何按鈕,直接在回調時,就已經将接收響應的按鈕給傳過來了,直接通過它修改即可。
  • 第二種:點選某個按鈕後,所有與之同類型的按鈕都要修改值,那麼可以通過在建立按鈕時将按鈕存入到數組中,在需要的時候周遊查找。

線程與程序的差別和聯系?

  • 一個程式至少要有進城,一個程序至少要有一個線程.
  • 程序:資源配置設定的最小獨立單元,程序是具有一定獨立功能的程式關于某個資料集合上的一次運作活動,程序是系統進行資源配置設定和排程的一個獨立機關.
  • 線程:程序下的一個分支,是程序的實體,是CPU排程和分派的基本單元,它是比程序更小的能獨立運作的基本機關,線程自己基本不擁有系統資源,隻擁有一點在運作中必不可少的資源(程式計數器、一組寄存器、棧),但是它可與同屬一個程序的其他線程共享程序所擁有的全部資源。
  • 程序和線程都是由作業系統所體會的程式運作的基本單元,系統利用該基本單元實作系統對應用的并發性。
  • 程序和線程的主要差别在于它們是不同的作業系統資源管理方式。程序有獨立的位址空間,一個程序崩潰後,在保護模式下不會對其它程序産生影響,而線程隻是一個程序中的不同執行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的位址空間,一個線程死掉就等于整個程序死掉,是以多程序的程式要比多線程的程式健壯,但在程序切換時,耗費資源較大,效率要差一些。
  • 但對于一些要求同時進行并且又要共享某些變量的并發操作,隻能用線程,不能用程序。

多線程程式設計

  • NSThread

    :當需要進行一些耗時操作時會把耗時的操作放到線程中。線程同步:多個線程同時通路一個資料會出問題,NSlock、線程同步塊、@synchronized(self){}。
  • NSOperationQueue操作隊列

    (不需考慮線程同步問題)。程式設計的重點都放在main裡面,

    NSInvocationOperation

    BSBlockOperation

    、自定義Operation。建立一個操作綁定相應的方法,當把操作添加到操作隊列中時,操作綁定的方法就會自動執行了,當把操作添加到操作隊列中時,預設會調用main方法。
  • GCD(

    `Grand Central Dispatch

    )宏大的中央排程,串行隊列、并發隊列、主線程隊列;
  • 同步和異步:同步指第一個任務不執行完,不會開始第二個,異步是不管第一個有沒有執行完,都開始第二個。
  • 串行和并行:串行是多個任務按一定順序執行,并行是多個任務同時執行;
  • 代碼是在分線程執行,在主線程嘟列中重新整理UI。

多線程程式設計是防止主線程堵塞、增加運作效率的最佳方法。

  • Apple提供了NSOperation這個類,提供了一個優秀的多線程程式設計方法;
  • 一個NSOperationQueue操作隊列,相當于一個線程管理器,而非一個線程,因為你可以設定這個線程管理器内可以并行運作的線程數量等。
  • 多線程是一個比較輕量級的方法來實作單個應用程式内多個代碼執行路徑。
  • iPhoneOS下的主線程的堆棧大小是1M。第二個線程開始就是512KB,并且該值不能通過編譯器開關或線程API函數來更改,隻有主線程有直接修改UI的能力。

定時器與線程的差別;

  • 定時器;可以執行多次,預設在主線程中。
  • 線程:隻能執行一次。

Apple裝置尺寸和程式設計尺寸

TCP和UDP的差別于聯系

  • TCP為傳輸控制層協定,為面向連接配接、可靠的、點到點的通信;
  • UDP為使用者資料報協定,非連接配接的不可靠的點到多點的通信;
  • TCP側重可靠傳輸,UDP側重快速傳輸。

TCP連接配接的三次握手

  • 第一次握手:用戶端發送syn包(syn=j)到伺服器,并進入SYN_SEND狀态,等待伺服器确認;
  • 第二次握手:伺服器收到syn包,必須确認客戶的SYN(ack=j+1),同時自己也發送一個SYN包,即SYN+ACK包,此時伺服器進入SYN+RECV狀态;
  • 第三次握手:用戶端收到伺服器的SYN+ACK包,向伺服器發送确認包ACK(ack=k+1),此發送完畢,用戶端和伺服器進入ESTABLISHED狀态,完成三次狀态。

Scoket連接配接和HTTP連接配接的差別:

  • HTTP協定是基于TCP連接配接的,是應用層協定,主要解決如何包裝資料。Socket是對TCP/IP協定的封裝,Socket本身并不是協定,而是一個調用接口(API),通過Socket,我們才能使用TCP/IP協定。
  • HTTP連接配接:短連接配接,用戶端向伺服器發送一次請求,伺服器響應後連接配接斷開,節省資源。伺服器不能主動給用戶端響應(除非采用HTTP長連接配接技術),iPhone主要使用類NSURLConnection。
  • Socket連接配接:長連接配接,用戶端跟伺服器端直接使用Socket進行連接配接,沒有規定連接配接後斷開,是以用戶端和伺服器段保持連接配接通道,雙方可以主動發送資料,一般多用于遊戲.Socket預設連接配接逾時時間是30秒,預設大小是8K(了解為一個資料包大小)。

HTTP協定的特點,關于HTTP請求GET和POST的差別

GET和POST的差別

  • HTTP超文本傳輸協定,是短連接配接,是用戶端主動發送請求,伺服器做出響應,伺服器響應之後,連結斷開。HTTP是一個屬于應用層面向對象的協定,HTTP有兩類封包:請求封包和響應封包。
  • HTTP請求封包:一個HTTP請求封包由請求行、請求頭部、空行和請求資料4部分組成。
  • HTTP響應封包:由三部分組成:狀态行、消息報頭、響應正文。
  • GET請求:參數在位址後拼接,沒有請求資料,不安全(因為所有參數都拼接在位址後面),不适合傳輸大量資料(長度有限制,為1024個位元組)。
    GET送出、請求的資料會附在URL之後,即把資料放置在HTTP協定頭<requestline>中。
      以?分割URL和傳輸資料,多個參數用&連接配接。如果資料是英文字母或數字,原樣發送,
      如果是空格,轉換為+,如果是中文/其他字元,則直接把字元串用BASE64加密。
               
  • POST請求:參數在請求資料區放着,相對GET請求更安全,并且資料大小沒有限制。把送出的資料放置在HTTP包的包體

    <request-body>

    中.
  • GET送出的資料會在位址欄顯示出來,而POST送出,位址欄不會改變。

傳輸資料的大小:

  • GET送出時,傳輸資料就會受到URL長度限制,POST由于不是通過URL傳值,理論上書不受限。

安全性:

  • POST的安全性要比GET的安全性高;
  • 通過GET送出資料,使用者名和密碼将明文出現在URL上,比如登陸界面有可能被浏覽器緩存。
  • HTTPS:安全超文本傳輸協定(

    Secure Hypertext Transfer Protocol

    ),它是一個安全通信通道,基于HTTP開發,用于客戶計算機和伺服器之間交換資訊,使用安全套結字層(

    SSI

    )進行資訊交換,即HTTP的安全版。

ASIHttpRequest、AFNetWorking之間的差別

  • ASIHttpRequest功能強大,主要是在MRC下實作的,是對系統CFNetwork API進行了封裝,支援HTTP協定的CFHTTP,配置比較複雜,并且ASIHttpRequest架構預設不會幫你監聽網絡改變,如果需要讓ASIHttpRequest幫你監聽網絡狀态改變,并且手動開始這個功能。
  • AFNetWorking建構于NSURLConnection、NSOperation以及其他熟悉的Foundation技術之上。擁有良好的架構,豐富的API及子產品建構方式,使用起來非常輕松。它基于NSOperation封裝的,AFURLConnectionOperation子類。
  • ASIHttpRequest是直接操作對象ASIHttpRequest是一個實作了NSCoding協定的NSOperation子類;AFNetWorking直接操作對象的AFHttpClient,是一個實作NSCoding和NSCopying協定的NSObject子類。
  • 同步請求:ASIHttpRequest直接通過調用一個

    startSynchronous

    方法;AFNetWorking預設沒有封裝同步請求,如果開發者需要使用同步請求,則需要重寫

    getPath:paraments:success:failures

    方法,對于AFHttpRequestOperation進行同步處理。
  • 性能對比:AFNetworking請求優于ASIHttpRequest;

XML資料解析方式各有什麼不同,JSON解析有哪些架構?

  • XML資料解析的兩種解析方式:DOM解析和SAX解析;
  • DOM解析必須完成DOM樹的構造,在處理規模較大的XML文檔時就很耗記憶體,占用資源較多,讀入整個XML文檔并建構一個駐留記憶體的樹結構(節點樹),通過周遊樹結構可以檢索任意XML節點,讀取它的屬性和值,通常情況下,可以借助XPath查詢XML節點;
  • SAX與DOM不同,它是事件驅動模型,解析XML文檔時每遇到一個開始或者結束标簽、屬性或者一條指令時,程式就産生一個事件進行相應的處理,一邊讀取XML文檔一邊處理,不必等整個文檔加載完才采取措施,當在讀取解析過程中遇到需要處理的對象,會發出通知進行處理。是以,SAX相對于DOM來說更适合操作大的XML文檔。
    -JSON解析:性能比較好的主要是第三方的JSONKIT和iOS自帶的JSON解析類,其中自帶的JSON解析性能最高,但隻能用于iOS5之後。
               

如何進行真機調試

  • 1.首先需要用

    鑰匙串

    建立一個鑰匙(key);
  • 2.将鑰匙串上傳到官網,擷取iOS Development證書;
  • 3.建立App ID即我們應用程式中的Boundle ID;
  • 4.添加Device ID即UDID;
  • 5.通過勾選前面所建立的證書:App ID、Device ID;
  • 6.生成mobileprovision檔案;
  • 7.先決條件:申請開發者賬号 99美刀

APP釋出的上架流程

  • 1.登入 應用釋出網站 添加應用資訊;
  • 2.下載下傳安裝釋出證書;
  • 3.選擇釋出證書,使用Archive編譯釋出包,用Xcode将代碼(釋出包)上傳到伺服器;
  • 4.等待稽核通過;
  • 5.生成IPA:菜單欄->Product->Archive.

SVN的使用

  • SVN=版本控制+備份伺服器,可以把SVN當成備份伺服器,并且可以幫助你記住每次上伺服器的檔案内容,并自動賦予每次變更的版本;
  • SVN的版本控制:所有上傳版本都會幫您記錄下來,也有版本分支及合并等功能。SVN可以讓不同的開發者存取同樣的檔案,并且利用SVN Server作為檔案同步的機制,即您有檔案更新時,無需将檔案寄送給您的開發成員。SVN的存放檔案方式是采用差異備份的方式,即會備份到不同的地方,節省硬碟空間,也可以對非文字檔案進行差異備份。
  • SVN的重要性:備份工作檔案的重要性、版本控管的重要性、夥伴間的資料同步的重要性、備份不同版本是很耗費硬碟空間的;
  • 防止沖突:
    1.防止代碼沖突:不要多人同時修改同一檔案,例如:A、B都修改同一個檔案,先讓A修改,然後送出到伺服器,然後B更新下來,再進行修改;
    2.伺服器上的項目檔案Xcodeproj,僅讓一個人管理送出,其他人隻更新,防止檔案發生沖突。
               

如何進行網絡消息推送

  • 一種是Apple自己提供的通知服務(APNS伺服器)、一種是用第三方推送機制。
  • 首先應用發送通知,系統彈出提示框詢問使用者是否允許,當使用者允許後向蘋果伺服器(APNS)請求deviceToken,并由蘋果伺服器發送給自己的應用,自己的應用将DeviceToken發送自己的伺服器,自己伺服器想要發送網絡推送時将deviceToken以及想要推送的資訊發送給蘋果伺服器,蘋果伺服器将資訊發送給應用。
  • 推送資訊内容,總容量不超過256個位元組;
  • iOS SDK本身提供的APNS伺服器推送,它可以直接推送給目标使用者并根據您的方式彈出提示。
    優點:不論應用是否開啟,都會發送到手機端;
    缺點:消息推送機制是蘋果服務端控制,個别時候可能會有延遲,因為蘋果伺服器也有隊列來處理所有的消息請求;           
  • 第三方推送機制,普遍使用Socket機制來實作,幾乎可以達到即時的發送到目标使用者手機端,适用于即時通訊類應用。
    優點:實時的,取決于心跳包的節奏;
    缺點:iOS系統的限制,應用不能長時間的背景運作,是以應用關閉的情況下這種推送機制不可用。
               

網絡七層協定

  • 應用層:
    1.使用者接口、應用程式;
    2.Application典型裝置:網關;
    3.典型協定、标準和應用:TELNET、FTP、HTTP           
  • 表示層:
    1.資料表示、壓縮和加密presentation
    2.典型裝置:網關
    3.典型協定、标準和應用:ASCLL、PICT、TIFF、JPEG|MPEG
    4.表示層相當于一個東西的表示,表示的一些協定,比如圖檔、聲音和視訊MPEG。           
  • 會話層:
    1.會話的建立和結束;
    2.典型裝置:網關;
    3.典型協定、标準和應用:RPC、SQL、NFS、X WINDOWS、ASP           
  • 傳輸層:
    1.主要功能:端到端控制Transport;
    2.典型裝置:網關;
    3.典型協定、标準和應用:TCP、UDP、SPX           
  • 網絡層:
    1.主要功能:路由、尋址Network;
    2.典型裝置:路由器;
    3.典型協定、标準和應用:IP、IPX、APPLETALK、ICMP;           
  • 資料鍊路層:
    1.主要功能:保證無差錯的疏忽鍊路的data link;
    2.典型裝置:交換機、網橋、網卡;
    3.典型協定、标準和應用:802.2、802.3ATM、HDLC、FRAME RELAY;           
  • 實體層:
    1.主要功能:傳輸比特流Physical;
    2.典型裝置:集線器、中繼器
    3.典型協定、标準和應用:V.35、EIA/TIA-232.
               

對NSUserDefaults的了解

  • NSUserDefaults:系統提供的一種存儲資料的方式,主要用于儲存少量的資料,預設存儲到library下的Preferences檔案夾。

SDWebImage原理

調用類别的方法:

  • 從記憶體中(字典)找圖檔(當這個圖檔在本次程式加載過),找到直接使用;
  • 從沙盒中找,找到直接使用,緩存到記憶體。
  • 從網絡上擷取,使用,緩存到記憶體,緩存到沙盒。

OC中是否有二維數組,如何實作二維數組

  • OC中沒有二維數組,可通過嵌套數組實作二維數組。

LayoutSubViews在什麼時候被調用?

  • 當View本身的frame改變時,會調用這個方法。

深拷貝和淺拷貝

  • 如果對象有個指針型成員變量指向記憶體中的某個資源,那麼如何複制這個對象呢?你會隻是複制指針的值傳給副本的新對象嗎?指針隻是存儲記憶體中資源位址的占位符。在複制操作中,如果隻是将指針複制給新對象,那麼底層的資源實際上仍然由兩個執行個體在共享。
  • 淺複制:兩個執行個體的指針仍指向記憶體中的同一資源,隻複制指針值而不是實際資源;
  • 深複制:不僅複制指針值,還複制指向指針所指向的資源。如下圖:

單例模式了解與使用

  • 單例模式是一種常用設計模式,單例模式是一個類在系統中隻有一個執行個體對象。通過全局的一個入口點對這個執行個體對象進行通路;
  • iOS中單例模式的實作方式一般分為兩種:非ARC和ARC+GCD。

對沙盒的了解

  • 每個iOS應用都被限制在“沙盒”中,沙盒相當于一個加了僅主人可見權限的檔案夾,及時在應用程式安裝過程中,系統為每個單獨的應用程式生成它的主目錄和一些關鍵的子目錄。蘋果對沙盒有幾條限制:
    1\. 應用程式在自己的沙盒中運作,但是不能通路任何其他應用程式的沙盒;
    2\. 應用之間不能共享資料,沙盒裡的檔案不能被複制到其他
    應用程式的檔案夾中,也不能把其他應用檔案夾複制到沙盒中;
    3\. 蘋果禁止任何讀寫沙盒以外的檔案,禁止應用程式将内容寫到沙盒以外的檔案夾中;
    4\. 沙盒目錄裡有三個檔案夾:Documents——存儲
    應用程式的資料檔案,存儲使用者資料或其他定期備份的資訊;
    Library下有兩個檔案夾,Caches存儲應用程式再次啟動所需的資訊,
    Preferences包含應用程式的偏好設定檔案,不可在這更改偏好設定;
    temp存放臨時檔案即應用程式再次啟動不需要的檔案。           
  • 擷取沙盒根目錄的方法,有幾種方法:用NSHomeDirectory擷取。
  • 擷取Document路徑:
    `NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)`.
               

對瀑布流的了解

  • 首先圖檔的寬度都是一樣的,1.将圖檔等比例壓縮,讓圖檔不變形;2.計算圖檔最低應該擺放的位置,哪一列低就放在哪;3.進行最優排列,在ScrollView的基礎上添加兩個tableView,然後将之前所計算的scrollView的高度通過tableView展示出來。
  • 如何使用兩個TableView産生關聯:将兩個tableView的滾動事件禁止掉,最外層scrollView滾動時将兩個TableView跟着滾動,并且更改contentOffset,這樣産生效果滾動的兩個tableView。

ViewController 的 loadView,、viewDidLoad,、viewDidUnload 分别是在什麼時候調用的?

  • viewDidLoad

    在view從nib檔案初始化時調用,

    loadView

    在controller的view為nil時調用。
  • 此方法在程式設計實作view時調用,view控制器預設會注冊

    memory warning notification

    ,當

    view controller

    的任何view沒有用的時候,

    viewDidUnload

    會被調用,在這裡實作将

    retain

    view release

    ,如果是

    retain

    IBOutlet view

    屬性則不要在這裡

    release

    ,

    IBOutlet

    會負責

    release

關鍵字volatile有什麼含意?并給出三個不同的例子:

  • 一個定義為

    volatile

    的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精确地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用儲存在寄存器裡的備份。下面是

    volatile

    變量的幾個例子:
    • 并行裝置的硬體寄存器(如:狀态寄存器);
    •一個中斷服務子程式中會通路到的非自動變量(Non-automatic variables);
    • 多線程應用中被幾個任務共享的變量。
               

@synthesize、@dynamic的了解

  • @synthesize

    是系統自動生成getter和setter屬性聲明;

    @synthesize

    的意思是,除非開發人員已經做了,否則由編譯器生成相應的代碼,以滿足屬性聲明;
  • @dynamic

    是開發者自已提供相應的屬性聲明,

    @dynamic

    意思是由開發人員提供相應的代碼:對于隻讀屬性需要提供

    setter

    ,對于讀寫屬性需要提供

    setter

    getter

    。查閱了一些資料确定

    @dynamic

    的意思是告訴編譯器,屬性的擷取與指派方法由使用者自己實作, 不自動生成。

frame和bounds有什麼不同?

  • frame指的是:該view在父view坐标系統中的位置和大小。(參照點是父親的坐标系統)
  • bounds指的是:該view在本身坐标系統中的位置和大小。(參照點是本身坐标系統)

view的touch事件有哪些?

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
  - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
  - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; 
  - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
           

自定義實作UITabbarController的原理

  • 運用字典,點選五個按鈕的一個可以從字典裡選擇一個控制器對象,将其View顯示到主要制器視圖上。

iOS中的響應者鍊的工作原理

  • 每一個應用有一個響應者鍊,我們的視圖結構是一個N叉樹(一個視圖可以有多個子視圖,一個子視圖同一時刻隻有一個父視圖),而每一個繼承

    UIResponder

    的對象都可以在這個N叉樹中扮演一個節點。
  • 當葉節點成為最高響應者的時候,從這個葉節點開始往其父節點開始追朔出一條鍊,那麼對于這一個葉節點來講,這一條鍊就是目前的響應者鍊。響應者鍊将系統捕獲到的UIEvent與UITouch從葉節點開始層層向下分發,期間可以選擇停止分發,也可以選擇繼續向下分發。
  • 如需了解更多細節,請讀

View和View之間傳值方式

  • 對象的property屬性傳值;
  • 方法參數傳值;
  • NSUserDefault傳值;
  • 塊傳值。

property屬性的修飾符的作用

  • getter=getName、setter=setName:設定setter與getter的方法名;
  • readwrite、readonly:設定可供通路級别;
  • assign:方法直接指派,不進行任何retain操作,為了解決原類型與環循引用問題;
  • retain:其setter方法對參數進行release舊值再retain新值,所有實作都是這個順序;
  • copy:其setter方法進行copy操作,與retain處理流程一樣,先對舊值release,再copy出新的對象,retainCount為1。這是為了減少對上下文的依賴而引入的機制。
  • nonatomic:非原子性通路,不加同步, 多線程并發通路會提高性能。注意,如果不加此屬性,則預設是兩個通路方法都為原子型事務通路。

對于Run Loop的了解

  • RunLoop,是多線程的法寶,即一個線程一次隻能執行一個任務,執行完任務後就會退出線程。主線程執行完即時任務時會繼續等待接收事件而不退出。非主線程通常來說就是為了執行某一任務的,執行完畢就需要歸還資源,是以預設是不運作RunLoop的;
  • 每一個線程都有其對應的RunLoop,隻是預設隻有主線程的RunLoop是啟動的,其它子線程的RunLoop預設是不啟動的,若要啟動則需要手動啟動;
  • 在一個單獨的線程中,如果需要在處理完某個任務後不退出,繼續等待接收事件,則需要啟用RunLoop;
  • NSRunLoop提供了一個添加NSTimer的方法,可以指定Mode,如果要讓任何情況下都回調,則需要設定Mode為Common模式;
  • 實質上,對于子線程的runloop預設是不存在的,因為蘋果采用了懶加載的方式。如果我們沒有手動調用

    [NSRunLoop currentRunLoop]

    的話,就不會去查詢是否存在目前線程的RunLoop,也就不會去加載,更不會建立。

SQLite中常用的SQL語句

  • 建立表:creat table 表名 (字段名 字段資料類型 是否為主鍵, 字段名 字段資料類型, 字段名 字段資料類型...);
  • 增: insert into 表名 (字段1, 字段2...) values (值1, 值2...);
  • 删: delete from 表名 where 字段 = 值;

XIB與Storyboards的優缺點

  • XIB:在編譯前就提供了可視化界面,可以直接拖控件,也可以直接給控件添加限制,更直覺一些,而且類檔案中就少了建立控件的代碼,确實簡化不少,通常每個XIB對應一個類。
  • Storyboard:在編譯前提供了可視化界面,可拖控件,可加限制,在開發時比較直覺,而且一個storyboard可以有很多的界面,每個界面對應一個類檔案,通過storybard,可以直覺地看出整個App的結構。
  • XIB:需求變動時,需要修改XIB很大,有時候甚至需要重新添加限制,導緻開發周期變長。XIB載入相比純代碼自然要慢一些。對于比較複雜邏輯控制不同狀态下顯示不同内容時,使用XIB是比較困難的。當多人團隊或者多團隊開發時,如果XIB檔案被發動,極易導緻沖突,而且解決沖突相對要困難很多。
  • Storyboard:需求變動時,需要修改storyboard上對應的界面的限制,與XIB一樣可能要重新添加限制,或者添加限制會造成大量的沖突,尤其是多團隊開發。對于複雜邏輯控制不同顯示内容時,比較困難。當多人團隊或者多團隊開發時,大家會同時修改一個storyboard,導緻大量沖突,解決起來相當困難。

将字元串“2015-04-10”格式化日期轉為NSDate類型

NSString *timeStr = @"2015-04-10";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
formatter.timeZone = [NSTimeZone defaultTimeZone];
NSDate *date = [formatter dateFromString:timeStr];
// 2015-04-09 16:00:00 +0000
NSLog(@"%@", date);
           

隊列和多線程的使用原理

在iOS中隊列分為以下幾種:

  • 串行隊列:隊列中的任務隻會順序執行;
    dispatch_queue_t q = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL);           
  • 并行隊列: 隊列中的任務通常會并發執行;
    dispatch_queue_t q = dispatch_queue_create("......",DISPATCH_QUEUE_CONCURRENT);           
  • 全局隊列:是系統的,直接拿過來(GET)用就可以;與并行隊列類似;
    dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);           
  • 主隊列:每一個應用程式對應唯一主隊列,直接GET即可;在多線程開發中,使用主隊列更新UI;
    dispatch_queue_t q = dispatch_get_main_queue();           
  • 更多細節見下圖:
    ![](//upload-images.jianshu.io/upload_images/1713024-0cb065e2b0883ffb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)
               

記憶體的使用和優化的注意事項

  • 重用問題:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews設定正确的reuseIdentifier,充分重用;
  • 盡量把views設定為不透明:當opque為NO的時候,圖層的半透明取決于圖檔和其本身合成的圖層為結果,可提高性能;
  • 不要使用太複雜的XIB/Storyboard:載入時就會将XIB/storyboard需要的所有資源,包括圖檔全部載入記憶體,即使未來很久才會使用。那些相比純代碼寫的延遲加載,性能及記憶體就差了很多;
  • 選擇正确的資料結構:學會選擇對業務場景最合适的數組結構是寫出高效代碼的基礎。比如,數組: 有序的一組值。使用索引來查詢很快,使用值查詢很慢,插入/删除很慢。字典: 存儲鍵值對,用鍵來查找比較快。集合: 無序的一組值,用值來查找很快,插入/删除很快。
    gzip/zip壓縮:當從服務端下載下傳相關附件時,可以通過gzip/zip壓縮後再下載下傳,使得記憶體更小,下載下傳速度也更快。           
  • 延遲加載:對于不應該使用的資料,使用延遲加載方式。對于不需要馬上顯示的視圖,使用延遲加載方式。比如,網絡請求失敗時顯示的提示界面,可能一直都不會使用到,是以應該使用延遲加載。
  • 資料緩存:對于cell的行高要緩存起來,使得reload資料時,效率也極高。而對于那些網絡資料,不需要每次都請求的,應該緩存起來,可以寫入資料庫,也可以通過plist檔案存儲。
  • 處理記憶體警告:一般在基類統一處理記憶體警告,将相關不用資源立即釋放掉
    重用大開銷對象:一些objects的初始化很慢,比如`NSDateFormatter`和`NSCalendar`,但又不可避免地需要使用它們。通常是作為屬性存儲起來,防止反複建立。           
  • 避免反複處理資料:許多應用需要從伺服器加載功能所需的常為JSON或者XML格式的資料。在伺服器端和用戶端使用相同的資料結構很重要;
  • 使用Autorelease Pool:在某些循環建立臨時變量處理資料時,自動釋放池以保證能及時釋放記憶體;
  • 正确選擇圖檔加載方式:詳情閱讀 細讀UIImage加載方式

UIViewController的完整生命周期

-[ViewController initWithNibName:bundle:];
-[ViewController init];
-[ViewController loadView];
-[ViewController viewDidLoad];
-[ViewController viewWillAppear:];
-[ViewController viewWillLayoutSubviews:];
-[ViewController viewDidLayoutSubviews:];
-[ViewController viewDidAppear:];
-[ViewController viewWillDisappear:];
-[ViewController viewDidDisappear:];
-[ViewController viewWillUnload:];
-[ViewController viewDidUnload:];
           

UIImageView添加圓角

  • 最直接的方法就是使用如下屬性設定:

    imgView.layer.cornerRadius = 10;

    // 這一行代碼是很消耗性能的

    imgView.clipsToBounds = YES;

    **這是離屏渲染(off-screen-rendering),消耗性能的**

  • 給UIImage添加生成圓角圖檔的擴充API:這是on-screen-rendering
    • (UIImage *)imageWithCornerRadius:(CGFloat)radius {

      CGRect rect = (CGRect){0.f, 0.f, self.size};

    UIGraphicsBeginImageContextWithOptions(self.size, NO, UIScreen.mainScreen.scale);
    CGContextAddPath(UIGraphicsGetCurrentContext(),
     [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);
    CGContextClip(UIGraphicsGetCurrentContext());
    
    [self drawInRect:rect];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    return image;
    }           
推薦一個QQ交流群:763164022 !群内有最近整理出來的面試題,以及一些書籍學習資料!也是為了給大部分還在做iOS開發的朋友一個交流圈子!

繼續閱讀