1、NSThread/NSOperation/GCD 三種多線程不同,分別使用場景?
?NSThread:
–優(yōu)點(diǎn):NSThread 比其他兩個輕量級,使用簡單
–缺點(diǎn):需要自己管理線程的生命周期、線程同步、加鎖、睡眠以及喚醒等。線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷
?NSOperation:
–不需要關(guān)心線程管理,數(shù)據(jù)同步的事情,可以把精力放在自己需要執(zhí)行的操作上
–NSOperation是面向?qū)ο蟮?/p>
?GCD:
–Grand Central Dispatch是由蘋果開發(fā)的一個多核編程的解決方案。iOS4.0+才能使用,是替代NSThread, NSOperation的高效和強(qiáng)大的技術(shù)
–GCD是基于C語言的
2、響應(yīng)鏈
iOS系統(tǒng)檢測到手指觸摸(Touch)操作時會將其打包成一個UIEvent對象,并放入當(dāng)前活動Application的事件隊列,單例的UIApplication會從事件隊列中取出觸摸事件并傳遞給單例的UIWindow來處理,UIWindow對象首先會使用hitTest:withEvent:方法尋找此次Touch操作初始點(diǎn)所在的視圖(View),即需要將觸摸事件傳遞給其處理的視圖,這個過程稱之為hit-test view。
UIWindow實例對象會首先在它的內(nèi)容視圖上調(diào)用hitTest:withEvent:,此方法會在其視圖層級結(jié)構(gòu)中的每個視圖上調(diào)用pointInside:withEvent:(該方法用來判斷點(diǎn)擊事件發(fā)生的位置是否處于當(dāng)前視圖范圍內(nèi),以確定用戶是不是點(diǎn)擊了當(dāng)前視圖),如果pointInside:withEvent:返回YES,則繼續(xù)逐級調(diào)用,直到找到touch操作發(fā)生的位置,這個視圖也就是要找的hit-test view。
hitTest:withEvent:方法的處理流程如下:
首先調(diào)用當(dāng)前視圖的pointInside:withEvent:方法判斷觸摸點(diǎn)是否在當(dāng)前視圖內(nèi);
若返回NO,則hitTest:withEvent:返回nil;
若返回YES,則向當(dāng)前視圖的所有子視圖(subviews)發(fā)送hitTest:withEvent:消息,所有子視圖的遍歷順序是從最頂層視圖一直到到最底層視圖,即從subviews數(shù)組的末尾向前遍歷,直到有子視圖返回非空對象或者全部子視圖遍歷完畢;
若第一次有子視圖返回非空對象,則hitTest:withEvent:方法返回此對象,處理結(jié)束;
如所有子視圖都返回非,則hitTest:withEvent:方法返回自身(self)。
3、__block與__weak的區(qū)別?
(1).__block不管是ARC還是MRC模式下都可以使用,可以修飾對象,還可以修飾基本數(shù)據(jù)類型。
__weak只能在ARC模式下使用,也只能修飾對象(NSString),不能修飾基本數(shù)據(jù)類型(int)。
(2).__block對象可以在block中被重新賦值,__weak不可以。
(3).__weak本身是可以避免循環(huán)引用的問題的,但是其會導(dǎo)致外部對象釋放了之后,block內(nèi)部也訪問不到這個對象的問題,我們可以通過在block內(nèi)部聲明一個__strong的變量來指向weakObj,使外部對象既能在block內(nèi)部保持住,又能避免循環(huán)引用的問題.
__block本身無法避免循環(huán)引用的問題,但是我們可以通過在block內(nèi)部手動把blockObj賦值為nil的方式來避免循環(huán)引用的問題。另外一點(diǎn)就是__block修飾的變量在block內(nèi)外都是唯一的,要注意這個特性可能帶來的隱患。
__block的理解是其實際上是把變量的作用域給改變了,應(yīng)該是提升了變量的作用域,使得在block內(nèi)部和外部所訪問的是同一個變量。
4、SDImage框架的緩存機(jī)制
(1)UIImageView+WebCache:setImageWithURL:placeholderImage:options:先顯示placeholderImage,同時由SDWebImageManager根據(jù)URL來在本地查找圖片。
(2)SDWebImageManager:downloadWithURL:delegate:options:userInfo:SDWebIma
geManager是將UIImageView+WebCache同SDImageCache鏈接起來的類,SDImageCache:queryDiskCacheForKey:delegate:userInfo:用來從緩存根據(jù)CacheKey查找圖片是否已經(jīng)在緩存中
(3)如果內(nèi)存中已經(jīng)有圖片緩存,SDWebImageManager會回調(diào)SDImageCacheDelegate :imageCache:didFindImage:forKey:userInfo:
(4)而UIImageView+WebCache則回調(diào)SDWebImageManagerDelegate:webImageManager:didFinishWithImage:來顯示圖片。
(5)如果內(nèi)存中沒有圖片緩存,那么生成NSInvocationOperation添加到隊列,從硬盤查找圖片是否已被下載緩存。
(6)根據(jù)URLKey在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在NSOperation進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào)notifyDelegate:。
(7)如果上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過小,會先清空內(nèi)存緩存)。SDImageCacheDelegate回調(diào)imageCache:didFindImage:forKey:userInfo:。進(jìn)而回調(diào)展示圖片。
(8)如果從硬盤緩存目錄讀取不到圖片,說明所有緩存都不存在該圖片,需要下載圖片,回調(diào)imageCache:didNotFindImageForKey:userInfo:。
(9)共享或重新生成一個下載器SDWebImageDownloader開始下載圖片。
(10)圖片下載由NSURLConnection來做,實現(xiàn)相關(guān)delegate來判斷圖片下載中、下載完成和下載失敗。
(11)connection:didReceiveData:中利用ImageIO做了按圖片下載進(jìn)度加載效果。
(12)connectionDidFinishLoading:數(shù)據(jù)下載完成后交給SDWebImageDecoder做圖片解碼處理。
(13)圖片解碼處理在一個NSOperationQueue完成,不會拖慢主線程UI。如果有需要對下載的圖片進(jìn)行二次處理,最好也在這里完成,效率會好很多。
(14)在主線程notifyDelegateOnMainThreadWithInfo:宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo:回調(diào)給SDWebImageDownloader。
(15)imageDownloader:didFinishWithImage:回調(diào)給SDWebImageManager告知圖片下載完成。
(16)通知所有的downloadDelegates下載完成,回調(diào)給需要的地方展示圖片。
(17)將圖片保存到SDImageCache中,內(nèi)存緩存和硬盤緩存同時保存。
(18)寫文件到硬盤在單獨(dú)NSInvocationOperation中完成,避免拖慢主線程。
(19)如果是在iOS上運(yùn)行,SDImageCache在初始化的時候會注冊notification到UIApplicationDidReceiveMemoryWarningNotification以及UIApplicationWillTerminateNotification,在內(nèi)存警告的時候清理內(nèi)存圖片緩存,應(yīng)用結(jié)束的時候清理過期圖片。
(20)SDWebImagePrefetcher可以預(yù)先下載圖片,方便后續(xù)使用。、
5、UITaBleView出現(xiàn)卡頓的可能情況
(1)imageView盡量設(shè)置為不透明
opque盡量設(shè)置為YES。
當(dāng)imageView的opque設(shè)置為YES的時候其alpha的屬性就會無效,imageView的半透明取決于其圖片半透明或者imageView本身的背景色合成的圖層view是半透明的。
如果圖片全部不是半透明就不會觸發(fā)圖層的blend操作,整個圖層就會不透明。
如果疊加的圖片有出現(xiàn)半透明的,就會立馬觸發(fā)圖層的blend操作,整個圖層不透明。
opque設(shè)為NO。
當(dāng)opque為NO的時候,圖層的半透明取決于圖片和其本身合成的圖層為結(jié)果。
背景色盡可能設(shè)為alpha值為1,當(dāng)某一塊圖層的alpha和其superView的背景色alpha不一樣的時候會觸發(fā)alpha合成操作,這是一項看似很簡單但卻是非常消耗CPU性能的操作。
(2)UIView的背景色設(shè)置
UIView的背景色盡量不要設(shè)置為clearColor,這樣也會觸發(fā)alpha疊加,在tableView滑動的時候是非常消耗性能的。子視圖的背景色盡可能設(shè)置成其superView的背景色,這樣圖層合成的時候不會觸發(fā)blend操作。最好不使用帶alpha通道的圖片,如果有alpha盡量讓美工取消alpha通道。
(3)cell上layer盡量避免使用圓角
在工作中關(guān)于滑動界面我們會時常遇到cell行設(shè)置頭像為圓角等需求,這時候我們盡量避免使用layder.cornerRadius,因為這會觸發(fā)離屏渲染。離屏渲染很耗時間。
離屏渲染:是GPU渲染區(qū)的一個渲染緩沖區(qū),我們所用的所有顯示屏的圖形圖像都是通過GPU進(jìn)行渲染,然后顯示在屏幕上。GPU負(fù)責(zé)渲染會把渲染的圖形放到緩沖區(qū)然后CPU就會發(fā)一個垂直信號顯示到屏幕。
如果要使用圓角,我們可以設(shè)置為layer.shouldRasterize
= YES,其實這個設(shè)置是觸發(fā)光柵化,可以大大提高渲染的性能。我的理解光柵化就是類似于cell的重用機(jī)制。
光柵化:把第一次渲染好的圖層放到緩沖區(qū),那么下次不需要再離屏渲染直接就可以從緩沖區(qū)拿去使用。
(4)優(yōu)化圖片的加載方式
我們都知道圖片的加載方式有兩種形式:
1、UIImage *headerImage = [UIImage
imageNamed:@"haodf.png";
2、UIImage * headerImage = [UIImageimageWithContentOfFile:@"haodf.png"];
我們講講兩種加載圖片方式的區(qū)別:
第一種:當(dāng)我們經(jīng)常需要這張圖片并且僅僅是小圖的時候,我們可以使用此種方式加載圖片。
這種方式是把圖片緩存在圖片緩存區(qū),當(dāng)我們使用的時候會通過圖片的名字也就是通過key的方式去查找圖片在緩存區(qū)的內(nèi)存地址。
當(dāng)我們使用很多圖片的時候系統(tǒng)就會開辟很多內(nèi)存來存儲圖片,所以qq、微信我們很多時候都會去清除緩存操作。
第二種:當(dāng)我們使用工程里面的一張大圖并且使用次數(shù)很少甚至為1次的時候,我們優(yōu)先會采用這種方式加載圖片,這種方式當(dāng)使用完圖片的時候會立即丟棄釋放資源,所以對性能不會帶來負(fù)擔(dān)。
(5)盡量延遲圖片的加載
當(dāng)我們在滑動頁面的時候尤其對于那種布局特別復(fù)雜的cell,滑動的時候不要加載圖片,當(dāng)滑動停止得時候再進(jìn)行圖片的加載。
我們都知道不管是UITableView還是ScrollView在滾動的時候需要顯示東西都是通過runLoop去拿。
當(dāng)滾動的時候runLoop會處于NSRunLoopTrackingMode的模式,我們可以通過一個主線程隊列dispatch_after或者selfPerformSelector設(shè)置runLoop的模式為NSDefaultRunLoopMode模式,就可以做到停止?jié)L動再加載圖片。
注:其實嚴(yán)格意義上selfPerformSelector的事件就是在主線程隊列中等待。
(6)優(yōu)先加載理念
一直很好奇墨跡天氣這款app基本都是很炫的圖片,是如何做到滑動時候不卡頓的呢,在cocoachina上有幸認(rèn)識了一位墨跡天氣的大牛,說是采用優(yōu)先加載的理念,既先展示一部分,當(dāng)滑動的時候再加載下面的一部分這樣就保持流暢。至于具體沒透露。
(7)避免阻塞主線程
讓圖片的繪制、圖片的下載、對象的創(chuàng)建、文本的渲染等這些耗時的操作盡可能采用子線程異步的方式去處理,對于layer及UI的操作不得不在主線程里面,只能想辦法優(yōu)化,所以此處給大家推薦Facebook的得力之作ASDK,有興趣的可以好好研究下,現(xiàn)在好多公司都進(jìn)行采用。
(8)xib、storyBoard、純代碼
蘋果推出storyboard確實為開發(fā)者節(jié)省了大量的時間,提高了開發(fā)效率,但是對于那種
復(fù)雜的滑動界面,利用storyboard是非常消耗資源的,不信的可以試試用性能工具timeProfie看看cpu所占的性能百分比,其CPU的資源遠(yuǎn)遠(yuǎn)大于純代碼布局,我看了一個國外的網(wǎng)站介紹,這兩種方式初始化對象分配內(nèi)存的先后方式完全不一樣,至于具體細(xì)節(jié)有興趣的可以找相關(guān)資料研究。
當(dāng)然對于那種重用性不強(qiáng)固定不怎么變化的界面還是很喜歡storyboard,一蹴而就,節(jié)省成本。
6、imageName和imageWithContentsOfFile、init的區(qū)別
第一種方法(imageName)為常見方法,利用它可以方便加載資源圖片。用imageNamed的方式加載時,會把圖像數(shù)據(jù)根據(jù)它的名字緩存在系統(tǒng)內(nèi)存中,以提高imageNamed方法獲得相同圖片的image對象的性能。即使生成的對象被autoReleasePool釋放了,這份緩存也不釋放。而且沒有明確的釋放方法。如果圖像比較大,或者圖像比較多,用這種方式會消耗很大的內(nèi)存。
第二種方法(imageWithContentsOfFile)加載的圖片是不會緩存的。得到的對象時autoRelease的,當(dāng)autoReleasePool釋放時才釋放。
第三種方法(init)要手動release掉。不系統(tǒng)緩存。release后立即釋放,一般用在封面等圖比較大的地方。
用imageNamed的方式加載時,系統(tǒng)會把圖像Cache到內(nèi)存。如果圖像比較大,或者圖像比較多,用這種方式會消耗很大的內(nèi)存,而且釋放圖像的內(nèi)存是一件相對來說比較麻煩的事情。例如:如果利用imageNamed的方式加載圖像到一個動態(tài)數(shù)組NSMutableArray,然后將將數(shù)組賦予一個UIView的對象的animationImages進(jìn)行逐幀動畫,那么這將會很有可能造成內(nèi)存泄露。并且釋放圖像所占據(jù)的內(nèi)存也不會那么簡單。但是利用imageNamed加載圖像也有自己的優(yōu)勢。對于同一個圖像系統(tǒng)只會把它Cache到內(nèi)存一次,這對于圖像的重復(fù)利用是非常有優(yōu)勢的。例如:你需要在一個TableView里重復(fù)加載同樣一個圖標(biāo),那么用imageNamed加載圖像,系統(tǒng)會把那個圖標(biāo)Cache到內(nèi)存,在Table里每次利用那個圖像的時候,只會把圖片指針指向同一塊內(nèi)存。這種情況使用imageNamed加載圖像就會變得非常有效。
7、nil、Nil、NULL與NSNUll的區(qū)別
(1)nil
指向一個對象的指針為空 ,在Objective-C中用于id類型的對象
NSString
*name = nil;
(2)Nil
指向一個類的指針為空,在Objective-C中用于Class類型的對象
Class aClass = Nil;
(3)NULL
指向C類型的指針為空,多用于如下例子:
int*pInt???? = NULL;
(4)NSNull
在Objective-C中是一個類,只是名字中有個Null,NSNull有+
(NSNull *)null;單例方法,多用于集合(NSArray,NSDictionary)中值為空的對象
8、bool與BOOL的區(qū)別
有的文章對bool與BOOL的區(qū)別做以下解釋,但這種解釋是錯誤的,BOOL b = 8960;結(jié)果是YES.
objective-c中的BOOL實際上是一種對帶符號的字符類型(signed char)的類型定義(typedef),它使用8位的存儲空間。通過#define指令把YES定義為1,NO定義為0。
注意:objective-c并不會將BOOL作為僅能保存YES或NO值的真正布爾類型來處理。編譯器仍將BOOL認(rèn)作8位二進(jìn)制數(shù),YES和NO值只是在習(xí)慣上的一種理解。
問題:如果不小心將一個大于1字節(jié)的整型值(比如short或int)賦給一個BOOL變量,那么只有低位字節(jié)會用作BOOL值。如果該低位字節(jié)剛好為0(比如8960,寫成十六進(jìn)制為0x2300),BOOL值將會被認(rèn)作是0,即NO值。而對于bool類型,只有true和false的區(qū)別,即0為false,非0為true。
舉例:
BOOL b1=8960; //實際是NO,因為8960換成十六進(jìn)制為0x2300,BOOL只有8位存儲空間,取0x2300的低8位,00,所以是NO
bool b2=8960;//實際是true,因為bool類型,非0即為true。
9、int與NSInteger的區(qū)別
當(dāng)需要使用int類型的變量的時候,可以像寫C的程序一樣,用int,也可以用NSInteger,但更推薦使用NSInteger,因為這樣就不用考慮設(shè)備是32位的還是64位的。
樓主你可以看如下定義:
#if?__LP64__?||?(TARGET_OS_EMBEDDED?&&?!TARGET_OS_IPHONE)?||?TARGET_OS_WIN32?||?NS_BUILD_32_LIKE_64
typedef?long?NSInteger;
typedef?unsigned?long?NSUInteger;
#else
typedef?int?NSInteger;
typedef?unsigned?int?NSUInteger;
#endif
32位編譯器:
char:1個字節(jié)
char*(即指針變量): 4個字節(jié)(32位的尋址空間是2^32,即32個bit,也就是4個字節(jié)。同理64位編譯器)
short int : 2個字節(jié)
int:4個字節(jié)
unsigned int : 4個字節(jié)
float:??4個字節(jié)
double:???8個字節(jié)
long:???4個字節(jié)
long long:??8個字節(jié)
unsigned long:??4個字節(jié)
64位編譯器:
char:1個字節(jié)
char*(即指針變量): 8個字節(jié)
short int : 2個字節(jié)
int:4個字節(jié)
unsignedint : 4個字節(jié)
float:4個字節(jié)
double:8個字節(jié)
long:8個字節(jié)
long long:8個字節(jié)
unsigned long:8個字節(jié)
10、IOS系統(tǒng)架構(gòu)
iOS的系統(tǒng)架構(gòu)分為四個層次:核心操作系統(tǒng)層(Core OS layer)、核心服務(wù)層(Core
Services layer)、媒體層(Media layer)和可觸摸層(Cocoa Touch layer)。
1、Core OS是位于iOS系統(tǒng)架構(gòu)最下面的一層是核心操作系統(tǒng)層,它包括內(nèi)存管理、文件系統(tǒng)、電源管理以及一些其他的操作系統(tǒng)任務(wù)。它可以直接和硬件設(shè)備進(jìn)行交互。作為app開發(fā)者不需要與這一層打交道。
2、Core Services是核心服務(wù)層,可以通過它來訪問iOS的一些服務(wù)。
3、Media是媒體層,通過它我們可以在應(yīng)用程序中使用各種媒體文件,進(jìn)行音頻與視頻的錄制,圖形的繪制,以及制作基礎(chǔ)的動畫效果。
4、Cocoa Touch是可觸摸層,這一層為我們的應(yīng)用程序開發(fā)提供了各種有用的框架,并且大部分與用戶界面有關(guān),本質(zhì)上來說它負(fù)責(zé)用戶在iOS設(shè)備上的觸摸交互操作。
11、CoreFoundtion對Socket的操作方法
Core Foundation層:因為直接使用socket需要更多的編程工作,所以蘋果對OS層的socket進(jìn)行簡單的封裝以簡化編程任務(wù)。該層提供了CFNetwork和CFNetServices,其中CFNetwork又是基于CFStream和CFSocket。
12、Object-c的類可以多重繼承么?可以實現(xiàn)多個接口么?Category是什么?重寫一個類的方式用繼承好還是分類好?為什么?
Object- c的類不可以多重繼承;可以實現(xiàn)多個接口,通過實現(xiàn)多個接口可以完成C++的多重繼承;Category是類別,一般情況用分類好,用Category去重寫類的方法,僅對本Category有效,不會影響到其他類與原有類的關(guān)系。
13.自動釋放池的作用
自動釋放池:是用來自動釋放對象的,不需要關(guān)心對象釋放的時間,不需要關(guān)心對象什么時候調(diào)用release
自動釋放池釋放的時間:事件循環(huán)結(jié)束
自動釋放池原理: 當(dāng)池子結(jié)束,會想池子里面的所有對象發(fā)送一條release消息
自動釋放池使用: 1.創(chuàng)建對象2.加入自動釋放池
14、AFN 2.0與AFN 3.0的不同?
AFNetworking 2.0開始使用NSURLConnection的基礎(chǔ)API,以及較新基于NSURLSession的API的選項。AFNetworking 3.0現(xiàn)已完全基于NSURLSession的API,這降低了維護(hù)的負(fù)擔(dān),同時支持蘋果增強(qiáng)關(guān)于NSURLSession提供的任何額外功能。
由于Xcode 7中,NSURLConnection的API已經(jīng)正式被蘋果棄用。雖然該API將繼續(xù)運(yùn)行,但將沒有新功能將被添加,并且蘋果已經(jīng)通知所有基于網(wǎng)絡(luò)的功能,以充分使NSURLSession向前發(fā)展。
15、Git集中式還是分布式?Git與SVN代碼管理方式的區(qū)別?
Git分布式管理
(1)GIT是分布式的,SVN不是:
這是GIT和其它非分布式的版本控制系統(tǒng),例如SVN,CVS等,最核心的區(qū)別。
GIT跟SVN一樣有自己的集中式版本庫或服務(wù)器。但,GIT更傾向于被使用于分布式模式,也就是每個開發(fā)人員從中心版本庫/服務(wù)器上chect out代碼后會在自己的機(jī)器上克隆一個自己的版本庫??梢赃@樣說,如果你被困在一個不能連接網(wǎng)絡(luò)的地方時,就像在飛機(jī)上,地下室,電梯里等,你仍然能夠提交文件,查看歷史版本記錄,創(chuàng)建項目分支,等。對一些人來說,這好像沒多大用處,但當(dāng)你突然遇到?jīng)]有網(wǎng)絡(luò)的環(huán)境時,這個將解決你的大麻煩。
(2)GIT把內(nèi)容按元數(shù)據(jù)方式存儲,而SVN是按文件:
所有的資源控制系統(tǒng)都是把文件的元信息隱藏在一個類似.svn,.cvs等的文件夾里。如果你把.git目錄的體積大小跟.svn比較,你會發(fā)現(xiàn)它們差距很大。因為.git目錄是處于你的機(jī)器上的一個克隆版的版本庫,它擁有中心版本庫上所有的東西,例如標(biāo)簽,分支,版本記錄等。
(3)GIT分支和SVN的分支不同:
分支在SVN中一點(diǎn)不特別,就是版本庫中的另外的一個目錄。如果你想知道是否合并了一個分支,你需要手工運(yùn)行像這樣的命令svn propget svn:mergeinfo,來確認(rèn)代碼是否被合并。感謝Ben同學(xué)指出這個特征。所以,經(jīng)常會發(fā)生有些分支被遺漏的情況。
然而,處理GIT的分支卻是相當(dāng)?shù)暮唵魏陀腥?。你可以從同一個工作目錄下快速的在幾個分支間切換。你很容易發(fā)現(xiàn)未被合并的分支,你能簡單而快捷的合并這些文件。