7月,iOS求職跳槽的相對較少,能在這個時間段求職的,不是被迫,就是對本身的技術很自信;
針對7月,特別總結了一份iOS常見大廠面試題(上);gitiOS面試題分爲 上、中、下三部分,方便你們觀看;github
請先本身
答一答
!面試
話很少說;直接上題
本文收錄:公衆號【iOS進階寶典《iOS底層面試題(上篇)》】安全
KVC
能夠經過key
直接訪問對象的屬性,或者給對象的屬性賦值,這樣能夠在運行時動態的訪問或修改對象的屬性markdown
可能有不少小夥伴還不太清楚,動靜態庫的開發,這裏推薦一篇博客:iOS-製做.a靜態庫SDK和使用.a靜態庫數據結構
若是咱們存在三方庫衝突就會保存:duplicate symbol _OBJC_IVAR_$_xxxx in:
多線程
目前見效最快的就是把**.framework**
選中,**taggert Membership**
的對勾取消掉,就編譯沒有問題了,可是後續的其餘問題可能還會出現併發
我想說的是像這種開源的使用率很高的源代碼本不該該包含在lib庫中,就算是你要包含那也要改個名字是吧。不過沒辦法如今人家既然包含,咱們就只有想辦法分離了異步
mkdir armv7:建立臨時文件夾
lipo libALMovie.a -thin armv7 -output armv7/armv7.a:取出armv7平臺的包
asyncar -t armv7/armv7.a:查看庫中所包含的文件列表
cd armv7 && ar xv armv7.a:解壓出object file(即.o後綴文件)
rm ALButton.o:找到衝突的包,刪除掉(此步能夠屢次操做)
cd … && ar rcs armv7.a armv7/*.o:從新打包object file
- 多平臺的SDK的話,須要屢次操做第4步。
操做完成後,合併多個平臺的文件爲一個.a文件:lipo -create armv7.a arm64.a -output new.a
- 將修改好的文件, 拖拽到原文件夾下,替換原文件便可。
好比在內存中維護一份數據,有多處地方可能會同時操做這塊數據,怎麼能保證數據安全?
這道題目總結獲得要知足如下三點:
- 1.讀寫互斥
- 2.寫寫互斥
- 3.讀讀併發
@implementation KCPerson- (instancetype)init
{
if (self = [super init]) {
_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);
_dic = [NSMutableDictionary dictionary];
}
return self;
}- (void)kc_setSafeObject:(id)object forKey:(NSString *)key{
key = [key copy];
dispatch_barrier_async(_concurrentQueue, ^{
[_dic setObject:object key:key];
});
}- (id)kc_safeObjectForKey::(NSString )key{
__block NSString temp;
dispatch_sync(_concurrentQueue, ^{
temp =[_dic objectForKey:key];
});
return temp;
}
@end- 首先咱們要維繫一個GCD 隊列,最好不用全局隊列,畢竟你們都知道全局隊列遇到柵欄函數是有坑點的,這裏就不分析了!
- 由於考慮性能 死鎖 堵塞的因素不考慮串行隊列,用的是自定義的併發隊列!
_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);
首先咱們來看看讀操做:kc_safeObjectForKey
咱們考慮到多線程影響是不能用異步函數的!說明:
name
線程3 獲取 age
若是由於異步併發,致使混亂 原本讀的是name
結果讀到了age
咱們容許多個任務同時進去! 可是讀操做須要同步返回,因此咱們選擇:同步函數
(讀讀併發)
函數調用者能夠自由傳遞一個
NSMutableString
的key
,而且可以在函數返回後修改它。所以咱們必須對傳入的字符串使用copy
操做以確保函數可以正確地工做。若是傳入的字符串不是可變的(也就是正常的NSString
類型),調用copy
基本上是個空操做。
這裏咱們選擇dispatch_barrier_async
, 爲何是柵欄函數而不是異步函數或者同步函數,下面分析:
爲何不是異步函數?應該很容易分析,畢竟會產生混亂!
A: atomic的實現機制
atomic
是property
的修飾詞之一,表示是原子性的,使用方式爲@property(atomic)int age
;此時編譯器會自動生成getter/setter
方法,最終會調用objc_getProperty
和objc_setProperty
方法來進行存取屬性。若此時屬性用
atomic
修飾的話,在這兩個方法內部使用os_unfair_lock
來進行加鎖,來保證讀寫的原子性。鎖都在PropertyLocks
中保存着(在iOS平臺會初始化8個,mac平臺64個),在用以前,會把鎖都初始化好,在須要用到時,用對象的地址加上成員變量的偏移量爲key
,去PropertyLocks
中去取。所以存取時用的是同一個鎖,因此atomic能保證屬性的存取時是線程安全的。- 注:因爲鎖是有限的,不用對象,不一樣屬性的讀取用的也多是同一個鎖
B: atomic爲何不能保證絕對的線程安全?
atomic
在getter/setter
方法中加鎖,僅保證了存取時的線程安全,假設咱們的屬性是@property(atomic)NSMutableArray *array
;可變的容器時,沒法保證對容器的修改是線程安全的.- 在編譯器自動生產的
getter/setter
方法,最終會調用objc_getProperty
和objc_setProperty
方法存取屬性,在此方法內部保證了讀寫時的線程安全的,當咱們重寫getter/setter
方法時,就只能依靠本身在getter/setter
中保證線程安全
Autoreleasepool
是由多個AutoreleasePoolPage
以雙向鏈表的形式鏈接起來的.Autoreleasepool
的基本原理:在每一個自動釋放池建立的時候,會在當前的AutoreleasePoolPage
中設置一個標記位,在此期間,當有對象調用autorelsease
時,會把對象添加 AutoreleasePoolPage
中
hotPage
,當自動釋放池pop時,從最下面依次往上pop,調用每一個對象的release
方法,直到遇到標誌位。AutoreleasePoolPage
結構以下
class AutoreleasePoolPage { magic_t const magic; id *next;//下一個存放autorelease對象的地址 pthread_t const thread; //AutoreleasePoolPage 所在的線程 AutoreleasePoolPage * const parent;//父節點 AutoreleasePoolPage *child;//子節點 uint32_t const depth;//深度,也能夠理解爲當前page在鏈表中的位置 uint32_t hiwat; }
喜歡的小夥伴記得點贊喔~
收藏等於白嫖,點贊纔是真情ღ( ´・ᴗ・` )ღ