1、UIView和UILayer的關系?
不同的地方:
1 )繼承結構不同
UIView繼承自UIResponder間接繼承自NSObject的,CALayer是直接繼承NSObject。因此UIView是可以響應事件的,如手勢;CA Layer則不可以。
2)所屬框架不同
UIView在UIKit.framework中定義的,UIKit主要是用來構建用戶界面,并且可以響應事件。CALayer則在QuartzCore.framework中定義的,CALayer是用來承載繪制內容的底層對象。
3)相似的樹形結構
4)在做iOS動畫的時候,修改非rootlayer的屬性(譬如位置、背景色等)會默認產生隱式動畫,而修改UIView則不會。
總結兩者最大的不同則是,UIView可以響應用戶事件,而CALayer不可以。UIView側重于對內容的繪制,UIView側重于對顯示內容的管理。
UIView和CALayer是相互依賴的關系。UIView依賴于CALayer提供的內容,CALayer依賴UIView提供的容器來顯示繪制的內容。歸根結底CALayer是一切的基礎,如果沒有CALayer,UIView自身也不會存在。UIView是一個特殊的CALayer實現且添加了響應事件的能力。UIView本身更像是一個CALayer的管理器,訪問它的跟繪圖以及坐標相關的屬性,例如frame、bounds等等,實際上內部都是在訪問它所包含的CALayer的相關屬性。UIView的layer樹形在系統中,存在著三份copy:
一、邏輯樹,代碼里可以操作的,如修改layer的屬性等就在這里;
二、動畫樹,中間層,系統正是在這一層上更改屬性,進行各種渲染操作;
三、顯示樹,這棵樹的內容是當前正被顯示在屏幕上的內容。
這三棵樹的邏輯結構都是一樣的,區別只有各自的屬性。
UIView的主layer以外,對它的subLayer即子layer的屬性進行更改,系統將自動進行動畫生成。
CALayer的坐標系系統和UIView的有點不一樣,多了一個anchorPoint屬性(相對于bound 坐標系)(CGPoint類型,值域是0-1,即按照比例來設置),這個點是各種圖形變換的坐標原點,同時會改變layer的position位置(相對于superLayer),它的缺省值是{0.5,0.5},layer的中央
frame、position以及anchorPoint關系:
frame.origin.x = position.x - anchorPoint.x * bounds.size.width;
frame.origin.y = position.y - anchorPoint.y * bounds.size.height;
2、hitTest
就直接描述一下事件響應鏈吧。
一、查找用戶點擊視圖。
當用戶點擊某視圖時,UIWindow首先接受到響應,此響應包括用戶點擊區域和一個封裝好的UIEvent對象,然后UIWindow會通過這些信息調用pointInside:withEvent:方法返回yes得知用戶點擊的范圍ViewA(假設);ViewA調用hitTest:withEvent:方法,在方法中遍歷所有的subView(如ViewB、ViewC)調用hitTest:withEvent:方法;在遍歷中發現使用ViewC調用pointInside:withEvent:方法時返回yes得知用戶點擊范圍ViewC中;再遍歷ViewC中各子視圖,并調用pointInside:withEvent:判斷點擊范圍;重復上述過程直至找到一個視圖的subviews個數為0,此視圖即為用戶點擊的View;
二、響應用戶點擊事件
利用UIResponder來實現,具體方法為UIResponder的nextResponder方法。
可以通過用戶點擊View,查看View是否響應了點擊事件,如果沒有,則找其nextResponder,如果沒有再繼續找,直至找到AppDelegate在沒有響應,則點擊事件會被系統丟棄
注意:
在調用nextResponder有以下幾條規則:
- 當一個view調用其nextResponder會返回其superView;
- 如果當前的view為UIViewController的view被添加到其他view上,那么調用nextResponder會返回當前的UIViewController,而這個UIViewController的nextResponder為view的superView;
- 如果當前的UIViewController的view沒有添加到任何其他view上,當前的UIViewController的nextResponder為nil,不管它是keyWinodw或UINavigationController的rootViewController,都是如此;
- 如果當前application的keyWindow的rootViewController為UINavigationController(或UITabViewController),那么通過調用UINavigationController(或UITabViewController)的nextResponder得到keyWinodw;
- keyWinodw的nextResponder為UIApplication,UIApplication的nextResponder為AppDelegate,AppDelegate的nextResponder為nil。
hit-Test View具體的應用見鏈接:http://www.lxweimin.com/p/d8512dff2b3e
3、block
1)什么是block?
block是帶有自動變量值的匿名函數,它也屬于對象(有isa指針)。
2)block類型
根據block存儲域block主要有三種類型,分別為:
_NSConcreteGlobalBlock存儲在棧上,沒有引用外部變量(但static以及全局變量除外);
_NSConcreteStackBlock,存儲在程序的數據區域(.data區),引用了外部變量,不會持有外部變量;
_NSConcreteMallocBlock存儲在堆上,一個block被copy時會生成_NSConcreteMallocBlock,會持有外部變量;
3)__block修飾符
當我們想在block體中修改引用的外部變量值(不包括全局以及static變量)的時候,需要使用__block來修飾外部變量。當我們對一個block進行copy的時候,若此block為stack類型,__block變量也會隨著block的copy,從棧復制到堆并被block所持有;當對malloc類型的block進行copy的話,對__block變量沒有任何影響。
4)block的循環引用問題
block是對象,擁有著和對象一樣的生命周期,如果沒有強引用的話,就會被釋放;若產生循環引用,可以使用__weak(ARC)或者__block(MRC)來解決
MRC環境下,如果沒有用__block會持有引用對象,而使用了__block則不會進行copy操作,只是進行指針復制,不會retain引用的對象。
5)block對以參數形式傳進來的對象,會不會強引用?
可以參考函數以及方法,block對于傳進來的參數,并不會持有
6)block的實現
使用clang -rewrite-objc來編譯可以得到,block最后是被轉化成指向__main_block_impl_0結構體的指針,struct中包括isa(block類型)、FunPtr(函數實現指針),引用變量(若是__block修飾的話,會是一個__Block_byref_i_0結構體的指針)。當不使用__block修飾的話,引用變量也僅僅是傳值,當使用__block修飾的話,會變成傳指針。
詳見http://www.lxweimin.com/p/ca6ac0ae93ad
4、runtime以及JSpatch
1)為什么說c語言等叫函數調用,而OC中叫消息發送?
c語言函數調用是編譯時就已經決定要調用哪個函數了,編譯完成之后直接順序執行,無任何二義性。OC中函數調用稱為消息發送,屬于動態調用過程。在編譯的時候,并不能決定真正調用哪個函數(事實上,在編譯階段,OC可以調用任何函數,即使這個函數并未實現,只要聲明過就不會報錯。這是與c函數調用是不同的)。只有在真正運行的時候才會根據函數的名稱找到對應的函數來調用。
2)消息發送過程
編譯器將[obj make]轉化成obj_msgSend(obj,@selector(make))。在obj_msgSend函數中,首先通過obj的isa指針找到obj所屬的class,在class中先去cache中通過SEL查找對應函數實現指針,若是沒有找到則在class的methodList中查找,若仍未找到,則去superClass中查找直到查找到最頂層的class,若是一直未找到則進行消息轉發過程。若是查找到,則將其加入cache中以方便下次查找,并通過查找到的method的函數指針跳轉到對應的函數中去執行。
3)消息轉發過程
1.動態方法解析
向當前類發送resolveInstanceMethod:信號,檢查是否動態向該類添加了方法(class_addMethod)。
2.快速消息轉發
檢查該類是否實現了forwardingTargetForSelector:方法,若是實現了則調用這個方法。若該方法返回非nil或非self,則向該返回對象重新發送消息。
3.標準消息轉發
runtime發送methodSignatureForSelector:消息獲取selector對應的方法簽名。返回值非空,則通過forwardInvocation:轉發消息;返回值為空則向當前對象發送doesNotRecognizeSelector:消息,程序crash。
4)快速消息轉發與標準消息準發比較
快速消息轉發:簡單、快速,但僅能轉發給一個對象
標準消息轉發:較復雜、較慢、但操作實現可控,可以實現多對象轉發
5、UIButton的繼承關系
UIButton繼承自UIControl->UIView->UIResponder,UIControl這個父類添加了target-action事件
6、UINavigationController用啥數據結構實現的?
這個是使用棧來實現的,因為navigationController下有許多ViewController,而且存在pushViewController和popViewController這兩種方法
7、__bridge、__bridge__transfer、__bridge__retained
__bridge只做類型轉換,但是不修改對象(內存)管理權;
__bridge_retained(也可以使用CFBridgingRetain)將Objective-C的對象轉換為Core Foundation的對象,同時將對象(內存)的管理權交給我們,后續需要使用CFRelease或者相關方法來釋放對象;
__bridge_transfer(也可以使用CFBridgingRelease)將Core Foundation的對象轉換為Objective-C的對象,同時將對象(內存)的管理權交給ARC。
8、怎么讓一個UIScrollView不左右滑動?上下滑動?
禁止UIScrollView垂直方向滾動,只允許水平方向滾動
scrollview.contentSize = CGSizeMake(你要的長度, 0);
禁止UIScrollView水平方向滾動,只允許垂直方向滾動
scrollview.contentSize = CGSizeMake(0, 你要的寬度);
9、svn版本控制命令
服務器拉取代碼:svn checkout http:XXXX
新建一個test.c文件然后提交:svn add test.c加到本地庫里面,然后svn ci -m "添加問價說明",ci是commit的縮寫
查看修改情況:svn status
對比服務器與本地版本之間的區別:svn diff
退到原來的工作拷貝:svn revert,這樣你的本地修改就會丟失
更新本地庫:svn update
解決沖突:svn resolved XX 這個會在更新的同時并保留本地的修改,并將沖突文件標記為resolved,此后你可以直接在沖突文件中看到標記
10、svn和git的區別(了解不深)
1)git是分布式的,svn卻不是;
2)git把內容按元數據方式存儲,svn是按文件
3)git沒有一個全局版本號
4)git下載下來后,在離線狀態下可以看到所有的log
5)svn克隆一份全新的目錄耗時長
6)svn只有一個版本庫,一旦掛掉所有的工作都不可以進行
7)git的分支很強大。svn的分支是一個完整的目錄,開辟一個新分支會影響所有人。
詳情請見 http://www.lxweimin.com/p/bfec042349ca