隨身帶上mac與源碼進(jìn)行學(xué)習(xí)與介紹
參考:
http://www.infocool.net/kb/IOS/201609/185104.html
http://www.infocool.net/kb/IOS/201609/185061.html
屬性
- atomic艰垂,nonatomic
參考:http://www.reibang.com/p/7288eacbb1a2
atomic會(huì)讓編譯器在setter科侈、getter方法中創(chuàng)建lock鎖涵卵;保證讀寫安全庙曙,但不能保證線程其他操作安全霹琼;
nonatomic不就行安全處理点额,不生成互斥枷鎖代碼咪啡,效率比較高坷随; - assign, weak 修飾對(duì)象有啥區(qū)別
assign只是指針賦值房铭,不做安全處理,若是對(duì)象釋放再次訪問温眉,相當(dāng)于訪問野指針缸匪,導(dǎo)致crash;
weak的對(duì)象若是釋放就會(huì)置為nil类溢,再次訪問不會(huì)出現(xiàn)問題豪嗽,比較安全;
函數(shù)直接調(diào)用與performSelector的區(qū)別
本事都是發(fā)送消息調(diào)用一個(gè)方法豌骏;
直接調(diào)用編譯區(qū)間如果不存在會(huì)報(bào)錯(cuò)龟梦,performSelector不會(huì)報(bào)錯(cuò)
performSelector可以調(diào)用運(yùn)行時(shí)動(dòng)態(tài)進(jìn)入的method,但是如果調(diào)用不存的selector會(huì)報(bào)unrecognized selector sent to instance導(dǎo)致crash
isKindOfClass 與 isMemberOfClass的區(qū)別
isKIndOfClass 返回一個(gè)實(shí)例是否是一個(gè)類或者其繼承類窃躲;
isMemberOfClass 返回一個(gè)實(shí)例是否是一個(gè)類计贰,不包括其繼承類;
iOS object 原理蒂窒?
What this says is: any structure which starts with a pointer to a Class
structure can be treated as an objc_object.
一個(gè)OC的類其實(shí)也是一個(gè)對(duì)象躁倒;
-
meta-class怎么理解?
meta class是一個(gè)類對(duì)象的類洒琢,metaClass的isa全指向root class秧秉;meta-class像Class一樣,也是一個(gè)對(duì)象衰抑;
當(dāng)向一個(gè)對(duì)象發(fā)送消息時(shí)象迎,runtime會(huì)在這個(gè)對(duì)象所屬的那個(gè)類的方法列表中查找;
當(dāng)向一個(gè)類發(fā)送消息時(shí),runtime會(huì)在這個(gè)類的meta-class的方法列表中查找砾淌;
isa指針有什么作用
查看NSObject對(duì)象的定義啦撮,可以看出它有一個(gè)‘struct objc_class’的isa變量,struct objc_class中包含有isa指針汪厨,成員變量赃春,方法列表等,如下:
typedef struct objc_class *Class;
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
可以看出劫乱,每一個(gè)類對(duì)象中都有一個(gè)方法列表织中,方法列表中記錄著方法的名稱,實(shí)現(xiàn)及參數(shù)類型衷戈,其實(shí)selector本質(zhì)就是方法名稱狭吼,通過這個(gè)方法名稱就可以再方法列表中找到對(duì)應(yīng)的方法實(shí)現(xiàn);
@property后面可以有哪些修飾符脱惰?
readwrite, atomic, assign是默認(rèn)修飾;
--> 讀寫屬性:readwrite readonly
--> setter屬性:assign retain copy weak strong
--> 原子屬性:atomic nonatomic
--> getter/setter修飾符:@property (setter=setName, getter=getName) NSString *name;
參考:Apple 官方文檔說明
消息轉(zhuǎn)發(fā)流程
- resolveInstanceMethod 可給類動(dòng)態(tài)添加方法窿春,返回YES后再次調(diào)用resolve
- forwardingTargetForSelector 轉(zhuǎn)發(fā)給其他的一個(gè)對(duì)象
-
forwardInvocation 可以將anInvocation轉(zhuǎn)發(fā)給多個(gè)對(duì)象
hitTest / pointInside
先調(diào)用hitTest檢查窗口是否響應(yīng)事件拉一,然后調(diào)用pointInside檢測是否在當(dāng)前窗口內(nèi);
hitTest:withEvent:在內(nèi)部首先會(huì)判斷該視圖是否能響應(yīng)觸摸事件旧乞,如果不能響應(yīng)蔚润,返回nil,表示該視圖不響應(yīng)此觸摸事件尺栖。然后再調(diào)用pointInside:withEvent:(該方法用來判斷點(diǎn)擊事件發(fā)生的位置是否處于當(dāng)前視圖范圍內(nèi))嫡纠。如果pointInside:withEvent:返回NO,那么hiteTest:withEvent:也直接返回nil延赌。
如果pointInside:withEvent:返回YES除盏,則向當(dāng)前視圖的所有子視圖發(fā)送hitTest:withEvent:消息,所有子視圖的遍歷順序是從最頂層視圖一直到到最底層視圖挫以,即從subviews數(shù)組的末尾向前遍歷者蠕。直到有子視圖返回非空對(duì)象或者全部子視圖遍歷完畢;
一個(gè)觸摸事件 多個(gè)響應(yīng)者同時(shí)處理該事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"touchBegan---%@", [self class]);
[super touchesBegan:touches withEvent:event];
}
怎么用copy關(guān)鍵字掐松?
copy的使用比較智能:
假若一個(gè)對(duì)象是不可變的踱侣,copy返回的是自身,計(jì)數(shù)器加1大磺;
假若是可變的對(duì)象抡句,那么是內(nèi)存拷貝,返回的是不可變對(duì)象杠愧;
使用案例:
@property (nonatomic, copy) NSString *pStr;
如果設(shè)置這個(gè)變量的屬性為strong待榔,那么如果外部賦值給它的對(duì)象是mutable string,外部mutable string改變的話流济,這個(gè)變量也會(huì)跟著變化究抓;此時(shí)要使用copy屬性盔几,外部mutable string變化也不會(huì)影響當(dāng)前變量;
所以使用NSString屬性時(shí)候最好聲明為copy而不是strong质欲,否則可能外部導(dǎo)致變量內(nèi)容發(fā)生變化郭脂;
When you declare a NSString property it is best to use copy instead of strong. In fact this is true for any immutable class that conforms to the NSCopying protocol like NSNumber, NSArray, NSSet and others. All these classes I mentioned also have a mutable version. You want to use copy because your NSString property can be passed either a NSString or a NSMutableString instance. If you’re being passed a NSMutableString instance then that means the value of your string may change behind your back. Let’s consider this example:
- NSMutableArray類型屬性變量為什么不能用copy?
因?yàn)閏opy屬性表示要使用NSMutableArray 的 copy函數(shù)橘茉,這個(gè)copy返回的是NSArray類型變量工腋,如果對(duì)這個(gè)屬性變量進(jìn)行可變操作就會(huì)導(dǎo)致程序崩潰,因?yàn)閷?shí)際操作的是NSArray畅卓;
明白copy屬性到底做了什么擅腰?一個(gè)屬性標(biāo)記了coy,當(dāng)你調(diào)用他的setter方法翁潘,他會(huì)建立一個(gè)索引計(jì)數(shù)器為1的對(duì)象趁冈,然后釋放就對(duì)象;
copy只是淺復(fù)制拜马,NSMutableArray的copy返回的是一個(gè)NSArray對(duì)象渗勘;要想深copy可以使用mutableCopy;
參考:https://segmentfault.com/q/1010000004359262?_ea=606650
實(shí)際測試(ARC模式下):可以給賦值俩莽,但是改變會(huì)崩潰旺坠,因?yàn)閷?shí)際上copy的是NSArray對(duì)象
@property (nonatomic, copy) NSMutableArray *mArr;
self.mArr = [NSMutableArray new];
[self.mArr addObject:@"1"]; //報(bào)錯(cuò)
如何讓自己的類用copy修飾符?如何重寫帶copy關(guān)鍵字的setter扮超?
重寫帶copy關(guān)鍵字的setter只需要在setter函數(shù)里調(diào)用對(duì)象的copy即可;
若想要自己所寫的對(duì)象具有拷貝功能取刃,需要實(shí)現(xiàn)NSCopying協(xié)議,有必要也實(shí)現(xiàn)NSMutableCopying協(xié)議出刷;NSCopying的協(xié)議方法為copyWithZone,內(nèi)容實(shí)現(xiàn)為:
- (id)copyWithZone:(NSZone *)zone {
// 需調(diào)用allocWithZone
MyClass *copy = [[self class] allocWithZone:zone];
// copy class中的屬性數(shù)據(jù)等
return copy;
}
PS: copy定義在NSObject中璧疗,要實(shí)現(xiàn)NSCopying協(xié)議才能調(diào)用,copy的文檔說明如下:
This is a convenience method for classes that adopt the NSCopying protocol. An exception is raised if there is no implementation for copyWithZone:.
NSObject does not itself support the NSCopying protocol. Subclasses must support the protocol and implement the copyWithZone: method.
property的本質(zhì)是什么馁龟?
@property = ival + getter + setter病毡, 由編譯器自動(dòng)生成;
property的只是給編譯器看的一種指令屁柏,可以幫助我們管理引用計(jì)數(shù)器啦膜,可以編譯之后為你生成ivar變量以及響應(yīng)的getter與setter方法;如果指定了retain/copy/assign淌喻,也會(huì)做出相應(yīng)處理僧家;
protocol與category中如何使用@property
protocol中定義了屬性,說明需要代理實(shí)現(xiàn)setter與getter方法裸删,否則會(huì)報(bào)unrecognized selector錯(cuò)誤八拱;
category中使用屬性,需要使用runtime函數(shù)set或者get變量:
- (NSString *)name {
objc_getAssociateObject(self, @"name");
}
- (void)setName:(NSString *)str {
objc_setAssociateObject(self, @"name", str,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
runtime如何實(shí)現(xiàn)weak?
參考:《objc高級(jí)編程》
當(dāng)我們初始化一個(gè)weak變量時(shí),runtime會(huì)調(diào)用objc_initWeak函數(shù)將weak變量存儲(chǔ)在weak表中, key是weak賦值對(duì)象的內(nèi)存地址肌稻;
weak表:一個(gè)弱引用表清蚀,實(shí)現(xiàn)為一個(gè)weak_table_t結(jié)構(gòu)體,存儲(chǔ)了對(duì)象相關(guān)的所有的弱引用信息爹谭,weak_entries成員變量負(fù)責(zé)維護(hù)和存儲(chǔ)指向一個(gè)對(duì)象的所有弱引用hash表枷邪;
對(duì)象釋放流程如下:
1.調(diào)用objc_release;
2.計(jì)數(shù)器變?yōu)?诺凡,執(zhí)行dealloc东揣;
3.在dealloc中,調(diào)用_objc_rootDealloc函數(shù)腹泌;
4.在_objc_rootDealloc中嘶卧,調(diào)用了object_dispose函數(shù);
5.調(diào)用objc_destructInstance;
6.最后調(diào)用objc_clear_deallocating -->
objc_clear_deallocating這個(gè)函數(shù)首先找出對(duì)象的weak_entry_t鏈表凉袱,然后挨個(gè)將弱引用置為nil芥吟,最后清理對(duì)象的記錄;
load 與 initialize
PS:在Compile Sources中,文件的排放順序就是起裝載順序专甩,自然也就是load方法調(diào)用的順序钟鸵;
initialize方法是在第一次給某個(gè)類發(fā)送消息時(shí)調(diào)用,并且只會(huì)調(diào)用一次配深;
UITableView優(yōu)化携添?
UITableView原理
UITableViewCell的重用機(jī)制能夠提高cell的使用效率嫁盲,減少了內(nèi)存消耗篓叶;
UITableview是先計(jì)算cell的高度確定將要顯示的cell(所有cell的height都會(huì)刷新),再顯示cell(只刷新顯示的cell)羞秤,所以主要優(yōu)化在 tableView:heightForRowAtIndexPath 與 tableView:cellForRowAtIndexPath 方法缸托;
heightForRowAtIndexPath是調(diào)用最頻繁的方法;
- height計(jì)算與cell填充分離開瘾蛋,不要重疊俐镐;
- 緩沖數(shù)據(jù)直接讀取,數(shù)據(jù)不需要?jiǎng)討B(tài)更新的哺哼,不需要每次計(jì)算佩抹;
- 直接繪繪制控件(在cell上添加系統(tǒng)控件的時(shí)候,實(shí)質(zhì)上系統(tǒng)都需要調(diào)用底層的接口進(jìn)行繪制取董,當(dāng)我們添加大量控件時(shí)棍苹,對(duì)資源的開銷很大,所以可以直接繪制茵汰,提高效率)枢里;
//異步繪制
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGRect rect = [_data[@"frame"] CGRectValue];
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
//整個(gè)內(nèi)容的背景
[[UIColor colorWithRed:250/255.0 green:250/255.0 blue:250/255.0 alpha:1] set];
CGContextFillRect(context, rect);
//內(nèi)容如果是圖文混排,就添加View,用CoreText繪制
//圖文混排栏豺,可以查閱Google彬碱,研究下CoreText,內(nèi)容比較多
[self drawText];
}
- 滑動(dòng)很快時(shí)奥洼,按需加載目標(biāo)范圍內(nèi)的cell巷疼,可提高流暢度;在大量圖片展示時(shí)溉卓,網(wǎng)絡(luò)加載比較有效(SDWebImage已經(jīng)實(shí)現(xiàn)異步加載)皮迟;
- 盡量使所有的view opaque(不透明),包括cell自身桑寨;
- 盡量少用或不用透明圖層(非常耗時(shí))伏尼;
- 避免使用圓角、陰影尉尾、遮罩等屬性爆阶;
- 如果cell內(nèi)顯示的內(nèi)容矮子web,使用異步加載沙咏,緩存請求結(jié)果辨图;
- 減少subviews的數(shù)量;
- 在heightForRowAtIndexPath:中盡量不使用cellForRowAtIndexPath:肢藐,如果你需要用到它故河,只用一次然后緩存結(jié)果;
- 盡量少用addView給Cell動(dòng)態(tài)添加View吆豹,開始初始化時(shí)添加鱼的,通過hide來控制顯示;
- 想提高效率痘煤,還是手動(dòng)寫cell凑阶,不要用xib或storyboard(看情況而論);
- 將GPU的部分渲染轉(zhuǎn)給CPU衷快,GPU與CPU的合理分配使用(了解gitbook上圖像渲染的知識(shí)點(diǎn))宙橱;
- 在drawRect中使用Core Graphics 繪制控件;
參考:
10 tips to speed up your table view
stack overflow
GCD 任務(wù)控制蘸拔?
Mac OS X 10.6, iOS4 以上可以使用师郑;
- 完成一些任務(wù)后再完成另一個(gè)任務(wù)?
使用 dispatch_group_async / dispatch_group_notify; - dispatch_barrier_async使用调窍?
是在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行宝冕,而且它后面的任務(wù)等它執(zhí)行完成之后才會(huì)執(zhí)行; - dispatch_apply使用陨晶?
執(zhí)行某個(gè)代碼塊N次: dispatch_apply(N, queue ^(){ /* code */ }); - 與NSOperation的區(qū)別猬仁?
參考:
https://www.appcoda.com/ios-concurrency/
https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/
http://www.reibang.com/p/fe1fec3d198f
Core Data 操作及多線程處理
CoreData實(shí)際上是對(duì)SQLite的封裝帝璧,提供了更高級(jí)的持久化方式;
CoreData操作簡單方便湿刽,但是存儲(chǔ)性能一般的烁,批處理數(shù)據(jù)不好,而且對(duì)于多線程的支持也不太好诈闺;
Core Data 堆棧
對(duì)象圖管理
持久化
-
相關(guān)類
參考:
Apple CoreData
Core Data 概述
一個(gè)完整的Core Data應(yīng)用
objc.io core-data
ios8 swift core data tutorial
NSOperation 自定義渴庆?
參見AFNetWorking的 AFHTTPRequestOperation.h
重寫 main 函數(shù):處理耗時(shí)操作后,返回回調(diào)處理雅镊;
運(yùn)行時(shí)添加變量襟雷?
不能向編譯后得到的類中增加實(shí)例變量,能向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量仁烹;
because:
- 編譯后的類已經(jīng)注冊在runtime中耸弄,類結(jié)構(gòu)中的objc_ivar_list實(shí)例變量的鏈表和instance_size實(shí)例變量的內(nèi)存大小已經(jīng)確定,所以不能向存在的類中添加實(shí)例變量卓缰;
- 運(yùn)行時(shí)創(chuàng)建的類可以添加實(shí)例變量计呈,調(diào)用class_addIvar函數(shù)但是得在調(diào)用objc_allocateClassPair之后,objc_registerClassPair之前征唬,原因同上捌显;
runloop與線程?
runloop是為了線程而生总寒,沒有線程就沒有存在的必要扶歪;內(nèi)部是一個(gè)do while循環(huán)類似的結(jié)構(gòu),比如一個(gè)event消息事件處理線程摄闸;
- 主線程的runloop默認(rèn)是啟動(dòng)的善镰;
- 其他線程,runloop默認(rèn)是沒有啟動(dòng)的贪薪,如果需要更多的線程交互可以手動(dòng)配置和啟動(dòng)媳禁,只是執(zhí)行一個(gè)長時(shí)間的已確定任務(wù)則不需要眠副;
- 任何一個(gè)cocoa程序的線程中画切,都可以通過 [NSRunLoop currentRunLoop] 獲取到當(dāng)前線程的runloop;
《Objective-C之run loop詳解》
《深入理解RunLoop》
runloop的mode作用囱怕?
mode主要用來指定事件在運(yùn)行循環(huán)中的優(yōu)先級(jí)霍弹;
- NSTimer 與 ScrollView 的問題
RunLoop只能運(yùn)行在一種mode下,如果要換mode娃弓,當(dāng)前的loop也需要停下重啟成新的典格;ScrollView滾動(dòng)過程中會(huì)從NSDefaultRunLoopMode切換到UITrackingRunLoopMode來保證ScrollView的流暢滑動(dòng);如果同時(shí)有NSTimer台丛,那么就會(huì)在滑動(dòng)的時(shí)候因?yàn)榍袚Qmode導(dǎo)致NSTimer將不再被調(diào)用耍缴;所以需要將timer設(shè)置為common mode:
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSRunLoopCommonModes]; - NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默認(rèn)砾肺,空閑狀態(tài)
- UITrackingRunLoopMode:ScrollView滑動(dòng)時(shí)
- UIInitializationRunLoopMode:啟動(dòng)時(shí)
- NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
autoreleasepool
autoreleas對(duì)象釋放機(jī)制?
- 指定autoreleasepool結(jié)束時(shí)(當(dāng)前作用域大括號(hào)結(jié)束時(shí))防嗡,對(duì)象釋放变汪;
- 系統(tǒng)自動(dòng)釋放:autorelease對(duì)象出了作用域之后,會(huì)被添加到最近一次創(chuàng)建的自動(dòng)釋放池中蚁趁,并會(huì)在當(dāng)前的runloop迭代結(jié)束時(shí)釋放裙盾;
main中的autoreleasepool如果不釋放,遲早會(huì)被撐滿他嫡,所以在一次完整的運(yùn)行循環(huán)結(jié)束之前番官,對(duì)象會(huì)被銷毀;
如果在一個(gè)vc的viewdidload中國創(chuàng)建一個(gè)autorelease對(duì)象钢属,那么對(duì)象在viewdidapper方法執(zhí)行之前就被銷毀了徘熔;
當(dāng)自動(dòng)釋放池被銷毀或耗盡時(shí),會(huì)向自動(dòng)釋放池的所有對(duì)象發(fā)送release消息淆党,釋放自動(dòng)釋放池中的所有對(duì)象近顷;
autoreleasepool的實(shí)現(xiàn):
主要通過三個(gè)函數(shù):
- objc_autoreleasepoolPush
- objc_autoreleasepoolPop
- objc_autorelease
《黑幕背后的Autorelease》
BAD_ACCESS發(fā)生在什么情況?
- 訪問量了野指針
- 對(duì)已經(jīng)釋放的對(duì)象執(zhí)行了release
- 訪問已經(jīng)釋放對(duì)象的成員變量或發(fā)消息
- 死循環(huán)
block內(nèi)修改外部變量
原則:block不允許修改外部變量的值宁否,是指占中指針的內(nèi)存地址窒升;棧區(qū)是紅燈區(qū)不可修改,堆區(qū)才是綠燈區(qū)可修改慕匠;
使用__block修飾外部變量饱须,實(shí)際上是把變量從棧區(qū)修改到堆區(qū)中了,可使用例子驗(yàn)證:
__block int a = 1;
NSLog(@"%p", &a); // 在棧區(qū)
void (^foo)(void) = ^ {
a = 2;
NSLog(@"%p", &a); //在堆區(qū) 1
};
NSLog(@"%p", &a); //在堆區(qū) 2
foo();
如何手動(dòng)觸發(fā)KVO
- KVO原理
當(dāng)你觀察一個(gè)對(duì)象時(shí)台谊,一個(gè)新的類會(huì)被動(dòng)態(tài)創(chuàng)建蓉媳。
這個(gè)類繼承自該對(duì)象的原本的類,并重寫了被觀察屬性的 setter 方法;
重寫的 setter 方法會(huì)負(fù)責(zé)在調(diào)用原 setter 方法之前和之后锅铅,通知所有觀察對(duì)象:值的更改;
最后通過 isa 混寫(isa-swizzling)把這個(gè)對(duì)象的 isa 指針
( isa 指針告訴 Runtime 系統(tǒng)這個(gè)對(duì)象的類是什么 )
指向這個(gè)新創(chuàng)建的子類酪呻,對(duì)象就神奇的變成了新創(chuàng)建的子類的實(shí)例;
鍵值觀察通知依賴于NSObject的兩個(gè)方法:willChangeValueForKey和didChangeValueForKey盐须;
系統(tǒng)會(huì)在setValue(成員變量賦值)或者setter(屬性賦值)中以某種方法在中間插入wilChangeValueForKey:
玩荠、 didChangeValueForKey:
和 observeValueForKeyPath:ofObject:change:context:
的調(diào)用;
什么方式贼邓?通過isa-swizzling阶冈;
Manual Change Notification---Apple 官方文檔
- 如果需要主動(dòng)觸發(fā)kvo,手動(dòng)調(diào)用這兩個(gè)函數(shù)包裹賦值塑径,就可以實(shí)現(xiàn)手動(dòng)觸發(fā)了女坑;
kvo只能觀察基本數(shù)據(jù)類型的內(nèi)容或者對(duì)象的指針變化,如果NSMutableArray 或者 NSMutableString 內(nèi)容變化是無法觀察到的统舀,所以當(dāng)內(nèi)容變化時(shí)需要手動(dòng)觸發(fā)匆骗;
《如何自己動(dòng)手實(shí)現(xiàn) KVO》
IBOutlet連出來的視圖屬性為什么可以被設(shè)置成weak劳景?
Should IBOutlets be strong or weak under ARC?
視圖本身已經(jīng)對(duì)它有一個(gè)強(qiáng)引用了;
如何調(diào)試BAD_ACCESS碉就?zombie object
- Enable Zombie Objects枢泰;
- 全局?jǐn)帱c(diǎn)開啟;
- xcode7的 Address Sanitizer铝噩;
- 重寫object的respondsToSelector方法衡蚂,顯示出現(xiàn)bad access前最后訪問的一個(gè)object;
LLVM原理及優(yōu)化骏庸?
LLVM:Low Level Virtual Machine 底層虛擬機(jī)
LLVM是架構(gòu)編譯器的框架系統(tǒng)毛甲,以C++編寫而成,用于優(yōu)化以任意程序語言編寫的程序的編譯時(shí)間具被、鏈接時(shí)間玻募、運(yùn)行時(shí)間及空閑時(shí)間,對(duì)開發(fā)者保值開放一姿;LLVM計(jì)劃啟動(dòng)于2000年七咧,2006年加盟Apple Inc;Apple也是LLVM計(jì)劃的主要資助者叮叹;
Clang是LLVM的一個(gè)編譯器前端艾栋,它目前支持C/C++/Object-C以及Object-C++等變成余元;clang對(duì)源程序進(jìn)行詞法分析和語義分析蛉顽,并將分析結(jié)果轉(zhuǎn)換為抽象語法樹蝗砾,最后使用LLVM作為后端代碼生成器;
meituan 面試部分
-
函數(shù)式編程的定義携冤,ios怎么用悼粮?
參考:https://www.zhihu.com/question/28292740
函數(shù)式語言:scala 、erlang
函數(shù)式編程是一種邏輯式編程曾棕,關(guān)心數(shù)據(jù)的映射(對(duì)應(yīng)關(guān)系的函數(shù))扣猫,而不是解決問題的步驟;嚴(yán)格意義的函數(shù)式編程意味著不使用可變的變量翘地,賦值申尤,循環(huán)和其他命令式控制結(jié)構(gòu)進(jìn)行編程;
函數(shù)式語言是面向數(shù)學(xué)的抽象子眶,更接近人的語言瀑凝,而不是機(jī)器語言序芦,代碼會(huì)比較簡潔臭杰,也更容易被理解;描述做什么谚中,而不是怎么做渴杆;
特點(diǎn):變量不可變性寥枝,函數(shù)作為主體;
不變性好處是:不共享狀態(tài)不會(huì)造成資源征用磁奖,也不需要用鎖來保護(hù)可變狀態(tài)囊拜,也不會(huì)出現(xiàn)思索,可以更好的并發(fā)起來比搭;
因?yàn)椴豢勺児邗危詅or while循環(huán)(需要可變狀態(tài)跳出循環(huán))不可用;因此函數(shù)式語言里就只能使用遞歸來解決迭代問題身诺,使得函數(shù)式編程嚴(yán)重依賴遞歸蜜托;
Masonry庫使用的語法就是函數(shù)式編程,可查看源碼實(shí)現(xiàn)霉赡;
實(shí)際調(diào)用函數(shù)返回的是一個(gè)block函數(shù)橄务,再對(duì)block函數(shù)進(jìn)行參數(shù)調(diào)用,通過block函數(shù)式可實(shí)現(xiàn)鏈?zhǔn)骄幊萄鳎纾?br> -
MVVM你怎么組織蜂挪,RAC的核心方法是什么?
參考: https://www.objccn.io/issue-13-1/
MVC的使用會(huì)使controller中集中大量代碼嗓化,臃腫不堪棠涮;
什么樣的內(nèi)容才應(yīng)該放到controller中?不便復(fù)用的代碼放在其中刺覆;
如何對(duì)viewcontroller瘦身故爵?《Lighter View Controllers》
MVVM將controller里面過于臃腫的邏輯抽取出來,形成新的可復(fù)用模塊或架構(gòu)隅津;
那么诬垂,把原來viewcontroller層的業(yè)務(wù)邏輯和頁面邏輯等剝離出來放到viewmodel層,就形成了 model-view-viewmodel結(jié)構(gòu)伦仍;保證了業(yè)務(wù)與UI分離结窘;
viewmodel層處理表示邏輯,將controller中的邏輯提取出來充蓝;
model只用來表示數(shù)據(jù)模型隧枫;
view只用來進(jìn)行數(shù)據(jù)顯示及交互;
與MVC兼容帶來了更輕量級(jí)的 View Controller谓苟;
kvo可以監(jiān)聽model的變化官脓,時(shí)而更新view;
***RAC**** Reactivecocoa
參考:http://www.reibang.com/p/3beb21d5def2
https://zhuanlan.zhihu.com/p/22959809
結(jié)合了函數(shù)式編程和響應(yīng)式編程的框架
將ios的delegate涝焙、kvo卑笨、通知等異步處理方式都用 signal 代替來統(tǒng)一處理; ReactNative還有jspatch這種js轉(zhuǎn)原生的實(shí)現(xiàn)原理是什么仑撞?
ReactNative原理
jspatch原理:利用OC消息轉(zhuǎn)發(fā)機(jī)制赤兴,替換原有的IMP指針妖滔,實(shí)現(xiàn)替換增加方法處理;class_addMethod, class_replaceMethod
jspatch核心是根據(jù)運(yùn)行時(shí)修改函數(shù)實(shí)現(xiàn)來處理的桶良?-
運(yùn)行時(shí)機(jī)制中座舍,@selector這樣的東西是用匯編寫的,為什么陨帆?
保證 objc_msgSend 最快的執(zhí)行速度曲秉;
objc_msgSend 核心是查找IMP,為了性能的優(yōu)化還是得使用一些匯編代碼疲牵;
@selector 會(huì)在運(yùn)行時(shí)通過obj_msgSend查到對(duì)應(yīng)的IMP指針岸浑;
參考:http://www.cocoachina.com/ios/20150812/12992.html
因?yàn)闆]有方法可以將傳入C函數(shù)的泛參傳給另一個(gè)函數(shù),你可以使用變參瑰步,但是變參和普通參數(shù)的傳遞方法不同矢洲,而且慢,所以這不適合普通的C參數(shù)缩焦;
在apple runtime中读虏,為了最大化速度,objc_msgSend整個(gè)函數(shù)是使用匯編實(shí)現(xiàn)的袁滥;因?yàn)橐粋€(gè)最簡單的動(dòng)作都會(huì)使用objc_msgSend盖桥,需要使用匯編來提高執(zhí)行效率;
部分源碼如下(objc-msg-arm.s 中):
-
ismemberofclass和isKindOfClass的底層區(qū)別题翻?
查看objc源碼揩徊,說明ismemberofclass判斷是否是同一個(gè)類,不包括父類嵌赠;
category為什么不能添加成員變量塑荒?它什么時(shí)候加載?
參考:http://www.tuicool.com/articles/QBbeQzv
美團(tuán)酒店事業(yè)部 category
OC中記錄當(dāng)前類屬性的ivars無法動(dòng)態(tài)改變姜挺;動(dòng)態(tài)創(chuàng)建的類可添加變量齿税;
調(diào)用過程:_objc_init --> map_images --> remethodizeClass --> attachCategoryMethods
category原理:類也是一個(gè)對(duì)象,在運(yùn)行時(shí)炊豪,將category和他的主類注冊到哈希表凌箕,重構(gòu)他的方法列表;通過remethodizeClass函數(shù)來重新整理類的數(shù)據(jù)词渤;
PS:無論我們有沒有主動(dòng)引用Category的頭文件牵舱,其中的方法都會(huì)被添加進(jìn)主類中;iOS 鎖
@synchronized
NSLock 互斥鎖
NSRecursiveLock 能多次鎖不造成死鎖缺虐,但必須多次解鎖芜壁,可使用在遞歸函數(shù)中防止引起死鎖;
NSConditionLock 發(fā)送某個(gè)條件時(shí)解鎖
NSCondition lock signal unlock
APP跳轉(zhuǎn)
調(diào)用openUrl跳轉(zhuǎn)到指定app;
- 微信跳轉(zhuǎn)流程:
官方使用文檔
調(diào)用sendReq發(fā)送請求沿盅,處理完畢后會(huì)向第三方程序發(fā)送一個(gè)處理結(jié)果SendMessageToWXResp數(shù)據(jù);
在app delegate中把篓,實(shí)現(xiàn)WXApiDelegate的onResp函數(shù)纫溃,用于接收response結(jié)果腰涧,并彈出對(duì)應(yīng)的提示; - openURL / handleOpenURL
openURL其他: 是你通過打開一個(gè)url的方式打開其他應(yīng)用紊浩;
openURL:sourceApplication / handleOpenURL: 是其他應(yīng)用通過你app中設(shè)置的URL scheme打開你的應(yīng)用窖铡;
后臺(tái)持續(xù)運(yùn)行機(jī)制
多米音樂播放器會(huì)持續(xù)運(yùn)行
可以持續(xù)運(yùn)行的是:音樂播放、GPS定位服務(wù)坊谁、voip费彼、后臺(tái)下載、fetch口芍;
- voip
voip是使用IP進(jìn)行通信的語音傳輸協(xié)議箍铲;
VOIP在iOS運(yùn)行的原理:當(dāng)進(jìn)行后臺(tái)之后,系統(tǒng)托管NSStream(TCP)的通道鬓椭,如果服務(wù)器有信息要傳遞到客戶端颠猴,系統(tǒng)會(huì)激活處于后臺(tái)的程序運(yùn)行10秒鐘(10秒鐘之內(nèi)都可以,可以設(shè)置為6秒小染,或者8秒之類的)翘瓮,這個(gè)時(shí)候可以通過LocalNotification來提示用戶有消息; - 定位服務(wù)
進(jìn)入后臺(tái)時(shí)裤翩,調(diào)用startUpdatingLocation啟動(dòng)定位资盅,定位服務(wù)可用的時(shí)候,程序會(huì)不斷刷新后臺(tái)時(shí)間踊赠,達(dá)到長久后臺(tái)的目的呵扛; - 音樂播放
開啟一段空的語音一直播放 - 后臺(tái)下載
啟動(dòng)一個(gè)后臺(tái)下載任務(wù), backgroundSessionConfiguration,(AFNetWorking使用的就是這個(gè)配置) - fetch和remote-notification
iOS7新增的筐带,可以在適當(dāng)?shù)臅r(shí)候在后臺(tái)喚醒a(bǔ)pp择份;
PS:靜默推送能夠讓收到推送后先拉取數(shù)據(jù),再提醒用戶烫堤;