【iOS學習筆記】一些問題

 

http://zhangmingwei.iteye.com/blog/1748431

1.什麼是arc?(arc是爲了解決什麼問題誕生的?)

首先解釋ARC: automatic reference counting自動引用計數。 
ARC幾個要點: 
在對象被建立時 retain count +1,在對象被release時 retain count -1.當retain count 爲0 時,銷燬對象。 
程序中加入autoreleasepool的對象會由系統自動加上autorelease方法,若是該對象引用計數爲0,則銷燬。 
那麼ARC是爲了解決什麼問題誕生的呢?這個得追溯到MRC手動內存管理時代提及。 
MRC下內存管理的缺點: 
1.當咱們要釋放一個堆內存時,首先要肯定指向這個堆空間的指針都被release了。(避免提早釋放) 
2.釋放指針指向的堆空間,首先要肯定哪些指針指向同一個堆,這些指針只能釋放一次。(MRC下即誰建立,誰釋放,避免重複釋放) 
3.模塊化操做時,對象可能被多個模塊建立和使用,不能肯定最後由誰去釋放。 
4.多線程操做時,不肯定哪一個線程最後使用完畢html

2.請解釋如下keywords的區別: assign vs weak, __block vs __weak

assign適用於基本數據類型,weak是適用於NSObject對象,而且是一個弱引用。 
首先__block是用來修飾一個變量,這個變量就能夠在block中被修改(參考block實現原理) 
__block:使用__block修飾的變量在block代碼快中會被retain(ARC下,MRC下不會retain) 
__weak:使用__weak修飾的變量不會在block代碼塊中被retain 
同時,在ARC下,要避免block出現循環引用 __weak typedof(self)weakSelf = self;程序員

3.__block在arc和非arc下含義同樣嗎?

是不同的。 
在MRC中__block variable在block中使用是不會retain的 
可是ARC中__block則是會Retain的。 
取而代之的是用__weak或是__unsafe_unretained來更精確的描述weak reference的目的 
其中前者只能在iOS5之後可使用,可是比較好 (該物件release之後,此pointer會自動設成nil) 
而後者是ARC的環境下為了相容4.x的解決方案。 
因此上面的範例中web

__block MyClass* temp = …;    // MRC環境下使用  __weak MyClass* temp = …;    // ARC但只支援iOS5.0以上的版本  __unsafe_retained MyClass* temp = …;  //ARC且能夠相容4.x以後的版本

4.使用nonatomic必定是線程安全的嗎?()

不是的。 
atomic原子操做,系統會爲setter方法加鎖。 具體使用 @synchronized(self){//code } 
nonatomic不會爲setter方法加鎖。 
atomic:線程安全,須要消耗大量系統資源來爲屬性加鎖 
nonatomic:非線程安全,適合內存較小的移動設備objective-c

5.描述一個你遇到過的retain cycle例子。

block中的循環引用:一個viewController算法

@property (nonatomic,strong)HttpRequestHandler * handler; @property (nonatomic,strong)NSData *data; _handler = [httpRequestHandler sharedManager]; [ downloadData:^(id responseData){ _data = responseData; }];

self 擁有_handler, _handler 擁有block, block擁有self(由於使用了self的_data屬性,block會copy 一份self) 
解決方法:sql

__weak typedof(self)weakSelf = self [ downloadData:^(id responseData){ weakSelf.data = responseData; }];

6.+(void)load; +(void)initialize;有什麼用處?

在Objective-C中,runtime會自動調用每一個類的兩個方法。+load會在類初始加載時調用,+initialize會在第一次調用類的類方法或實例方法以前被調用。這兩個方法是可選的,且只有在實現了它們時纔會被調用。 
共同點:兩個方法都只會被調用一次。瀏覽器

7.爲何其餘語言裏叫函數調用, objective c裏則是給對象發消息(或者談下對runtime的理解)

先來看看怎麼理解發送消息的含義:緩存

曾經以爲Objc特別方便上手,面對着 Cocoa 中大量 API,只知道簡單的查文檔和調用。還記得初學 Objective-C 時把[receiver message]當成簡單的方法調用,而無視了「發送消息」這句話的深入含義。因而[receiver message]會被編譯器轉化爲: 
objc_msgSend(receiver, selector) 
若是消息含有參數,則爲: 
objc_msgSend(receiver, selector, arg1, arg2, ...)安全

若是消息的接收者可以找到對應的selector,那麼就至關於直接執行了接收者這個對象的特定方法;不然,消息要麼被轉發,或是臨時向接收者動態添加這個selector對應的實現內容,要麼就乾脆玩完崩潰掉。ruby

如今能夠看出[receiver message]真的不是一個簡簡單單的方法調用。由於這只是在編譯階段肯定了要向接收者發送message這條消息,而receive將要如何響應這條消息,那就要看運行時發生的狀況來決定了。

Objective-C 的 Runtime 鑄就了它動態語言的特性,這些深層次的知識雖然平時寫代碼用的少一些,可是倒是每一個 Objc 程序員須要瞭解的。

Objc Runtime使得C具備了面向對象能力,在程序運行時建立,檢查,修改類、對象和它們的方法。可使用runtime的一系列方法實現。

順便附上OC中一個類的數據結構 /usr/include/objc/runtime.h

struct objc_class { Class isa OBJC_ISA_AVAILABILITY; //isa指針指向Meta Class,由於Objc的類的自己也是一個Object,爲了處理這個關係,r untime就創造了Meta Class,當給類發送[NSObject alloc]這樣消息時,其實是把這個消息發給了Class Object #if !__OBJC2__ Class super_class OBJC2_UNAVAILABLE; // 父類 const char *name OBJC2_UNAVAILABLE; // 類名 long version OBJC2_UNAVAILABLE; // 類的版本信息,默認爲0 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; // 方法緩存,對象接到一個消息會根據isa指針查找消息對象,這時會在method Lists中遍歷,若是cache了,經常使用的方法調用時就可以提升調用的效率。 struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協議鏈表 #endif } OBJC2_UNAVAILABLE;

OC中一個類的對象實例的數據結構(/usr/include/objc/objc.h):

typedef struct objc_class *Class; /// Represents an instance of a class. struct objc_object { Class isa OBJC_ISA_AVAILABILITY; }; /// A pointer to an instance of a class. typedef struct objc_object *id;

向object發送消息時,Runtime庫會根據object的isa指針找到這個實例object所屬於的類,而後在類的方法列表以及父類方法列表尋找對應的方法運行。id是一個objc_object結構類型的指針,這個類型的對象可以轉換成任何一種對象。

而後再來看看消息發送的函數:objc_msgSend函數

在引言中已經對objc_msgSend進行了一點介紹,看起來像是objc_msgSend返回了數據,其實objc_msgSend從不返回數據而是你的方法被調用後返回了數據。下面詳細敘述下消息發送步驟:

檢測這個 selector 是否是要忽略的。好比 Mac OS X 開發,有了垃圾回收就不理會 retain,release 這些函數了。 
檢測這個 target 是否是 nil 對象。ObjC 的特性是容許對一個 nil 對象執行任何一個方法不會 Crash,由於會被忽略掉。 
若是上面兩個都過了,那就開始查找這個類的 IMP,先從 cache 裏面找,完了找獲得就跳到對應的函數去執行。 
若是 cache 找不到就找一下方法分發表。 
若是分發表找不到就到超類的分發表去找,一直找,直到找到NSObject類爲止。 
若是還找不到就要開始進入動態方法解析了,後面會提到。

後面還有: 
動態方法解析resolveThisMethodDynamically 
消息轉發forwardingTargetForSelector

詳情可參考 https://app.yinxiang.com/shard/s10/nl/146175/7925ae66-03f7-487c-83a7-26c519aa897b/

8.什麼是method swizzling?

Method Swizzling 原理(方法攪拌?)

在Objective-C中調用一個方法,實際上是向一個對象發送消息,查找消息的惟一依據是selector的名字。利用Objective-C的動態特性,能夠實如今運行時偷換selector對應的方法實現,達到給方法掛鉤的目的。 
每一個類都有一個方法列表,存放着selector的名字和方法實現的映射關係。IMP有點相似函數指針,指向具體的Method實現。

方法指向

咱們能夠利用 method_exchangeImplementations 來交換2個方法中的IMP,

咱們能夠利用 class_replaceMethod 來修改類,

咱們能夠利用 method_setImplementation 來直接設置某個方法的IMP, 
…… 
歸根結底,都是偷換了selector的IMP,以下圖所示: 
方法交換

詳情:http://blog.csdn.net/yiyaaixuexi/article/details/9374411

9.UIView和CALayer是啥關係?

1.UIView是iOS系統中界面元素的基礎,全部的界面元素都繼承自它。它自己徹底是由CoreAnimation來實現的 (Mac下彷佛不是這樣)。它真正的繪圖部分,是由一個叫CALayer(Core Animation Layer)的類來管理。 UIView自己,更像是一個CALayer的管理器,訪問它的跟繪圖和跟座標有關的屬性,例如frame,bounds等 等,實際上內部都是在訪問它所包含的CALayer的相關屬性。

2.UIView有個layer屬性,能夠返回它的主CALayer實例,UIView有一個layerClass方法,返回主layer所使用的 類,UIView的子類,能夠經過重載這個方法,來讓UIView使用不一樣的CALayer來顯示,例如經過

- (class) layerClass { return ([CAEAGLLayer class]); }

=使某個UIView的子類使用GL來進行繪製。

3.UIView的CALayer相似UIView的子View樹形結構,也能夠向它的layer上添加子layer,來完成某些特殊的表 示。例以下面的代碼

grayCover = [[CALayer alloc] init];      grayCover.backgroundColor = [[[UIColor blackColor] colorWithAlphaComponent:0.2] CGColor]; [self.layer addSubLayer: grayCover];

會在目標View上敷上一層黑色的透明薄膜。

4.UIView的layer樹形在系統內部,被系統維護着三份copy(這段理解有點吃不許)。

  1. 邏輯樹,就是代碼裏能夠操縱的,例如更改layer的屬性等等就在這一份。
  2. 動畫樹,這是一箇中間層,系統正在這一層上更改屬性,進行各類渲染操做。
  3. 顯示樹,這棵樹的內容是當前正被顯示在屏幕上的內容。

這三棵樹的邏輯結構都是同樣的,區別只有各自的屬性。

10. 如何高性能的給UIImageView加個圓角?(不許說layer.cornerRadius!)

我以爲應該是使用Quartz2D直接繪製圖片,得把這個看看。 
步驟: 
a、建立目標大小(cropWidth,cropHeight)的畫布。

  b、使用UIImage的drawInRect方法進行繪製的時候,指定rect爲(-x,-y,width,height)。

  c、從畫布中獲得裁剪後的圖像。

- (UIImage*)cropImageWithRect:(CGRect)cropRect {     CGRect drawRect = CGRectMake(-cropRect.origin.x , -cropRect.origin.y, self.size.width * self.scale, self.size.height * self.scale); UIGraphicsBeginImageContext(cropRect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextClearRect(context, CGRectMake(0, 0, cropRect.size.width, cropRect.size.height)); [self drawInRect:drawRect]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } @end

11. 使用drawRect有什麼影響?(這個可深可淺,你至少得用過。。)

drawRect方法依賴Core Graphics框架來進行自定義的繪製,但這種方法主要的缺點就是它處理touch事件的方式:每次按鈕被點擊後,都會用setNeddsDisplay進行強制重繪;並且不止一次,每次單點事件觸發兩次執行。這樣的話從性能的角度來講,對CPU和內存來講都是欠佳的。特別是若是在咱們的界面上有多個這樣的UIButton實例。

12. ASIHttpRequest或者SDWebImage裏面給UIImageView加載圖片的邏輯是什麼樣的?

詳見SDWebImage的實現流程 http://www.cnblogs.com/6duxz/p/4159572.html

13. 麻煩你設計個簡單的圖片內存緩存器(移除策略是必定要說的)

14. 講講你用Instrument優化動畫性能的經歷吧(別問我什麼是Instrument)

能夠參考iOS App性能優化

15. loadView是幹嗎用的?

當你訪問一個ViewController的view屬性時,若是此時view的值是nil,那麼,ViewController就會自動調用loadView這個方法。這個方法就會加載或者建立一個view對象,賦值給view屬性。 
loadView默認作的事情是:若是此ViewController存在一個對應的nib文件,那麼就加載這個nib。不然,就建立一個UIView對象。

若是你用Interface Builder來建立界面,那麼不該該重載這個方法。

若是你想本身建立view對象,那麼能夠重載這個方法。此時你須要本身給view屬性賦值。你自定義的方法不該該調用super。若是你須要對view作一些其餘的定製操做,在viewDidLoad裏面去作。

=========================================

根據上面的文檔能夠知道,有兩種狀況:

一、若是你用了nib文件,重載這個方法就沒有太大意義。由於loadView的做用就是加載nib。若是你重載了這個方法不調用super,那麼nib文件就不會被加載。若是調用了super,那麼view已經加載完了,你須要作的其餘事情在viewDidLoad裏面作更合適。

二、若是你沒有用nib,這個方法默認就是建立一個空的view對象。若是你想本身控制view對象的建立,例如建立一個特殊尺寸的view,那麼能夠重載這個方法,本身建立一個UIView對象,而後指定 self.view = myView; 但這種狀況也沒有必要調用super,由於反正你也不須要在super方法裏面建立的view對象。若是調用了super,那麼就是浪費了一些資源而已 
參考:http://www.cnblogs.com/dyllove98/archive/2013/06/06/3123005.html

16. viewWillLayoutSubView你老是知道的。

橫豎屏切換的時候,系統會響應一些函數,其中 viewWillLayoutSubviews 和 viewDidLayoutSubviews。

//

- (void)viewWillLayoutSubviews { [self _shouldRotateToOrientation:(UIDeviceOrientation)[UIApplication sharedApplication].statusBarOrientation]; } -(void)_shouldRotateToOrientation:(UIDeviceOrientation)orientation { if (orientation == UIDeviceOrientationPortrait ||orientation == UIDeviceOrientationPortraitUpsideDown) { // 豎屏 } else { // 橫屏 } }

經過上述一個函數就知道橫豎屏切換的接口了。 
注意:viewWillLayoutSubviews只能用在ViewController裏面,在view裏面沒有響應。

17. GCD裏面有哪幾種Queue?你本身創建過串行queue嗎?背後的線程模型是什麼樣的?

1.主隊列 dispatch_main_queue(); 串行 ,更新UI 
2.全局隊列 dispatch_global_queue(); 並行,四個優先級:background,low,default,high 
3.自定義隊列 dispatch_queue_t queue ; 能夠自定義是並行:DISPATCH_QUEUE_CONCURRENT或者串行DISPATCH_QUEUE_SERIAL

18. 用過coredata或者sqlite嗎?讀寫是分線程的嗎?遇到過死鎖沒?咋解決的?

參考:CoreData與SQLite的線程安全

19. http的post和get啥區別?(區別挺多的,麻煩多說點)

1.GET請求的數據會附在URL以後(就是把數據放置在HTTP協議頭中),以?分割URL和傳輸數據,參數之間以&相連,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。若是數據是英文字母/數字,原樣發送,若是是空格,轉換爲+,若是是中文/其餘字符,則直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX爲該符號以16進製表示的ASCII。 
POST把提交的數據則放置在是HTTP包的包體中。

2.」GET方式提交的數據最多隻能是1024字節,理論上POST沒有限制,可傳較大量的數據,IIS4中最大爲80KB,IIS5中爲100KB」??!

  以上這句是我從其餘文章轉過來的,其實這樣說是錯誤的,不許確的:

  (1).首先是」GET方式提交的數據最多隻能是1024字節」,由於GET是經過URL提交數據,那麼GET可提交的數據量就跟URL的長度有直接關係了。而實際上,URL不存在參數上限的問題,HTTP協議規範沒有對URL長度進行限制。這個限制是特定的瀏覽器及服務器對它的限制。IE對URL長度的限制是2083字節(2K+35)。對於其餘瀏覽器,如Netscape、FireFox等,理論上沒有長度限制,其限制取決於操做系統的支持。

  注意這是限制是整個URL長度,而不只僅是你的參數值數據長度。[見參考資料5]

  (2).理論上講,POST是沒有大小限制的,HTTP協議規範也沒有進行大小限制,說「POST數據量存在80K/100K的大小限制」是不許確的,POST數據是沒有限制的,起限制做用的是服務器的處理程序的處理能力。

3.在ASP中,服務端獲取GET請求參數用Request.QueryString,獲取POST請求參數用Request.Form。在JSP中,用request.getParameter(\」XXXX\」)來獲取,雖然jsp中也有request.getQueryString()方法,但使用起來比較麻煩,好比:傳一個test.jsp?name=hyddd&password=hyddd,用request.getQueryString()獲得的是:name=hyddd&password=hyddd。在PHP中,能夠用GET_POST分別獲取GET和POST中的數據,而REQUESTGETPOSTJSP使requestPHP使_REQUEST都會有隱患,這個下次再寫個文章總結。

4.POST的安全性要比GET的安全性高。注意:這裏所說的安全性和上面GET提到的「安全」不是同個概念。上面「安全」的含義僅僅是不做數據修改,而這裏安全的含義是真正的Security的含義,好比:經過GET提交數據,用戶名和密碼將明文出如今URL上,由於(1)登陸頁面有可能被瀏覽器緩存,(2)其餘人查看瀏覽器的歷史紀錄,那麼別人就能夠拿到你的帳號和密碼了,除此以外,使用GET提交數據還可能會形成Cross-site request forgery攻擊。

總結一下,Get是向服務器發索取數據的一種請求,而Post是向服務器提交數據的一種請求,在FORM(表單)中,Method默認爲」GET」,實質上,GET和POST只是發送機制不一樣,並非一個取一個發!

20. 我知道你大學畢業事後就沒接觸過算法數據結構了,可是請你必定告訴我什麼是Binary search tree? search的時間複雜度是多少?

Binary search tree:二叉搜索樹。 
主要由四個方法:(用C語言實現或者Python) 
1.search:時間複雜度爲O(h),h爲樹的高度

2.traversal:時間複雜度爲O(n),n爲樹的總結點數。

3.insert:時間複雜度爲O(h),h爲樹的高度。

4.delete:最壞狀況下,時間複雜度爲O(h)+指針的移動開銷。

能夠看到,二叉搜索樹的dictionary operation的時間複雜度與樹的高度h相關。因此須要儘量的下降樹的高度,由此引出平衡二叉樹Balanced binary tree。它要求左右兩個子樹的高度差的絕對值不超過1,而且左右兩個子樹都是一棵平衡二叉樹。這樣就能夠將搜索樹的高度儘可能減少。經常使用算法有紅黑樹、AVL、Treap、伸展樹等。

 

http://www.jianshu.com/p/262c1f8b7461

相關文章
相關標籤/搜索