面試題只是武功招式,知識體系才是內(nèi)功心法。

總結(jié)一下常見的面試題,一般初級iOS Developer記住的都是招式,但招式何其多,面試的時候總會有遺漏和盲區(qū),內(nèi)功心法才是一通萬通,能以不變應(yīng)萬變。這份面試題你答不全不能說明你iOS不及格,你全答對了你也不能上天。真正應(yīng)該關(guān)注的是這份題背后所包含的理論知識體系。

內(nèi)存管理
多線程實現(xiàn)方式
動畫技術(shù)
繪圖技術(shù)
設(shè)計模式
Objective-C的一些語言特性

上點干貨。

1??. 說說你對ARC和MRC的認(rèn)識?

  1. ARC:Automatic Reference Counting 自動引用計數(shù)
  2. MRC:Mannul Reference Counting 手動引用計數(shù)

ARC是基于MRC的,本質(zhì)都是管理對象的retainCount屬性,不同的是管理內(nèi)存代碼是由誰來寫。
MRC要求程序員自己寫代碼管理對象的retainCount屬性,
而在ARC下,編譯器編譯代碼的時候,會自動根據(jù)當(dāng)前代碼的情況添加對象的內(nèi)存管理的代碼。

之所以要管理內(nèi)存,是因為對象在堆中,不會自動回收。如果不去管理,那就要等到程序結(jié)束才回收。如果用戶一直在使用,會導(dǎo)致內(nèi)存的占用越來越大。

說到這里,必須說一下內(nèi)存管理的原則。

1>對象創(chuàng)建后,要對應(yīng)一次release
2>哪個指針retain了對象,就用哪個指針release對象
3>retain的次數(shù)要和release相匹配
4>在對象被釋放前,指針不可設(shè)為nil或指向別的對象,因為會出現(xiàn)內(nèi)存泄漏

MRC下要注意的問題:對象之間的循環(huán)retain
ARC下要注意的總是:對象之間的循環(huán)引用

Xcode 4.1之后 才有ARC

ARC下,不顯示指定任何屬性關(guān)鍵字時,默認(rèn)的關(guān)鍵字都有哪些?

對應(yīng)基本數(shù)據(jù)類型默認(rèn)關(guān)鍵字是
atomic,readwrite,assign

對于普通的OC對象
atomic,readwrite,strong

2??. 第三方框架相關(guān)

1.談?wù)劰ぷ髦心闶侨绾巫鰣D片緩存的?

一般用第三方框架SDWebImage

SDWebImage庫的作用:
通過對UIImageView的類別擴(kuò)展來實現(xiàn)異步加載替換圖片的工作。

主要用到的對象:

1.UIImageView (WebCache)類別,入口封裝,實現(xiàn)讀取圖片完成后的回調(diào)。
2.SDWebImageManager,對圖片進(jìn)行管理的中轉(zhuǎn)站,記錄那些圖片正在讀取。
向下層讀取Cache(調(diào)用SDImageCache),或者向網(wǎng)絡(luò)讀取對象( 調(diào)用SDWebImageDownloader )。
實現(xiàn)SDImageCache和SDWebImageDownloader的回調(diào)。
3.SDImageCache,根據(jù)據(jù)URL的MD5摘要對圖片進(jìn)行存儲和讀?。▽崿F(xiàn)存在內(nèi)存中或者存在硬盤上兩種實現(xiàn))
實現(xiàn)圖片和內(nèi)存清理工作。
4.SDWebImageDownloader,根據(jù)URL向網(wǎng)絡(luò)讀取數(shù)據(jù)(實現(xiàn)部分讀取和全部讀取后再通知回調(diào)兩種方式)

5.SDWebImageDecoder,異步對圖像進(jìn)行了一次解壓.
由于UIImage的imageWithData函數(shù)是每次畫圖的時候才將Data解壓成ARGB的圖像,
所以在每次畫圖的時候,會有一個解壓操作,這樣效率很低,但是只有瞬時的內(nèi)存需求。
為了提高效率通過SDWebImageDecoder將包裝在Data下的資源解壓,然后畫在另外一張圖片上,這樣這張新圖片就不再需要重復(fù)解壓了。

1、SDImageCache是怎么做數(shù)據(jù)管理的?
SDImageCache分兩個部分,一個是內(nèi)存層面的,一個是硬盤層面的。
內(nèi)存層面的相當(dāng)是個緩存器,以Key-Value的形式存儲圖片。當(dāng)內(nèi)存不夠的時候會清除所有緩存圖片。
用搜索文件系統(tǒng)的方式做管理,文件替換方式是以時間為單位,剔除時間大于一周的圖片文件。
當(dāng)SDWebImageManager向SDImageCache要資源時,先搜索內(nèi)存層面的數(shù)據(jù),如果有直接返回,沒有的話去訪問磁盤,將圖片從磁盤讀取出來,然后做Decoder,將圖片對象放到內(nèi)存層面做備份,再返回調(diào)用層。

SDWebImage原理及使用

2.SDWebImage常見面試題。

1> 圖片文件緩存的時間有多長:1周

_maxCacheAge = kDefaultCacheMaxCacheAge

2> SDWebImage 的內(nèi)存緩存是用什么實現(xiàn)的?

NSCache

3> SDWebImage 的最大并發(fā)數(shù)是多少?

maxConcurrentDownloads = 6

4> SDWebImage 支持動圖嗎?GIF

#import <ImageIO/ImageIO.h>
[UIImage animatedImageWithImages:images duration:duration];```
5> SDWebImage是如何區(qū)分不同格式的圖像的

根據(jù)圖像數(shù)據(jù)第一個字節(jié)來判斷的!
PNG:0x89
JPG:0xFF
GIF:0x47```
6> SDWebImage 緩存圖片的名稱是怎么確定的!

md5
如果單純使用 文件名保存,重名的幾率很高!
使用 MD5 的散列函數(shù)!對完整的 URL 進(jìn)行 md5,結(jié)果是一個 32 個字符長度的字符串!```
7> SDWebImage 的內(nèi)存警告是如何處理的!
利用通知中心觀察
  • UIApplicationDidReceiveMemoryWarningNotification 接收到內(nèi)存警告的通知
    執(zhí)行 clearMemory 方法,清理內(nèi)存緩存!
  • UIApplicationWillTerminateNotification 接收到應(yīng)用程序?qū)⒁K止通知
    執(zhí)行 cleanDisk 方法,清理磁盤緩存!
  • UIApplicationDidEnterBackgroundNotification 接收到應(yīng)用程序進(jìn)入后臺通知
    執(zhí)行 backgroundCleanDisk 方法,后臺清理磁盤!
    通過以上通知監(jiān)聽,能夠保證緩存文件的大小始終在控制范圍之內(nèi)!
    clearDisk 清空磁盤緩存,將所有緩存目錄中的文件,全部刪除! 實際工作,將緩存目錄直接刪除,再次創(chuàng)建一個同名空目錄!
###3.談?wù)劰ぷ髦杏袥]有二次封裝過第三方框架,都封裝過哪些,舉例說明。

此類與工作經(jīng)驗密切相關(guān)。如AFN的二次封裝。


##3??. 說說NSTimer創(chuàng)建后,會在哪個線程運行。runloop和線程的關(guān)系?

    有兩種創(chuàng)建NSTimer的方式
       第一種:scheduled創(chuàng)建的定時器會自動以默認(rèn)方式(NSDefaultRunLoopMode)加入到當(dāng)前運行循環(huán)里面
       NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(setNumLabelNum) userInfo:nil repeats:YES];

    第二種: timerWithTimeInterval創(chuàng)建的定時器需要手動加入到當(dāng)前運行循環(huán)里
        NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(setNumLabelNum) userInfo:nil repeats:YES];
        
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    
kCFRunLoopDefaultMode:默認(rèn)模式,不能再交互時保持運行
NSRunLoopCommonModes : 是模式組,包含多種模式,可以在交互的時候保持運行;kCFRunLoopDefaultMode 和 UITrackingRunLoopMode



RunLoop 和線程

RunLoop 的作用就是來管理線程的,當(dāng)線程的 RunLoop
開啟后,線程就會在執(zhí)行完任務(wù)后,處于休眠狀態(tài),隨時等待接受新的任務(wù),而不是退出。

只有主線程的RunLoop是默認(rèn)開啟的,所以程序在開啟后,會一直運行,不會退出。其他線程的RunLoop
如果需要開啟,就手動開啟,

判斷下面運行循環(huán)能否執(zhí)行 。執(zhí)行幾次?
  • (void)viewDidLoad {
    [super viewDidLoad];
    _timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
    [_timer fire];
    }

  • (void)runTimer{
    [NSThread detachNewThreadSelector:@selector(startTimer) toTarget:self withObject:nil];
    }

  • (void)startTimer
    {
    NSLog(@"我運行幾次?");
    }



猜想runloop內(nèi)部是如何實現(xiàn)的?

1、有一個判斷循環(huán)的條件,滿足條件,就一直循環(huán)

2、線程得到喚醒事件被喚醒,事件處理完畢以后,回到睡眠狀態(tài),等待下次喚醒。

##4??. objc中向一個nil對象發(fā)送消息將會發(fā)生什么?

  在Objective-C中向nil發(fā)送消息是完全有效的——只是在運行時不會有任何作用。Cocoa中的幾種模式就利用到了這一點。發(fā)向nil的消息的返回值也可以是有效的:
  
    ? 如果一個方法返回值是一個對象,那么發(fā)送給nil的消息將返回0(nil)。例如:Person * motherInlaw = [ aPerson spouse] mother]; 如果spouse對象為nil,那么發(fā)送給nil的消息mother也將返回nil。
    ? 如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*),float,double,long double 或者long long的整型標(biāo)量,發(fā)送給nil的消息將返回0。
    ? 如果方法返回值為結(jié)構(gòu)體,正如在《Mac OS X ABI 函數(shù)調(diào)用指南》,發(fā)送給nil的消息將返回0。結(jié)構(gòu)體中各個字段的值將都是0。其他的結(jié)構(gòu)體數(shù)據(jù)類型將不是用0填充的。
    ? 如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給nil的消息的返回值將是未定義的。
    
  下面的代碼段就是一個有效地向nil發(fā)送消息的示例:
    
    //id anObjectMybeNil = nil;  
    //這種寫法是有效的  
    if ( [ anObjectMaybeNil methordThatReturnADouble] == 0.0 )  
    {  
            //其他的實現(xiàn)代碼  
    }  
    
    
   注意:在Mac OS X v10.5版本中,向nil發(fā)送消息的結(jié)果與上面的描述會稍有不同。在Mac OS X v10.4以及更以前的版本中,向nil發(fā)送消息是完全有效的,只要消息的返回值是對象,任意類型的指針,void,或者是其他大小小于或者等于sizeof(void*)的整型標(biāo)量。此時,發(fā)送給nil的消息將返回nil。如果發(fā)送nil的消息的返回值不是上述幾種類型(比如說返回的類型是結(jié)構(gòu)體,或者是浮點類型,或者是向量類型的),其返回值則是未定義的。因此,在Mac OS X v10.4以及更老的版本中,我們不應(yīng)該依賴于發(fā)送給nil對象的消息的返回值,除非該消息的返回值是一個對象,任意類型的指針,或者是任意大小小于或者是等于sizeof(void *)的整型標(biāo)量。
    

##???. 比較一下objc中的類方法和實例方法?

1、類方法是屬于整個類,而不屬于某個對象。  
2、類方法只能訪問類成員變量,不能訪問實例變量,而實例方法可以訪問類成員變量和實例變量。  
3、類方法的調(diào)用可以通過類名.類方法和對象.類方法,而實例方法只能通過對象.實例方法訪問。  
4、類方法只能訪問類方法,而實例方法可以訪問類方法和實例方法。  
5、類方法不能被覆蓋,實例方法可以被覆蓋。  

實例方法是— 類開頭是+ 實例方法是用實例對象訪問,類方法的對象是類而不是實例,通常創(chuàng)建對象或者工具類。

在實例方法里,根據(jù)繼承原理發(fā)送消息給self和super其實都是發(fā)送給self

在類方法里面self是其他的類的類方法,在類方法中給self發(fā)送消息只能發(fā)類方法self是類super也是

什么時候用類方法,要創(chuàng)建一個實例時候獲取一個共享實例,或者獲取關(guān)于類的一些共有信息




##6??. @property 相關(guān)

###1. @property 后面可以有哪些修飾符?

    線程安全的: atomic,nonatomic
    訪問權(quán)限的:readonly,readwrite
    內(nèi)存管理(ARC):assign,strong,weak,copy
    內(nèi)存管理(MRC):assign,retain,copy
    指定方法名稱 :setter,getter
###2. 什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同?比如:
在MRC環(huán)境下使用retain修飾對象類型,使用assign實現(xiàn)基本類型;

在ARC環(huán)境下,strong相當(dāng)于retain,weak相當(dāng)于assign,不對對象的引用計數(shù)+1;

目前 assigin 可以既可以用于修飾非OC對象也可以修飾OC對象,而weak必須用于修飾OC對象。
![weak與assign對比](http://i4.buimg.com/567571/d0d193725f17d3df.jpg "Title")


`weak 和 assign 的主要區(qū)別`:也是為什么控件用weak不用assign修飾:
對象銷毀后,weak 修飾的 property 會自動設(shè)置為 nil,這個最大的好處就是之后發(fā)送的消息都不會因為對象銷毀而出錯;assign 修飾的 property 并不會自動變?yōu)?nil,形成野指針,所以在此之后如果沒有判斷對象是否銷毀的話,很有可能就會對野指針發(fā)送消息導(dǎo)致crash。

官方來說,如果不想增加持有對象的引用計數(shù)器的話,推薦使用 weak 而不是 assign,這一點從 Apple 提供的頭文件就可以看出——所有 delegate 的修飾符都是 weak。

weak 此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系” (nonowning relationship)。為這種屬性設(shè)置新值時,設(shè)置方法既不保留新值,也不釋放舊值。此特質(zhì)同assign類似, 然而在屬性所指的對象遭到摧毀時,屬性值也會清空(nil out)。 而 assign 的“設(shè)置方法”只會執(zhí)行針對“純量類型” (scalar type,例如 CGFloat 或 NSlnteger 等)的簡單賦值操作。

 
在ARC中,出現(xiàn)循環(huán)引用的時候,必須要有一端使用weak,比如:自定義View的代理屬性,已經(jīng)自身已經(jīng)對它進(jìn)行一次強(qiáng)應(yīng)用,沒有必要在強(qiáng)引用一次,此時也會使用weak,自定義View的子控件屬性一般也使用weak;但是也可以使用strong
當(dāng)父控件銷毀的時候,指向?qū)ο蟮闹羔槙蛔詣釉O(shè)置為nil,對象沒有強(qiáng)指針指向也會被銷毀。

strong - 定義OC對象,根視圖,父視圖
weak - 代理,子控件,解決block循環(huán)引用時
copy - 字符串,block,可變的集合(NSMutableArray ,dictM,SetM)


###3. 為什么字符串不用strong 而用copy?

copy此特質(zhì)所表達(dá)的所屬關(guān)系與strong類似。然而設(shè)置方法并不保留新值,而是將其“拷貝” (copy)。 當(dāng)屬性類型為NSString時,經(jīng)常用此特質(zhì)來保護(hù)其封裝性,因為傳遞給設(shè)置方法的新值有可能指向一個NSMutableString類的實例。這個類是NSString的子類,表示一種可修改其值的字符串,此時若是不拷貝字符串,那么設(shè)置完屬性之后,字符串的值就可能會在對象不知情的情況下遭人更改。所以,這時就要拷貝一份“不可變” (immutable)的字符串,確保對象中的字符串值不會無意間變動。只要實現(xiàn)屬性所用的對象是“可變的” (mutable),就應(yīng)該在設(shè)置新屬性值時拷貝一份。

用@property聲明 NSString、NSArray、NSDictionary 經(jīng)常使用copy關(guān)鍵字,是因為他們有對應(yīng)的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進(jìn)行賦值操作,為確保對象中的字符串值不會無意間變動,應(yīng)該在設(shè)置新屬性值時拷貝一份。

保證其恒定性。
###4、關(guān)于block變量為什么用copy?

block 使用 copy 是從 MRC 遺留下來的“傳統(tǒng)”,在 MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).在 ARC 中寫不寫都行:對于 block 使用 copy 還是 strong 效果是一樣的,但寫上 copy 也無傷大雅,還能時刻提醒我們:編譯器自動對 block 進(jìn)行了 copy 操作。如果不寫 copy ,該類的調(diào)用者有可能會忘記或者根本不知道“編譯器會自動對 block 進(jìn)行了 copy 操作”,他們有可能會在調(diào)用之前自行拷貝屬性值。這種操作多余而低效。

~~只有copy后的Block才會在堆中~~ **不正確的**, 在ARC中引用外部變量的block系統(tǒng)默認(rèn)到堆區(qū)。不引用外部變量的block在棧區(qū)。但是在實際開發(fā)中,不引用外部變量的block是不存在的。棧中的Block的生命周期是和棧綁定的   。

在MRC下防止循環(huán)引用
__block typeof(self) weakSelf = self;  

在ARC下防止循環(huán)引用
__weak typeof(self) weakSelf=self;  

因為MRC下沒有__weak
##7??. KVC與KVO理解
KVC,即是指 NSKeyValueCoding,一個非正式的 Protocol,提供一種機(jī)制來間接訪問對象的屬性。KVO 就是基于 KVC 實現(xiàn)的關(guān)鍵技術(shù)之一。

一個對象擁有某些屬性。比如說,一個 Person 對象有一個 name 和一個 address 屬性。以 KVC 說法,Person 對象分別有一個 value 對應(yīng)他的 name 和 address 的 key。 key 只是一個字符串,它對應(yīng)的值可以是任意類型的對象。從最基礎(chǔ)的層次上看,KVC 有兩個方法:一個是設(shè)置 key 的值,另一個是獲取 key 的值。

Key-Value Observing (KVO) 建立在 KVC 之上,它能夠觀察一個對象的 KVC key path 值的變化。

[KVC與KVO詳解](http://magicalboy.com/kvc_and_kvo/ "Title")

##8??. UIView 與CALayer的關(guān)系
說出自己的理解
UIView類似于畫布,CALayer類似于畫筆

[CALayer與UIView的關(guān)系](http://www.cnblogs.com/yswdarren/p/3555436.html "Title")

CALayer屬于Core Animation

1. UIView是iOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都是繼承自它。它本身完全是由CoreAnimation來實現(xiàn)的。它真正的繪圖部分,是由一個CALayer類來管理。UIView本身更像是一個CALayer的管理器,訪問它的跟繪圖和跟坐標(biāo)有關(guān)的屬性,例如frame,bounds等,實際上內(nèi)部都是在訪問它所包含的CALayer的相關(guān)屬性。
2. UIView 有一個屬性layer??梢苑祷厮腃ALayer實例。所有從UIView繼承來的對象都繼承了這個屬性。這意味著你可以轉(zhuǎn)換、縮放、旋轉(zhuǎn),甚至可以在Navigation bars,Tables,Text boxes等其它的View類上增加動畫。每個UIView都有一個層,控制著各自的內(nèi)容最終被顯示在屏幕上的方式。
3. CALayer的坐標(biāo)系統(tǒng)比UIView多了一個anchorPoint屬性,使用CGPoint結(jié)構(gòu)表示,值域是0~1。


##9??數(shù)據(jù)持久化存儲方案有哪些?

    plist文件(屬性列表)
    preference(偏好設(shè)置)
    NSKeyedArchiver(歸檔)
    SQLite 3
    CoreData

[數(shù)據(jù)持久化存儲方案](http://www.cocoachina.com/ios/20150720/12610.html "Title")

##1??0??多線程實現(xiàn)方式

4種實現(xiàn)方式 常用3種
    
    Pthreads
    NSThread
    GCD
    NSOperation & NSOperationQueue
[關(guān)于iOS多線程,你看我就夠了](http://www.itdecent.cn/p/0b0d9b1f1f19 "Title")
##1??1??網(wǎng)絡(luò)請求的GET 和POST的區(qū)別
一般情況下,Get是向服務(wù)器發(fā)索取數(shù)據(jù)的一種請求,而Post是向服務(wù)器提交數(shù)據(jù)的一種請求。

1. GET請求的數(shù)據(jù)會附在URL之后(就是把數(shù)據(jù)放置在HTTP協(xié)議頭中),以?分割URL和傳輸數(shù)據(jù),參數(shù)之間以&相連,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果數(shù)據(jù)是英文字母/數(shù)字,原樣發(fā)送,如果是空格,轉(zhuǎn)換為+,如果是中文/其他字符,則直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX為該符號以16進(jìn)制表示的ASCII。
2. POST把提交的數(shù)據(jù)則放置在是HTTP包的包體(請求頭、請求體)中。POST的安全性要比GET的安全性高。注意:這里所說的安全性和上面GET提到的“安全”不是同個概念。上面“安全”的含義僅僅是不作數(shù)據(jù)修改,而這里安全的含義是真正的Security的含義,比如:通過GET提交數(shù)據(jù),用戶名和密碼將明文出現(xiàn)在URL上,因為(1)登錄頁面有可能被瀏覽器緩存,(2)其他人查看瀏覽器的歷史紀(jì)錄,那么別人就可以拿到你的賬號和密碼了。



>我們更應(yīng)關(guān)注的是每道題背后所包含的理論知識體系。謹(jǐn)記面試題只是武功招式,知識體系才是內(nèi)功心法。
最后編輯于
?著作權(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)容

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