2019-11-14 記iOS高級工程師面試題

1. 簡述一下iOS的內(nèi)存管理?

內(nèi)存條中主要分為幾大類:棧區(qū)(stack)、堆區(qū)(heap)、常量區(qū)、代碼區(qū)(.text)、保留區(qū)。常量區(qū)分為未初始化區(qū)域(.bss)和已初始化區(qū)域(.data),棧區(qū)stack存儲順序是由高地址存向低地址,而堆區(qū)是由低地址向高地址存儲。內(nèi)存條中地址由低到高的區(qū)域分別為:保留區(qū),代碼區(qū),已初始化區(qū)(.data),未初始化區(qū)(.bss),堆區(qū)(heap),棧區(qū)(stack),內(nèi)核區(qū)。而程序員操作的主要是棧區(qū)與堆區(qū)還有常量區(qū)

當創(chuàng)建一個對象的實例并在堆上申請內(nèi)存時,對象的引用計數(shù)就為1,在其他對象中需要持有這個對象時,就需要把該對象的引用計數(shù)加1,需要釋放一個對象時,就將該對象的引用計數(shù)減1,直至對象的引用計數(shù)為0,對象的內(nèi)存會被立刻釋放。

MRC(手動管理引用計數(shù)):在MRC中增加的引用計數(shù)都是需要自己手動釋放的,遵循4個法則:

自己生成的對象,自己持有。

非自己生成的對象,自己也能持有。

不在需要自己持有對象的時候,釋放。

非自己持有的對象無需釋放。

ARC(自動管理引用計數(shù)):? 現(xiàn)在的iOS開發(fā)基本都是基于ARC的,所以開發(fā)人員大部分情況都是不需要考慮內(nèi)存管理的,因為編譯器已經(jīng)幫你做了。為什么說是大部分呢,因為底層的?Core Foundation?對象由于不在 ARC 的管理下,所以需要自己維護這些對象的引用計數(shù)。

2. 屬性關(guān)鍵字有哪些? block和delegate作為屬性用什么修飾 為什么?

關(guān)鍵字? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 注釋

readwrite? ? ? ? ? ? ? ? ? ?此標記說明屬性會被當成讀寫的,這也是默認屬性。

readonly? ? ? ? ? ? ? ? ? ? 此標記說明屬性只可以讀,也就是不能設(shè)置,可以獲取。

assign? ? ? ? ? ? ? ? ? ? ? ?不會使引用計數(shù)加1,也就是直接賦值。 基本數(shù)據(jù)類型和C數(shù)據(jù)類型默認屬性

retain? ? ? ? ? ? ? ? ? ? ? ? ?會使引用計數(shù)加1。

copy? ? ? ? ? ? ? ? ? ? ? ? ? ?建立一個索引計數(shù)為1的對象,在賦值時使用傳入值的一份拷貝。

nonatomic? ? ? ? ? ? ? ? ?非原子性訪問,多線程并發(fā)訪問會提高性能。

?atomic? ? ? ? ? ? ? ? ? ? ? ?原子性訪問。默認屬性

strong? ? ? ? ? ? ? ? ? ? ? ? 打開ARC時才會使用,相當于retain。默認屬性

weak? ? ? ? ? ? ? ? ? ? ? ? ? 打開ARC時才會使用,相當于assign,可以把對應(yīng)的指針變量置為nil

基本數(shù)據(jù):?atomic,readwrite,assign

普通的 OC 對象:?atomic,readwrite,strong

block在創(chuàng)建的時候,它的內(nèi)存是分配在棧(stack)上,而不是在堆(heap)上。他本身的作于域是屬于創(chuàng)建時候的作用域,一旦在創(chuàng)建時候的作用域外面調(diào)用block將導致程序崩潰(棧區(qū)上的過了作用域就清除了).

因為block變量默認是聲明為棧變量的,為了能夠在block的聲明域外使用,所以要把block拷貝(copy)到堆,所以說為了block屬性聲明和實際的操作一致,最好聲明為copy

使用copy修飾就會對Block的內(nèi)部對象進行強引用,導致循環(huán)引用。內(nèi)存無法釋放。就需要__weak對block內(nèi)部對象進行修飾

如果代理是strong修飾,那么當Viewcontroller需要釋放的時候—->就需要先釋放這個A—->A就需要釋放這個代理—–>代理又需要釋放這個Viewcontroller,就會引起循環(huán)引用。故而需要使用weak

3.? 什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同?

在 ARC 中,在有可能出現(xiàn)循環(huán)引用的時候,往往要通過讓其中一端使用 weak 來解決

assign自身已經(jīng)對它進行一次強引用,沒有必要再強引用一次,此時也會使用 weak

自定義IBOutlet 控件屬性一般也使用weak;當然,也可以使用 strong,但是建議使用 weak

weak 策略在屬性所指的對象遭到摧毀時,系統(tǒng)會將 weak 修飾的屬性對象的指針指向 nil,在 OC 給 nil 發(fā)消息是不會有什么問題的;如果使用 assign 策略在屬性所指的對象遭到摧毀時,屬性對象指針還指向原來的對象,由于對象已經(jīng)被銷毀,這時候就產(chǎn)生了野指針,如果這時候在給此對象發(fā)送消息,很容造成程序奔潰assigin 可以用于修飾非 OC 對象,而 weak 必須用于 OC 對象。

4. 怎么用 copy 關(guān)鍵字?

NSString、NSArray、NSDictionary 等等經(jīng)常使用 copy 關(guān)鍵字,是因為他們有對應(yīng)的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary.

因為父類指針可以指向子類對象,使用 copy 的目的是為了讓本對象的屬性不受外界影響,使用 copy 無論給我傳入是一個可變對象還是不可對象,我本身持有的就是一個不可變的副本.

為確保對象中的屬性值不會無意間變動,應(yīng)該在設(shè)置新屬性值時拷貝一份,保護其封裝性block,也經(jīng)常使用 copy,關(guān)鍵字block

使用 copy 是從 MRC 遺留下來的“傳統(tǒng)”,在 MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).

在 ARC 中寫不寫都行:對于 block 使用 copy 還是 strong 效果是一樣的,但是建議寫上 copy,因為這樣顯示告知調(diào)用者“編譯器會自動對 block 進行了 copy 操作。

[不可變對象 copy]// 淺復制

[不可變對象 mutableCopy]//深復制

[可變對象 copy]//深復制?

[可變對象 mutableCopy]//深復制

5.?如何讓自定義類可以用 copy 修飾符?如何重寫帶 copy 關(guān)鍵字的 setter?

若想令自己所寫的對象具有拷貝功能,則需實現(xiàn) NSCopying 協(xié)議。如果自定義的對象分為可變版本與不可變版本,那么就要同時實現(xiàn) NSCopyiog 與NSMutableCopying 協(xié)議,不過一般沒什么必要,實現(xiàn) NSCopying 協(xié)議就夠了

// 實現(xiàn)不可變版本拷貝-(id)copyWithZone:(NSZone*)zone;// 實現(xiàn)可變版本拷貝-(id)mutableCopyWithZone:(NSZone*)zone;// 重寫帶 copy 關(guān)鍵字的 setter-(void)setName:(NSString*)name{_name=[name copy];}

6.. 簡述一下KVO和KVC的原理?具體到方法

KVC/KVO實現(xiàn)的根本是Objective-C的動態(tài)性和runtime

KVC:Key-Value Coding,即鍵值編碼 是一種不通過存取方法 而是通過屬性字符串間接訪問屬性的機制 。

-(id)valueForKey:(NSString*)key;

-(void)setValue:(id)value forKey:(NSString*)key;

-(id)valueForKeyPath:(NSString*)keyPath;

-(void)setValue:(id)value forKeyPath:(NSString*)keyPath;

前兩個方法無論獲取值還是賦值,只需要傳入屬性名稱的字符串就行了。但KVC也提供了傳入path的方法。所謂path,就是用點號連接的多層級的屬性,比如student.name,student屬性里的name屬性。

KVC的方法查找順序:

①檢查是否存在-<key>、-is<key>(只針對布爾值有效)或者-get<key>的訪問器方法,如果有可能,就是用這些方法返回值;

檢查是否存在名為-set<key>:的方法,并使用它做設(shè)置值。對于-get<key>和-set<key>:方法,將大寫Key字符串的第一個字母,并與Cocoa的方法命名保持一致;

②如果上述方法不可用,則檢查名為-_<key>、-_is<key>(只針對布爾值有效)、-_get<key>和-_set<key>:方法;

③如果沒有找到訪問器方法,可以嘗試直接訪問實例變量。實例變量可以是名為:<key>或_<key>;

④如果仍為找到,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法。這些方法的默認實現(xiàn)都是拋出異常,我們可以根據(jù)需要重寫它們。

KVO:key-value observing 即鍵值觀察 提供了一種當前對象屬性被修改的時候通過當前對象的機制,KVO很適合實現(xiàn)model和controller之間的通訊。

當某個類的對象第一次被觀察時,系統(tǒng)就會在運行期動態(tài)地創(chuàng)建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的 setter 方法。

派生類在被重寫的 setter 方法實現(xiàn)真正的通知機制

新類會重寫對應(yīng)的set方法,是為了在set方法中增加另外兩個方法的調(diào)用:

- (void)willChangeValueForKey:(NSString *)key

- (void)didChangeValueForKey:(NSString *)key

其中,didChangeValueForKey:方法負責調(diào)用:

- (void)observeValueForKeyPath:(NSString *)keyPath? ?ofObject:(id)object? ?change:(NSDictionary *)change context:(void *)context

KVO的缺點:

KVO的回調(diào)機制不能傳一個Selector或block作為回調(diào) 必須回調(diào)-addObserver:forKeyPath:options:context:方法

具體方法:

首先給目標對象的屬性添加觀察:-(void)addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context;

實現(xiàn)下面方法來接收通知,需要注意各個參數(shù)的含義:

-(void)observeValueForKeyPath:(nullable NSString*)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*,id>*)change context:(nullablevoid*)context;

最后要移除觀察者:

-(void)removeObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath;

7. setvalue forkey? 和 setobject forkey的區(qū)別?

?setValue:forKey: 的value是可以為nil的(但是當value為nil的時候,會自動調(diào)用removeObject:forKey方法);

setObject:forKey: 的value則不可以為nil。

setValue:forKey: 的key必須是不為nil的字符串類型;

setObject:forKey: 的key可以是不為nil的所有類型。

8. iOS的數(shù)據(jù)本地存儲有方式哪些?

iOS本地持久化存儲的路徑:

Documents: 最常用的目錄,存放重要的數(shù)據(jù),iTunes同步時會備份該目錄

Library/Caches: 一般存放體積大,不重要的數(shù)據(jù),iTunes同步時不會備份該目錄

Library/Preferences: 存放用戶的偏好設(shè)置,iTunes同步時會備份該目錄

tmp: 用于存放臨時文件,在程序未運行時可能會刪除該文件夾中的數(shù)據(jù),iTunes同步時不會備份該目錄

存儲方式:NSUserDefaults、Plist、NSKeyedArchiver、SQLite3、Core Data、Keychain、FMDB

NSUserDafaults存儲:

寫入:NSUserDefaults*login=[NSUserDefaults standardUserDefaults];

login setObject:self.passwordField.text forKey:@"token"]

;[login synchronize];

取出:NSUserDefaults*login=[NSUserDefaults standardUserDefaults];

NSString*str=[login objectForKey:@"token"];

特點:只能存儲OC常用數(shù)據(jù)類型(NSString、NSDictionary、NSArray、NSData、NSNumber等類型)而不能直接存儲自定義數(shù)據(jù)。

鍵值對存儲,直接指定存儲類型。

plist方式存儲:

重要方法: NSString*path=[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)objectAtIndex:0]stringByAppendingPathComponent:@"password.plist"];

特點:

只能存儲OC常用數(shù)據(jù)類型(NSString、NSDictionary、NSArray、NSData、NSNumber等類型)而不能直接存儲自定義模型對象。

plist文件存儲的位置,但一般存在Documents中

如果存儲圖片路徑的話,一定要存儲相對位置,因為每次啟動APP,plist文件的路徑就會變化,自然圖片的位置也就變化了。

NSKeyedArchiver歸檔(NSCoding)方式存儲:

-(nullable instancetype)initWithCoder:(nonnull NSCoder*)aDecoder{

-(void)encodeWithCoder:(nonnull NSCoder*)aCoder{

FMDB方式存儲:

NSString*docuPath=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)[0];

NSString*dbPath=[docuPath stringByAppendingPathComponent:@"test.db"];

NSLog(@"!!!dbPath = %@",dbPath);//2.創(chuàng)建對應(yīng)路徑下數(shù)據(jù)庫

db=[FMDatabase databaseWithPath:dbPath];

FMDatabase:一個FMDatabase對象代表一個單獨的SQLite數(shù)據(jù)庫,通過SQLite語句執(zhí)行數(shù)據(jù)庫的增刪改查操作

FMResultSet:使用FMDatabase對象查詢數(shù)據(jù)庫后的結(jié)果集

FMDatabaseQueue:用于多線程操作數(shù)據(jù)庫,它保證線程安全

開啟事務(wù) :beginTransaction

回滾事務(wù):rollback

提交事務(wù):commit

// 插入數(shù)據(jù)-(void)insertDataWithSQL:(NSString*)sql{[self.queue inDatabase:^(FMDatabase*db){BOOL result=[db executeUpdate:sql withArgumentsInArray:nil];if(result){NSLog(@"插入數(shù)據(jù)成功");}else{NSLog(@"插入數(shù)據(jù)失敗");}}];}

10. iOS多線程有哪些?GCD項目中有什么地方應(yīng)用到?線程死鎖有哪些原因?怎么避免?

NSThread:

NSThread是封裝程度最小最輕量級的,使用更靈活,但要手動管理線程的生命周期、線程同步和線程加鎖等,開銷較大;

兩種創(chuàng)建方式:

NSThread*newThread=[[NSThread alloc]initWithTarget:selfselector:@selector(run)object:nil];

/* 開啟線程 */[newThread start];

[NSThread detachNewThreadSelector:@selector(run)toTarget:selfwithObject:nil];[NSThread detachNewThreadWithBlock:^{NSLog(@"block run...");}];

NSOperation是基于GCD的一個抽象基類,將線程封裝成要執(zhí)行的操作,不需要管理線程的生命周期和同步,但比GCD可控性

更強,例如可以加入操作依賴(addDependency)、設(shè)置操作隊列最大可并發(fā)執(zhí)行的操作個數(shù)

(setMaxConcurrentOperationCount)、取消操作(cancel)等。

NSOperation作為抽象基類不具備封裝我們的操作的功能,需要使用兩個它的實體子類:NSBlockOperation和

NSInvocationOperation,或者繼承NSOperation自定義子類。

NSBlockOperation和NSInvocationOperation用法的主要區(qū)別是:前者執(zhí)行指定的方法,后者執(zhí)行代碼塊,相對來說后者更加靈活易用。

NSInvocationOperation*invoOpertion=[[NSInvocationOperation alloc]initWithTarget:selfselector:@selector(run)object:nil];[invoOpertion start];/* NSBlockOperation初始化 */NSBlockOperation*blkOperation=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"NSBlockOperation");}];[blkOperation start];

?GCD 中兩個核心概念:『任務(wù)』?和?『隊列』

任務(wù):就是執(zhí)行操作的意思,換句話說就是你在線程中執(zhí)行的那段代碼。在 GCD 中是放在 block 中的。執(zhí)行任務(wù)有兩種方

式:『同步執(zhí)行』和『異步執(zhí)行』。兩者的主要區(qū)別是:是否等待隊列的任務(wù)執(zhí)行結(jié)束,以及是否具備開啟新線程的能力。

可以使用?dispatch_queue_create?方法來創(chuàng)建隊列。該方法需要傳入兩個參數(shù):

第一個參數(shù)表示隊列的唯一標識符,用于 DEBUG,可為空。隊列的名稱推薦使用應(yīng)用程序 ID 這種逆序全程域名。

第二個參數(shù)用來識別是串行隊列還是并發(fā)隊列。DISPATCH_QUEUE_SERIAL?表示串行隊列,

DISPATCH_QUEUE_CONCURRENT?表示并發(fā)隊列

GCD 默認提供了:『主隊列(Main Dispatch Queue)』。所有放在主隊列中的任務(wù),都會放到主線程中執(zhí)行??墒?/p>

用?dispatch_get_main_queue()?方法獲得主隊列。

區(qū)別? ? ? ? ? ? ? ? ? ? ? ? ?并發(fā)隊? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 列串行隊列? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?主隊列

同步(sync)? ? 沒有開啟新線程,串行執(zhí)行任務(wù)? ? ? ?沒有開啟新線程,串行執(zhí)行任務(wù)? ? ? ? ? ? ?死鎖卡住不執(zhí)行

異步(async)? ?有開啟新線程,并發(fā)執(zhí)行任務(wù)? ? ? ? ? ?有開啟新線程(1條),串行執(zhí)行任務(wù)? 沒有開啟新線程,串行執(zhí)行任務(wù)

『主線程』中調(diào)用『主隊列』+『同步執(zhí)行』會導致死鎖問題。

這是因為主隊列中追加的同步任務(wù)和主線程本身的任務(wù)兩者之間相互等待,阻塞了『主隊列』,最終造成了主隊列所在的線程

(主線程)死鎖問題。

GCD 線程間的通信:

// 獲取主隊列 dispatch_queue_t mainQueue = dispatch_get_main_queue();

// 回到主線程

? ? ? ? dispatch_async(mainQueue, ^{

? ? ? ? ? ? // 追加在主線程中執(zhí)行的任務(wù)

? ? ? ? ? ? [NSThread sleepForTimeInterval:2];? ? ? ? ? ? ? // 模擬耗時操作

? ? ? ? ? ? NSLog(@"2---%@",[NSThread currentThread]);? ? ? // 打印當前線程

? ? ? ? });

GCD 柵欄方法:dispatch_barrier_async

我們有時需要異步執(zhí)行兩組操作,而且第一組操作執(zhí)行完之后,才能開始執(zhí)行第二組操作。這樣我們就需要一個相當于柵欄一

樣的一個方法將兩組異步執(zhí)行的操作組給分割起來,當然這里的操作組里可以包含一個或多個任務(wù)。這就需要用到

dispatch_barrier_async方法在兩個操作組間形成柵欄。

dispatch_barrier_async(queue, ^{

? ? ? ? // 追加任務(wù) barrier

? ? ? ? [NSThread sleepForTimeInterval:2];? ? ? ? ? ? ? // 模擬耗時操作

? ? ? ? NSLog(@"barrier---%@",[NSThread currentThread]);// 打印當前線程

? ? });

GCD 延時執(zhí)行方法:dispatch_after

在指定時間(例如 3 秒)之后執(zhí)行某個任務(wù)。可以用 GCD 的dispatch_after?方法來實現(xiàn)。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

? ? ? ? // 2.0 秒后異步追加任務(wù)代碼到主隊列,并開始執(zhí)行

? ? ? ? NSLog(@"after---%@",[NSThread currentThread]);? // 打印當前線程

? ? });

GCD 一次性代碼(只執(zhí)行一次):dispatch_once

我們在創(chuàng)建單例、或者有整個程序運行過程中只執(zhí)行一次的代碼時,我們就用到了 GCD 的dispatch_once方法。使用

dispatch_once方法能保證某段代碼在程序運行過程中只被執(zhí)行 1 次,并且即使在多線程的環(huán)境下,dispatch_once也可以保證

線程安全。

/**

* 一次性代碼(只執(zhí)行一次)dispatch_once

*/

- (void)once {

? ? static dispatch_once_t onceToken;

? ? dispatch_once(&onceToken, ^{

? ? ? ? // 只執(zhí)行 1 次的代碼(這里面默認是線程安全的)

? ? });

}

GCD 快速迭代方法:dispatch_apply

通常我們會用 for 循環(huán)遍歷,但是 GCD 給我們提供了快速迭代的方法dispatch_apply。dispatch_apply按照指定的次數(shù)將指定

的任務(wù)追加到指定的隊列中,并等待全部隊列執(zhí)行結(jié)束。

我們可以利用并發(fā)隊列進行異步執(zhí)行。比如說遍歷

?0~5 這 6 個數(shù)字,for 循環(huán)的做法是每次取出一個元素,逐個遍歷。dispatch_apply?可以 在多個線程中同時(異步)遍歷多個

數(shù)字。

GCD 隊列組:dispatch_group

有時候我們會有這樣的需求:分別異步執(zhí)行2個耗時任務(wù),然后當2個耗時任務(wù)都執(zhí)行完畢后再回到主線程執(zhí)行任務(wù)。這時候我

們可以用到 GCD 的隊列組。

調(diào)用隊列組的dispatch_group_async先把任務(wù)放到隊列中,然后將隊列放入隊列組中。或者使用隊列組的

dispatch_group_enter、dispatch_group_leave組合來實現(xiàn)dispatch_group_async。

調(diào)用隊列組的?dispatch_group_notify?回到指定線程執(zhí)行任務(wù)。或者使用?dispatch_group_wait?回到當前線程繼續(xù)向下執(zhí)行(會

阻塞當前線程)。

// 等待上面的任務(wù)全部完成后,會往下繼續(xù)執(zhí)行(會阻塞當前線程)

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

dispatch_group_enter?標志著一個任務(wù)追加到 group,執(zhí)行一次,相當于 group 中未執(zhí)行完畢任務(wù)數(shù) +1

dispatch_group_leave?標志著一個任務(wù)離開了 group,執(zhí)行一次,相當于 group 中未執(zhí)行完畢任務(wù)數(shù) -1。

當 group 中未執(zhí)行完畢任務(wù)數(shù)為0的時候,才會使?dispatch_group_wait?解除阻塞,以及執(zhí)行追加到?dispatch_group_notify?中

的任務(wù)。

GCD 信號量:dispatch_semaphore

dispatch_semaphore_create:創(chuàng)建一個 Semaphore 并初始化信號的總量

dispatch_semaphore_signal:發(fā)送一個信號,讓信號總量加 1

dispatch_semaphore_wait:可以使總信號量減 1,信號總量小于 0 時就會一直等待(阻塞所在線程),否則就可以正常執(zhí)行。

Dispatch Semaphore 在實際開發(fā)中主要用于:保持線程同步,將異步執(zhí)行任務(wù)轉(zhuǎn)換為同步執(zhí)行任務(wù)

保證線程安全,為線程加鎖

我們在開發(fā)中,會遇到這樣的需求:異步執(zhí)行耗時任務(wù),并使用異步執(zhí)行的結(jié)果進行一些額外的操作。換句話說,相當于,將

將異步執(zhí)行任務(wù)轉(zhuǎn)換為同步執(zhí)行任務(wù)。比如說:AFNetworking 中 AFURLSessionManager.m 里面的tasksForKeyPath:方法。

通過引入信號量的方式,等待異步執(zhí)行任務(wù)結(jié)果,獲取到 tasks,然后再返回該 tasks。

11. Masony布局中使用了block?為什么沒有造成循環(huán)引用?

查看masonry源碼可以看到究竟:masonry中設(shè)置布局的方法中的block對象并沒有被View所引用,而是直接在方法內(nèi)部同步執(zhí)

行,執(zhí)行完以后block將釋放,其中捕捉的外部變量的引用計數(shù)也將還原到之前。

12. 在cell多列布局中,每列有多個lable,假如后臺數(shù)據(jù)返回的數(shù)量不一 ,怎么保證cell的高度是按最大lable布局?

13. 說一下iOS中主流的設(shè)計模式 ,

目前常用的幾種設(shè)計模式:代理模式、觀察者模式、MVC模式、單例模式、策略模式、工廠模式、MVVM

14. JSON解析的原理 ?

Runtime運行時機制 利用class_copyPropertyList??property_getName等方法

15. 簡述一下響應(yīng)者鏈?假如一個viewA 上有一個viewB,且viewB的面積大于viewA 點擊viewB且不和viewA重疊的區(qū)域 是否會響應(yīng) 為什么?

響應(yīng)者對象UIResponder,只有繼承UIResponder的的類,才能處理事件。

1.當iOS程序中發(fā)生觸摸事件后,系統(tǒng)會將事件加入到UIApplication管理的一個任務(wù)隊列中

2.UIApplication將處于任務(wù)隊列最前端的事件向下分發(fā)。即UIWindow。

3.UIWindow將事件向下分發(fā),即UIView。

4.UIView首先看自己是否能處理事件,觸摸點是否在自己身上。如果能,那么繼續(xù)尋找子視圖。

5.遍歷子控件,重復以上兩步。

6.如果沒有找到,那么自己就是事件處理者。如果

7.如果自己不能處理,那么不做任何處理。

其中 UIView不接受事件處理的情況主要有以下三種

1)alpha <0.01

2)userInteractionEnabled = NO

3.hidden = YES.

怎么尋找最合適的view:

此方法返回的View是本次點擊事件需要的最佳View

-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event

// 判斷一個點是否落在范圍內(nèi)

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,626評論 1 32
  • 1.設(shè)計模式是什么? 你知道哪些設(shè)計模式,并簡要敘述?設(shè)計模式是一種編碼經(jīng)驗,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,294評論 0 12
  • 1.設(shè)計模式是什么? 你知道哪些設(shè)計模式,并簡要敘述? 設(shè)計模式是一種編碼經(jīng)驗,就是用比較成熟的邏輯去處理某一種類...
    司馬DE晴空閱讀 1,458評論 0 7
  • 1.NSTimer不準時的原因:(1).RunLoop循環(huán)處理時間,每次循環(huán)是固定時間,只有在這段時間才會去查看N...
    稻春閱讀 1,360評論 0 3
  • 實務(wù)技能課程包括:基礎(chǔ)課程(初始咨詢+咨詢進階)+帶教課程(經(jīng)典個案演示帶教)+內(nèi)功訓練(自我訓練和語言精細化訓練...
    田凱心理閱讀 426評論 0 1

友情鏈接更多精彩內(nèi)容