序言
目前形勢,參加到iOS隊伍的人是越來越多,甚至已經到供過於求了。今年,找過工作人可能會更深刻地體會到今年的就業形勢不容樂觀,加之,培訓機構一火車地向用人單位輸送iOS開發人員,打破了生態圈的動態平衡。矯情一下,言歸正傳,我奉獻一下,為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方法名,如
1@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
訊息的斷裂。因此,最好不要覆蓋原始類中的方法。
類別的作用
- 給系統原有類新增方法,不能擴充套件屬性。如果類別中方法的名字跟系統的方法名一樣,在呼叫的時候類別中的方法優先順序更高;
- 分散類的實現:如:
12+ (NSIndexPath *)indexPathForRow:(NSInteger)rowinSection:(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
1 2 3 4 5 6 7 8 |
[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
- 註冊觀察者(
注意:觀察者和被觀察者不會被保留也不會被釋放
)
123- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPathoptions:(NSKeyValueObservingOptions)optionscontext:(void *)context; - 接收變更通知
12- (void)observeValueForKeyPath:(NSString *)keyPathofObject:(id)object change:(NSDictionary *)change context:(void *)context; - 移除物件的觀察者身份
12- (void)removeObserver:(NSObject *)observerforKeyPath:(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
協議方法為:
12345- (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中,並沒有提供三個引數。因此,我們只能傳陣列或者字典,但是陣列或者字典只有存入物件型別,而結構體並不是物件型別,我們只能通過物件放入結構作為屬性來傳過去了.
1234- (id)performSelector:(SEL)aSelector;- (id)performSelector:(SEL)aSelector withObject:(id)object;- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2; - 具體實現如下:
1234567891011121314151617181920typedef 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 - 測試:
123456789101112my_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滑動時會切換到該ModeUIInitializationRunLoopMode
:run loop啟動時,會切換到該modeNSRunLoopCommonModes(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,這種重用機制會導致內容出錯,為解決這種出錯的方法,把原來的
12UITableViewCell *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來實現:
123456789dispatch_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,具體實現
- 實現方法:
123456NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0repeats:YEScallback:^() {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個位元組)。
12GET提交、請求的資料會附在URL之後,即把資料放置在HTTP協議頭中。以?分割URL和傳輸資料,多個引數用 - POST請求:引數在請求資料區放著,相對GET請求更安全,並且資料大小沒有限制。把提交的資料放置在HTTP包的包體
中.
- 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應用都被限制在“沙盒”中,沙盒相當於一個加了僅主人可見許可權的資料夾,及時在應用程式安裝過程中,系統為每個單獨的應用程式生成它的主目錄和一些關鍵的子目錄。蘋果對沙盒有幾條限制:
1234567891. 應用程式在自己的沙盒中運作,但是不能訪問任何其他應用程式的沙盒;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事件有哪些?
1 2 3 4 |
- (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型別
1 2 3 4 5 6 7 |
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中佇列分為以下幾種:
- 序列佇列:佇列中的任務只會順序執行;
1dispatch_queue_t q = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL); - 並行佇列: 佇列中的任務通常會併發執行;
1dispatch_queue_t q = dispatch_queue_create("......",DISPATCH_QUEUE_CONCURRENT); - 全域性佇列:是系統的,直接拿過來(GET)用就可以;與並行佇列類似;
1dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - 主佇列:每一個應用程式對應唯一主佇列,直接GET即可;在多執行緒開發中,使用主佇列更新UI;
1dispatch_queue_t q = dispatch_get_main_queue(); - 更多細節見下圖:
來自簡書
記憶體的使用和優化的注意事項
- 重用問題:如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的完整生命週期
1 2 3 4 5 6 7 8 |
-[ViewController initWithNibName:bundle:]; -[ViewController init]; -[ViewController loadView]; -[ViewController viewDidLoad]; -[ViewController viewWillDisappear:]; -[ViewController viewWillAppear:]; -[ViewController viewDidAppear:]; -[ViewController viewDidDisappear:]; |
UIImageView新增圓角
- 最直接的方法就是使用如下屬性設定:
123imgView.layer.cornerRadius = 10;// 這一行程式碼是很消耗效能的imgView.clipsToBounds = YES;
**這是離屏渲染(off-screen-rendering),消耗效能的**
- 給UIImage新增生成圓角圖片的擴充套件API:這是on-screen-rendering
123456789101112131415- (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;}