Swift
1> Swift和OC的區(qū)別
1.1> Swift沒有地址/指針的概念
1.2> 泛型
1.3> 類型嚴(yán)謹(jǐn) 對(duì)比oc的動(dòng)態(tài)綁定
1.編譯鏈接
1> id和instancetype的區(qū)別
instancetype只能做返回值,編譯時(shí)判斷真實(shí)類型,不符合發(fā)警告
特殊情況: 關(guān)聯(lián)類型返回方法,如類方法alloc或new開頭,實(shí)例方法中,以autorelease,init,retain,或self開頭
三: synthesize&denamic
1:通過@synthesize 指令告訴編譯器在編譯期間產(chǎn)生getter/setter方法硼被。
2: 通過@dynamic指令,自己實(shí)現(xiàn)方法桦锄。
有些存取是在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建的永淌,如在CoreData的NSManagedObject類使用的某些濒生。如果你想這些情況下,聲明和使用屬性控乾,但要避免缺少方法在編譯時(shí)的警告么介,你可以使用@dynamic動(dòng)態(tài)指令,而不是@synthesize合成指令蜕衡。
9.在項(xiàng)目開發(fā)中常用 的開發(fā)工具有哪些壤短?有哪些心得?
instrument
beyondCompare
git
七: UITableView&UICollection
UICollectionView是iOS6新引進(jìn)的API慨仿,用于展示集合視圖久脯,布局更加靈活,其用法類似于UITableView镰吆。而 UICollectionView帘撰、UICollectionViewCell與UITableView、UITableViewCell在用法上有相似 的也有不同的万皿,下面是一些基本的使用方法:
對(duì)于UITableView摧找,僅需要UITableViewDataSource,UITableViewDelegate這兩個(gè)協(xié)議核行,使用 UICollectionView需要實(shí)現(xiàn)UICollectionViewDataSource, UICollectionViewDelegate,UICollectionViewDelegateFlowLayout這三個(gè)協(xié)議蹬耘,這是因?yàn)?UICollectionViewDelegateFlowLayout實(shí)際上是UICollectionViewDelegate的一個(gè)子協(xié)議芝雪,它繼承 了UICollectionViewDelegate,它的作用是提供一些定義UICollectionView布局模式的函數(shù)
八:NSProxy&NSObject
NSObjetct:
NSObject協(xié)議組對(duì)所有的Object-C下的objects都生效综苔。 如果objects遵從該協(xié)議惩系,就會(huì)被看作是first-class objects(一級(jí)類)。 另外休里,遵從該協(xié)議的objects的retain蛆挫,release,autorelease等方法也服從objects的管理和在Foundation中 定義的釋放方法妙黍。一些容器中的對(duì)象也可以管理這些objects悴侵,比如 說NSArray 和NSDictionary定義的對(duì)象。 Cocoa的根類也遵循該協(xié)議拭嫁,所以所有繼承NSObjects的objects都有遵循該協(xié)議的特性可免。
NSProXY:
NSProxy 是一個(gè)虛基類,它為一些表現(xiàn)的像是其它對(duì)象替身或者并不存在的對(duì)象定義一套API做粤。一般的浇借,發(fā)送給代理的消息被轉(zhuǎn)發(fā)給一個(gè)真實(shí)的對(duì)象或者代理本身 load(或者將本身轉(zhuǎn)換成)一個(gè)真實(shí)的對(duì)象作喘。NSProxy的基類可以被用來透明的轉(zhuǎn)發(fā)消息或者耗費(fèi)巨大的對(duì)象的lazy 初始化采盒。
Object&Swift
Obejective-C復(fù)雜的語法孔庭,更加簡(jiǎn)單易用袍嬉、有未來,讓許多開發(fā)者心動(dòng)不已旷赖,Swift明顯的特點(diǎn)有:
蘋果宣稱 Swift 的特點(diǎn)是:快速寞宫、現(xiàn)代供炼、安全吼和、互動(dòng)涨薪,而且明顯優(yōu)于 Objective-C 語言
可以使用現(xiàn)有的 Cocoa 和 Cocoa Touch 框架
Swift 取消了 Objective C 的指針及其他不安全訪問的使用
舍棄 Objective C 早期應(yīng)用 Smalltalk 的語法,全面改為句點(diǎn)表示法
提供了類似 Java 的名字空間(namespace)炫乓、泛型(generic)刚夺、運(yùn)算對(duì)象重載(operator overloading)
Swift 被簡(jiǎn)單的形容為 “沒有 C 的 Objective-C”(Objective-C without the C)
為蘋果開發(fā)工具帶來了Xcode Playgrounds功能,該功能提供強(qiáng)大的互動(dòng)效果末捣,能讓Swift源代碼在撰寫過程中實(shí)時(shí)顯示出其運(yùn)行結(jié)果侠姑;
基于C和Objective-C,而卻沒有C的一些兼容約束箩做;
采用了安全的編程模式莽红;
界面基于Cocoa和Cocoa Touch框架;
保留了Smalltalk的動(dòng)態(tài)特性
二十一:傳值通知&推送通知(本地&遠(yuǎn)程)
傳值通知:類似通知卒茬,代理船老,Block實(shí)現(xiàn)值得傳遞
推送通知:推送到用戶手機(jī)對(duì)應(yīng)的App上(主要是不再前臺(tái)的情況)
本地通知。
local notification圃酵,用于基于時(shí)間行為的通知柳畔,比如有關(guān)日歷或者todo列表的小應(yīng)用。另外郭赐,應(yīng)用如果在后臺(tái)執(zhí)行薪韩,iOS允許它在受限的時(shí)間內(nèi)運(yùn) 行,它也會(huì)發(fā)現(xiàn)本地通知有用捌锭。比如俘陷,一個(gè)應(yīng)用,在后臺(tái)運(yùn)行观谦,向應(yīng)用的服務(wù)器端獲取消息拉盾,當(dāng)消息到達(dá)時(shí),比如下載更新版本的提示消息豁状,通過本地通知機(jī)制通知 用戶捉偏。
本地通知是UILocalNotification的實(shí)例,主要有三類屬性:
scheduled time泻红,時(shí)間周期夭禽,用來指定iOS系統(tǒng)發(fā)送通知的日期和時(shí)間;
notification type谊路,通知類型讹躯,包括警告信息、動(dòng)作按鈕的標(biāo)題缠劝、應(yīng)用圖標(biāo)上的badge(數(shù)字標(biāo)記)和播放的聲音潮梯;
自定義數(shù)據(jù),本地通知可以包含一個(gè)dictionary類型的本地?cái)?shù)據(jù)剩彬。
對(duì)本地通知的數(shù)量限制酷麦,iOS最多允許最近本地通知數(shù)量是64個(gè),超過限制的本地通知將被iOS忽略喉恋。
遠(yuǎn)程通知(需要服務(wù)器)沃饶。
流程大概是這樣的
1.生成CertificateSigningRequest.certSigningRequest文件
2.將CertificateSigningRequest.certSigningRequest上傳進(jìn)developer,導(dǎo)出.cer文件
3.利用CSR導(dǎo)出P12文件
4.需要準(zhǔn)備下設(shè)備token值(無空格)
5.使用OpenSSL合成服務(wù)器所使用的推送證書
一般使用極光推送轻黑,步驟是一樣的糊肤,只是我們使用的服務(wù)器是極光的,不需要自己大服務(wù)器氓鄙!
二十二:第三方庫&第三方平臺(tái)
第三方庫:一般是指大牛封裝好的一個(gè)框架(庫)馆揉,或者第三方給我們提供的一個(gè)庫,這里比較籠統(tǒng) *第三方平臺(tái):指第三方提供的一些服務(wù)抖拦,其實(shí)很多方面跟第三方庫是一樣的升酣,但是還是存在一些區(qū)別舷暮。
區(qū)別:
庫:AFN,ASI噩茄,Alomofire下面,MJRefresh,MJExtension绩聘,MBProgressHUD
平臺(tái):極光沥割,百度,友盟凿菩,Mob机杜,環(huán)信
1.imageName和ImageWithContextOfFile的區(qū)別?哪個(gè)性能高
(1)用imageNamed的方式加載時(shí)衅谷,圖片使用完畢后緩存到內(nèi)存中椒拗,內(nèi)存消耗多,加載速度快会喝。即使生成的對(duì)象被 autoReleasePool釋放了陡叠,這份緩存也不釋放,如果圖像比較大肢执,或者圖像比較多枉阵,用這種方式會(huì)消耗很大的內(nèi)存。
imageNamed采用了緩存機(jī)制预茄,如果緩存中已加載了圖片兴溜,直接從緩存讀就行了,每次就不用再去讀文件了耻陕,效率會(huì)更高 拙徽。
(2)ImageWithContextOfFile加載,圖片是不會(huì)緩存的诗宣,加載速度慢膘怕。
(3)大量使用imageNamed方式會(huì)在不需要緩存的地方額外增加開銷CPU的時(shí)間.當(dāng)應(yīng)用程序需要加載一張比較大的圖片并且使用一次性,那么其實(shí)是沒有必要去緩存這個(gè)圖片的召庞,用imageWithContentsOfFile是最為經(jīng)濟(jì)的方式,這樣不會(huì)因?yàn)閁IImage元素較多情況下潮酒,CPU會(huì)被逐個(gè)分散在不必要緩存上浪費(fèi)過多時(shí)間.
十:NSCache&NSDcitionary
NSCache與可變集合有幾點(diǎn)不同:
NSCache類結(jié)合了各種自動(dòng)刪除策略盼砍,以確保不會(huì)占用過多的系統(tǒng)內(nèi)存压储。如果其它應(yīng)用需要內(nèi)存時(shí)路操,系統(tǒng)自動(dòng)執(zhí)行這些策略。當(dāng)調(diào)用這些策略時(shí)诅诱,會(huì)從緩存中刪除一些對(duì)象髓堪,以最大限度減少內(nèi)存的占用。
NSCache是線程安全的,我們可以在不同的線程中添加干旁、刪除和查詢緩存中的對(duì)象驶沼,而不需要鎖定緩存區(qū)域。
不像NSMutableDictionary對(duì)象争群,一個(gè)緩存對(duì)象不會(huì)拷貝key對(duì)象商乎。
NSCache和NSDictionary類似,不同的是系統(tǒng)回收內(nèi)存的時(shí)候它會(huì)自動(dòng)刪掉它的內(nèi)容祭阀。
(1)可以存儲(chǔ)(當(dāng)然是使用內(nèi)存)
(2)保持強(qiáng)應(yīng)用, 無視垃圾回收. =>這一點(diǎn)同 NSMutableDictionary
(3)有固定客戶.
四: UIView的setNeedsDisplay和setNeedsLayout方法
1、在Mac OS中NSWindow的父類是NSResponder鲜戒,而在i OS 中UIWindow 的父類是UIVIew专控。程序一般只有一個(gè)窗口但是會(huì)又很多視圖。
2遏餐、UIView的作用:描畫和動(dòng)畫伦腐,視圖負(fù)責(zé)對(duì)其所屬的矩形區(qū)域描畫、布局和子視圖管理失都、事件處理柏蘑、可以接收觸摸事件、事件信息的載體粹庞、等等咳焚。
3、UIViewController 負(fù)責(zé)創(chuàng)建其管理的視圖及在低內(nèi)存的時(shí)候?qū)⑺麄儚膬?nèi)存中移除庞溜。還為標(biāo)準(zhǔn)的系統(tǒng)行為進(jìn)行響應(yīng)革半。
4、layOutSubViews 可以在自己定制的視圖中重載這個(gè)方法流码,用來調(diào)整子視圖的尺寸和位置又官。
5、UIView的setNeedsDisplay(需要重新顯示,繪制)和setNeedsLayout(需要重新布局)方法漫试。首先兩個(gè)方法都是異步執(zhí)行的六敬。而 setNeedsDisplay會(huì)調(diào)用自動(dòng)調(diào)用drawRect方法,這樣可以拿到UIGraphicsGetCurrentContext驾荣,就可以畫畫 了外构。而setNeedsLayout會(huì)默認(rèn)調(diào)用layoutSubViews,就可以處理子視圖中的一些數(shù)據(jù)秘车。
綜上所述:setNeedsDisplay方便繪圖典勇,而layoutSubViews方便出來數(shù)據(jù)
setNeedDisplay告知視圖它發(fā)生了改變,需要重新繪制自身叮趴,就相當(dāng)于刷新界面.
六: UILayer&UIView
UIView是iOS系統(tǒng)中界面元素的基礎(chǔ)割笙,所有的界面元素都繼承自它。它本身完全是由CoreAnimation來實(shí)現(xiàn)的(Mac下似乎不是這 樣)。它真正的繪圖部分伤溉,是由一個(gè)叫CALayer(Core Animation Layer)的類來管理般码。UIView本身,更像是一個(gè)CALayer的管理器乱顾,訪問它的跟繪圖和跟坐標(biāo)有關(guān)的屬性板祝,例如frame,bounds等等走净, 實(shí)際上內(nèi)部都是在訪問它所包含的CALayer的相關(guān)屬性券时。
UIView有個(gè)重要屬性layer,可以返回它的主CALayer實(shí)例伏伯。
UIView的CALayer類似UIView的子View樹形結(jié)構(gòu)橘洞,也可以向它的layer上添加子layer,來完成某些特殊的表示说搅。即CALayer層是可以嵌套的炸枣。
UIView的layer樹形在系統(tǒng)內(nèi)部,被維護(hù)著三份copy弄唧。分別是邏輯樹适肠,這里是代碼可以操縱的;動(dòng)畫樹候引,是一個(gè)中間層侯养,系統(tǒng)就在這一層上更改屬性,進(jìn)行各種渲染操作澄干;顯示樹沸毁,其內(nèi)容就是當(dāng)前正被顯示在屏幕上得內(nèi)容。
動(dòng)畫的運(yùn)作:對(duì)UIView的subLayer(非主Layer)屬性進(jìn)行更改傻寂,系統(tǒng)將自動(dòng)進(jìn)行動(dòng)畫生成息尺,動(dòng)畫持續(xù)時(shí)間的缺省值似乎是0.5秒。
坐標(biāo)系統(tǒng):CALayer的坐標(biāo)系統(tǒng)比UIView多了一個(gè)anchorPoint屬性疾掰,使用CGPoint結(jié)構(gòu)表示搂誉,值域是0~1,是個(gè)比例值静檬。
渲染:當(dāng)更新層炭懊,改變不能立即顯示在屏幕上。當(dāng)所有的層都準(zhǔn)備好時(shí)拂檩,可以調(diào)用setNeedsDisplay方法來重繪顯示侮腹。
變換:要在一個(gè)層中添加一個(gè)3D或仿射變換,可以分別設(shè)置層的transform或affineTransform屬性稻励。
變形:Quartz Core的渲染能力父阻,使二維圖像可以被自由操縱愈涩,就好像是三維的。圖像可以在一個(gè)三維坐標(biāo)系中以任意角度被旋轉(zhuǎn)加矛,縮放和傾斜履婉。CATransform3D的一套方法提供了一些魔術(shù)般的變換效果。
九: layoutSubViews&drawRects
layoutSubviews在以下情況下會(huì)被調(diào)用(視圖位置變化是觸發(fā)):
1斟览、init初始化不會(huì)觸發(fā)layoutSubviews毁腿。
2撒顿、addSubview會(huì)觸發(fā)layoutSubviews炼吴。
3谤狡、設(shè)置view的Frame會(huì)觸發(fā)layoutSubviews愚墓,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化。
4荷憋、滾動(dòng)一個(gè)UIScrollView會(huì)觸發(fā)layoutSubviews蜀涨。
5炕婶、旋轉(zhuǎn)Screen會(huì)觸發(fā)父UIView上的layoutSubviews事件侍瑟。
6、改變一個(gè)UIView大小的時(shí)候也會(huì)觸發(fā)父UIView上的layoutSubviews事件丙猬。
7涨颜、直接調(diào)用setLayoutSubviews。
drawRect在以下情況下會(huì)被調(diào)用:
1茧球、如果在UIView初始化時(shí)沒有設(shè)置rect大小庭瑰,將直接導(dǎo)致drawRect不被自動(dòng)調(diào)用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 兩方法之后掉用的.所以不用擔(dān)心在 控制器中,這些View的drawRect就開始畫了.這樣可以在控制器中設(shè)置一些值給View(如果這些View draw的時(shí)候需要用到某些變量 值).
2抢埋、該方法在調(diào)用sizeToFit后被調(diào)用弹灭,所以可以先調(diào)用sizeToFit計(jì)算出size。然后系統(tǒng)自動(dòng)調(diào)用drawRect:方法揪垄。
3穷吮、通過設(shè)置contentMode屬性值為UIViewContentModeRedraw。那么將在每次設(shè)置或更改frame的時(shí)候自動(dòng)調(diào)用drawRect:饥努。
4捡鱼、直接調(diào)用setNeedsDisplay,或者setNeedsDisplayInRect:觸發(fā)drawRect:酷愧,但是有個(gè)前提條件是rect不能為0驾诈。
drawRect方法使用注意點(diǎn):
1、 若使用UIView繪圖溶浴,只能在drawRect:方法中獲取相應(yīng)的contextRef并繪圖乍迄。如果在其他方法中獲取將獲取到一個(gè)invalidate 的ref并且不能用于畫圖。drawRect:方法不能手動(dòng)顯示調(diào)用士败,必須通過調(diào)用setNeedsDisplay 或 者 setNeedsDisplayInRect闯两,讓系統(tǒng)自動(dòng)調(diào)該方法。
2、若使用calayer繪圖生蚁,只能在drawInContext: 中(類似魚drawRect)繪制噩翠,或者在delegate中的相應(yīng)方法繪制。同樣也是調(diào)用setNeedDisplay等間接調(diào)用以上方法 3邦投、若要實(shí)時(shí)畫圖伤锚,不能使用gestureRecognizer,只能使用touchbegan等方法來掉用setNeedsDisplay實(shí)時(shí)刷新屏幕
二十六:UDID&UUID
UDID是Unique Device Identifier的縮寫,中文意思是設(shè)備唯一標(biāo)識(shí).
在很多需要限制一臺(tái)設(shè)備一個(gè)賬號(hào)的應(yīng)用中經(jīng)常會(huì)用到,在Symbian時(shí)代,我們是使用IMEI作為設(shè)備的唯一標(biāo)識(shí)的,可惜的是Apple官方不允許開發(fā)者獲得設(shè)備的IMEI.
[UIDevice currentDevice] uniqueIdentifier]
但是我們需要注意的一點(diǎn)是,對(duì)于已越獄了的設(shè)備,UDID并不是唯一的.使用Cydia插件UDIDFaker,可以為每一個(gè)應(yīng)用分配不同的UDID. 所以UDID作為標(biāo)識(shí)唯一設(shè)備的用途已經(jīng)不大了.
UUID是Universally Unique Identifier的縮寫,中文意思是通用唯一識(shí)別碼.
由網(wǎng)上資料顯示,UUID是一個(gè)軟件建構(gòu)的標(biāo)準(zhǔn),也是被開源軟件基金會(huì)(Open Software Foundation,OSF)的組織在分布式計(jì)算環(huán)境(Distributed Computing Environment,DCE)領(lǐng)域的一部份.UUID的目的,是讓分布式系統(tǒng)中的所有元素,都能有唯一的辨識(shí)資訊,而不需要透過中央控制端來做辨識(shí)資 訊的指定.
二十七:CPU&GPU
CPU:中央處理器(英文Central Processing Unit)是一臺(tái)計(jì)算機(jī)的運(yùn)算核心和控制核心志衣。CPU屯援、內(nèi)部存儲(chǔ)器和輸入/輸出設(shè)備是電子計(jì)算機(jī)三大核心部件。其功能主要是解釋計(jì)算機(jī)指令以及處理計(jì)算機(jī)軟件中的數(shù)據(jù)念脯。
GPU:英文全稱Graphic Processing Unit狞洋,中文翻譯為“圖形處理器”。一個(gè)專門的圖形核心處理器绿店。GPU是顯示卡的“大腦”吉懊,決定了該顯卡的檔次和大部分性能,同時(shí)也是2D顯示卡和3D 顯示卡的區(qū)別依據(jù)假勿。2D顯示芯片在處理3D圖像和特效時(shí)主要依賴CPU的處理能力借嗽,稱為“軟加速”。3D顯示芯片是將三維圖像和特效處理功能集中在顯示芯 片內(nèi)转培,也即所謂的“硬件加速”功能恶导。
二十八:點(diǎn)(pt)&像素(px)
像素(pixels)是數(shù)碼顯示上最小的計(jì)算單位。在同一個(gè)屏幕尺寸浸须,更高的PPI(每英寸的像素?cái)?shù)目)惨寿,就能顯示更多的像素,同時(shí)渲染的內(nèi)容也會(huì)更清晰删窒。
點(diǎn)(points)是一個(gè)與分辨率無關(guān)的計(jì)算單位裂垦。根據(jù)屏幕的像素密度,一個(gè)點(diǎn)可以包含多個(gè)像素(例如肌索,在標(biāo)準(zhǔn)Retina顯示屏上1 pt里有2 x 2個(gè)像素)缸废。
當(dāng)你為多種顯示設(shè)備設(shè)計(jì)時(shí),你應(yīng)該以“點(diǎn)”為單位作參考驶社,但設(shè)計(jì)還是以像素為單位設(shè)計(jì)的企量。這意味著仍然需要以3種不同的分辨率導(dǎo)出你的素材,不管你以哪種分辨率設(shè)計(jì)你的應(yīng)用亡电。
二十九:屬性與成員變量:
成員變量是不與外界接觸的變量届巩,應(yīng)用于類的內(nèi)部,如果你說那用@Public外部不就是可以訪問了么份乒。簡(jiǎn)單的說public只能適當(dāng)使用恕汇,不要泛濫腕唧,否則就像你把鑰匙插在你自己家門上了。誰來都可以開門瘾英。毫無安全性枣接。
由于成員變量的私有性,為了解決外部訪問的問題就有了屬性變量缺谴。屬性變量個(gè)人認(rèn)為最大的好處就是讓其他對(duì)象訪問這個(gè)變量但惶。而且你可以設(shè)置只讀、可寫等等屬性湿蛔,同時(shí)設(shè)置的方法我們也可以自己定義膀曾。記住一點(diǎn),屬性變量主要是用于與其他對(duì)象相互交互的變量
如果對(duì)于上面所說還是含糊不清那就記住這幾點(diǎn)吧阳啥!
1.只有類內(nèi)使用添谊,屬性為private,那么就定義成員變量察迟。
2.如果你發(fā)現(xiàn)你需要的這個(gè)屬性需要是public的斩狱,那么毫不猶豫就用屬性在.h中定義。
3.當(dāng)你自己內(nèi)部需要setter實(shí)現(xiàn)一些功能的時(shí)候扎瓶,用屬性在.m中定義所踊。
4.當(dāng)你自己內(nèi)部需要getter實(shí)現(xiàn)一些功能的時(shí)候燥透,用屬性在.m中定義逞度。
1.int和NSInteger的區(qū)別
NSInteger表示當(dāng)前cpu下整型所占最大字節(jié),不同CPU的long型所占字節(jié)不同,32位int4 long4,64位int4,long8
2.import和include
import可以避免重復(fù)包含
3.@class
避免循環(huán)引用頭文件
3.全局&靜態(tài)變量
1.全局變量和靜態(tài)變量的區(qū)別
1> 修飾符
全局變量在聲明源文件之外使用,需要extern引用一下;
靜態(tài)變量使用static來修飾
2> 存儲(chǔ)地址
兩者都是存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū),非堆棧上,它們與局部變量的存儲(chǔ)分開
3> 生命周期
兩者都是在程序編譯或加載時(shí)由系統(tǒng)自動(dòng)分配的,程序結(jié)束時(shí)消亡
4> 外部可訪問性
全局變量在整個(gè)程序的任何地方均可訪問,而靜態(tài)變量相當(dāng)于面向?qū)ο笾械乃接凶兞?他的可訪問性只限定于聲明它的那個(gè)源文件,即作用于僅局限于本文件中
二.類和對(duì)象
1.category
1> 分類 拓展 協(xié)議中哪些可以聲明屬性?
都可以,但分類和協(xié)議創(chuàng)建的屬性只相當(dāng)于方法,但是內(nèi)部沒有對(duì)成員變量的操作(無法創(chuàng)建成員變量),拓展可以(私有成員變量)
代理中聲明屬性,沒有實(shí)際創(chuàng)建成員變量,相當(dāng)于聲明了屬性名對(duì)應(yīng)的訪問方法,遵守協(xié)議的類需要實(shí)現(xiàn)對(duì)應(yīng)的訪問器方法,否則運(yùn)行報(bào)錯(cuò)
分類中聲明屬性,警告提示需要手動(dòng)實(shí)現(xiàn)訪問器方法(Swift中叫計(jì)算型屬性),而分類中不能創(chuàng)建成員變量,可以在手寫訪問器方法中使用runtime的 objc_setAssociatedObject方法關(guān)聯(lián)對(duì)象間接創(chuàng)建屬性(靜態(tài)庫添加屬性)
拓展里可以聲明屬性,直接可以使用
2> 繼承和類別的區(qū)別
1> 使用繼承:
1.1> 添加新方法和父類方法一致,但父類方法仍需要使用
1.2> 添加新屬性
2> 類別:
2.1> 針對(duì)系統(tǒng)提供的一些類,系統(tǒng)本身不提倡繼承,因?yàn)檫@些類的內(nèi)部實(shí)現(xiàn)對(duì)繼承有所限制(NSString initWithFormat繼承崩潰)
2.2> 類別可以將自己構(gòu)建的類中的方法進(jìn)行分組,對(duì)于大型的類,提高可維護(hù)性
3> 分類的作用
將類的實(shí)現(xiàn)分散到多個(gè)不同文件或多個(gè)不同框架中册踩。
創(chuàng)建對(duì)私有方法的前向引用。
向?qū)ο筇砑臃钦絽f(xié)議乍赫。
(非正式協(xié)議:即NSObject的分類,聲明方法可以不實(shí)現(xiàn),OC2.0以前protocal沒有@optional,主要使用分類添加可選協(xié)議方法
oc中聲明方法不實(shí)現(xiàn),不調(diào)用則只警告不報(bào)錯(cuò)
正式協(xié)議的優(yōu)點(diǎn):可繼承,泛型約束
如kvo的observeValueForKeyPath屬于nsobject的分類,且不需要調(diào)父類,說明可選實(shí)現(xiàn)該方法,沒警告可能是編譯器規(guī)則過濾)
4> 分類的局限性
無法向類中添加新的實(shí)例變量,類別沒有位置容納實(shí)例變量陆蟆。
名稱沖突雷厂,即當(dāng)類別中的方法與原始類方法名稱沖突時(shí),類別具有更高的優(yōu)先級(jí)叠殷。類別方法將完全取代初始方法從而無法再使用初始方法改鲫。
無法添加實(shí)例變量的局限可以使用字典對(duì)象解決。
2.extension
3.protocol
二: category&extension
類別主要有三個(gè)作用
(1)可以將類的實(shí)現(xiàn)分散到多個(gè)不同文件或多個(gè)不同框架中林束,方便代碼管理像棘。也可以對(duì)框架提供類的擴(kuò)展(沒有源碼,不能修改)壶冒。
(2)創(chuàng)建對(duì)私有方法的前向引用:如果其他類中的方法未實(shí)現(xiàn)缕题,在你訪問其他類的私有方法時(shí)編譯器報(bào)錯(cuò)這時(shí)使用類別,在類別中聲明這些方法(不必提供方法實(shí)現(xiàn))胖腾,編譯器就不會(huì)再產(chǎn)生警告
(3)向?qū)ο筇砑臃钦絽f(xié)議:創(chuàng)建一個(gè)NSObject的類別稱為“創(chuàng)建一個(gè)非正式協(xié)議”烟零,因?yàn)榭梢宰鳛槿魏晤惖奈袑?duì)象使用瘪松。
他們的主要區(qū)別是:
1、形式上來看锨阿,extension是匿名的category宵睦。
2、extension里聲明的方法需要在mainimplementation中實(shí)現(xiàn)墅诡,category不強(qiáng)制要求壳嚎。
3、extension可以添加屬性(變量)书斜,category不可以诬辈。
Category和Extension都是用來給已定義的類增加新的內(nèi)容的。
Category和原有類的耦合更低一些荐吉,聲明和實(shí)現(xiàn)都可以寫在單獨(dú)的文件里焙糟。但是只能為已定義類增加Method,而不能加入instance variable样屠。
Extension耦合比較高穿撮,聲明可以單獨(dú)寫,但是實(shí)現(xiàn)必須寫在原有類的@implementation中痪欲≡么可以增加Method和instance variable。
Extension給人感覺更像是在編寫類時(shí)為了封裝之類的特性而設(shè)計(jì)业踢,和類是同時(shí)編寫的栗柒。而category則是在用到某一個(gè)framework中的類時(shí)臨時(shí)增加的特性。
Extension的一個(gè)特性就是可以redeclare一個(gè)instance variable知举,將之從readonly改為對(duì)內(nèi)readwrite.
使用Extension可以更好的封裝類瞬沦,在h文件中能看到的都是對(duì)外的接口,其余的instance variable和對(duì)內(nèi)的@property等都可以寫在Extension雇锡,這樣類的結(jié)構(gòu)更加清晰逛钻。
三.Foundation
1.字符串
1> 字符串比較
NSString *a = @“hello”;
NSString *b = [NSString stringWithFormat:@hello”];
if (a == b){
nslog(@“a==b”); }
if ([a isEqualToString: b]){
nslog(@“a isEqualToString b”); }
== 比較變量中保存的數(shù)值(地址) 速度快 內(nèi)容同,可能地址不同(常量區(qū),堆區(qū))
isEqualTo 比較字符串 非常耗時(shí)
2> 字符串截取
截取字符串”20 | http://www.baidu.com”中,”|”字符前面和后面的數(shù)據(jù),分別輸出它們。
NSString * str = @"20 | http://www.baidu.com";
NSArray *array = [str componentsSeparatedByString:@"|"]; //這是分別輸出的截取后的字符串
for (int i = 0; i<[array count]; ++i) {
NSLog(@"%d=%@",i,[array objectAtIndex:i]);
}
3> 格式
NSString *str1 = [NSString stringWithFormat:@"a"b”]; //報(bào)錯(cuò)锰提,a”后加b非法
NSString *str2 = [NSString stringWithFormat:@“a""b”]; //顯示 ab
NSString *str3 = [NSString stringWithFormat:@“a"b”]; //顯示 a”b 反斜杠轉(zhuǎn)義
2.NSArray和NSDictionary
1> iOS遍歷數(shù)組/字典的方法
數(shù)組: for循環(huán) for in enumerateObjectsUsingBlock(正序) enumerateObjectsWithOptions:usingBlock:(多一個(gè)遍歷選項(xiàng),不保證順序)
字典:
- for(NSString *object in [testDic allValues])
- for(id akey in [testDic allKeys]){
[sum appendString:[testDic objectForKey:akey]]; } - [testDic enumerateKeysAndObjectsUsingBlock:^(idkey,idobj,BOOL*stop) {
[sum appendString:obj]; } ];
速度: 對(duì)于數(shù)組, 增強(qiáng)for最快,普通for和block速度差不多,增強(qiáng)最快是因?yàn)樵鰪?qiáng)for語法會(huì)對(duì)容器里的元素的內(nèi)存地址建立緩沖,遍歷的時(shí)候直接從緩沖中取元素地址而不是通過調(diào)用方法來獲取,所以效率高.這也是使用增強(qiáng)for時(shí)不能在循環(huán)體中修改容器元素的原因之一(可以在循環(huán)體中添加標(biāo)記,在循環(huán)體外修改元素)
對(duì)于字典,allValues最快,allKey和block差不多,原因是allKey需要做objcetForKey的方法
3.NSValue NSNumber
1> 歸檔視圖尺寸曙痘,坐標(biāo)
4.其他
nil Nil null NSNull 的區(qū)別
2> 如何避免循環(huán)引用
兩個(gè)對(duì)象相互強(qiáng)引用,都無法release立肘,解決辦法為一個(gè)使用strong边坤,一個(gè)使用assign(weak)
- CFSocket使用有哪幾個(gè)步驟。
答:創(chuàng)建 Socket 的上下文谅年;創(chuàng)建 Socket 惩嘉;配置要訪問的服務(wù)器信息;封裝服務(wù)器信息踢故;連接服務(wù)器文黎; - Core Foundation中提供了哪幾種操作Socket的方法惹苗?
答: CFNetwork 、 CFSocket 和 BSD Socket 耸峭。 - 解析XML文件有哪幾種方式桩蓉?
答:以 DOM 方式解析 XML 文件;以 SAX 方式解析 XML 文件劳闹; - 什么是沙盒模型院究?哪些操作是屬于私有api范疇?
答:某個(gè)iphone工程進(jìn)行文件操作有此工程對(duì)應(yīng)的指定的位置,不能逾越本涕。
iphone沙箱模型的有四個(gè)文件夾documents业汰,tmp,app菩颖,Library样漆,永久數(shù)據(jù)存儲(chǔ)一般放documents文件夾,得到模擬器的路徑的可使用NSHomeDirectory()方法晦闰。Nsuserdefaults保存的文件在tmp文件夾里放祟。 - 在一個(gè)對(duì)象的方法里面:self.name= “object”;和 name =”object” 有什么不同嗎?
答:self.name =”object”:會(huì)調(diào)用對(duì)象的setName()方法呻右;
name = “object”:會(huì)直接把object賦值給當(dāng)前對(duì)象的name屬性跪妥。 - 請(qǐng)簡(jiǎn)要說明viewDidLoad和viewDidUnload何時(shí)調(diào)用
答:viewDidLoad在view從nib文件初始化時(shí)調(diào)用,loadView在controller的view為nil時(shí)調(diào)用声滥。此方法在編程實(shí)現(xiàn)view時(shí)調(diào)用眉撵,view控制器默認(rèn)會(huì)注冊(cè)memory warning notification,當(dāng)view controller的任何view沒有用的時(shí)候落塑,viewDidUnload會(huì)被調(diào)用纽疟,在這里實(shí)現(xiàn)將retain的view release,如果是retain的IBOutlet view 屬性則不要在這里release芜赌,IBOutlet會(huì)負(fù)責(zé)release 仰挣。
4> 創(chuàng)建控制器伴逸、視圖的方式
4.1> 創(chuàng)建控制器的方式
1)通過代碼的方式加載viewController
UIViewController *controller = [[UIViewController alloc] init];
2)通過stroyboard來加載viewController
2.1) 加載storyboard中箭頭指向的viewController
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; //加載箭頭指向的viewController
CZViewController *controller = [storyboard instantiateInitialViewController];
2.2) 加載storyboard中特定標(biāo)示的viewController(storyboard可以有多個(gè)controller)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
CZViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"two"];
3)通過xib加載viewController
3.1) 傳統(tǒng)方法
3.1.1)創(chuàng)建Xib,并指定xib的files owner為自定義控制器類(為了能連線關(guān)聯(lián)管理IB的內(nèi)容)
3.1.2)xib中要有內(nèi)容缠沈,且xib中描述的控制器類的view屬性要與xib的view控件完成關(guān)聯(lián)(關(guān)聯(lián)方法兩種,一種是control+files owner拖線到xib中搭建的指定view控件,另一種是指定xib中的view拖線到@interface)
3.1.3)從xib加載viewController
CZViewController *controller = [[CZViewController alloc] initWithNibName:@"CZOneView" bundle:nil];
3.2)bundle中取出xib內(nèi)容
CZViewController *vc = [[NSBundle mainBundle] loadNibNamed:@"Two" owner:nil options:nil].lastObject;
4.2> 創(chuàng)建視圖的方式
1.用系統(tǒng)的loadView方法創(chuàng)建控制器的視圖
2.如果指定加載某個(gè)storyboard文件做控制器的視圖,就會(huì)加載storyboard里面的描述去創(chuàng)建view
3.如果指定讀取某個(gè)xib文件做控制器的視圖错蝴,就根據(jù)指定的xib文件去加載創(chuàng)建
4.如果有xib文件名和控制器的類名前綴(也就是去掉controller)的名字一樣的 xib文件 就會(huì)用這個(gè)xib文件來創(chuàng)建控件器的視圖 例:控件器的名為 MJViewController xib文件名為 MJView.xib 如果xib文件名后有一個(gè)字不一樣就不會(huì)去根據(jù)它去創(chuàng)建如:MJView8.xib
5.找和控制器同名的xib文件去創(chuàng)建
6.如果以上都沒有就創(chuàng)建一個(gè)空的控制器的視圖;
5> UIWindow
是一種特殊的UIView,通常在一個(gè)程序中只會(huì)有一個(gè)UIWindow,但可以手 動(dòng)創(chuàng)建多個(gè)UIWindow,同時(shí)加到程序里面洲愤。UIWindow在程序中主要起到三個(gè)作用:
1、作為容器,包含app所要顯示的所有視圖
2漆腌、傳遞觸摸消息到程序中view和其他對(duì)象
3堂污、與UIViewController協(xié)同工作,方便完成設(shè)備方向旋轉(zhuǎn)的支持
- 簡(jiǎn)述內(nèi)存分區(qū)情況
答:
1).代碼區(qū):存放函數(shù)二進(jìn)制代碼
2).數(shù)據(jù)區(qū):系統(tǒng)運(yùn)行時(shí)申請(qǐng)內(nèi)存并初始化凰慈,系統(tǒng)退出時(shí)由系統(tǒng)釋放。存放全局變量肛宋、靜態(tài)變量州藕、常量
3).堆區(qū):通過malloc等函數(shù)或new等操作符動(dòng)態(tài)申請(qǐng)得到,需程序員手動(dòng)申請(qǐng)和釋放
4).棧區(qū):函數(shù)模塊內(nèi)申請(qǐng)酝陈,函數(shù)結(jié)束時(shí)由系統(tǒng)自動(dòng)釋放床玻。存放局部變量、函數(shù)參數(shù) - 隊(duì)列和棧有什么區(qū)別
答:隊(duì)列和棧是兩種不同的數(shù)據(jù)容器沉帮。從”數(shù)據(jù)結(jié)構(gòu)”的角度看锈死,它們都是線性結(jié)構(gòu),即數(shù)據(jù)元素之間的關(guān)系相同穆壕。
隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)待牵,它在兩端進(jìn)行操作,一端進(jìn)行入隊(duì)列操作喇勋,一端進(jìn)行出列隊(duì)操作缨该。
棧是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),它只能在棧頂進(jìn)行操作茄蚯,入棧和出棧都在棧頂操作压彭。 - iOS的系統(tǒng)架構(gòu)
答: iOS的系統(tǒng)架構(gòu)分為( 核心操作系統(tǒng)層 theCore OS layer )、( 核心服務(wù)層theCore Services layer )渗常、( 媒體層 theMedia layer )和( Cocoa 界面服務(wù)層 the Cocoa Touch layer )四個(gè)層次壮不。 - 控件主要響應(yīng)3種事件
答:1). 基于觸摸的事件 ; 2). 基于值的事件 ; 3).基于編輯的事件。 - xib文件的構(gòu)成分為哪3個(gè)圖標(biāo)皱碘?都具有什么功能询一。
答: File’s Owner 是所有 nib 文件中的每個(gè)圖標(biāo),它表示從磁盤加載 nib 文件的對(duì)象癌椿;
First Responder 就是用戶當(dāng)前正在與之交互的對(duì)象健蕊;
View 顯示用戶界面;完成用戶交互踢俄;是 UIView 類或其子類缩功。 - 簡(jiǎn)述視圖控件器的生命周期。
答: loadView 盡管不直接調(diào)用該方法都办,如多手動(dòng)創(chuàng)建自己的視圖嫡锌,那么應(yīng)該覆蓋這個(gè)方法并將它們賦值給試圖控制器的 view 屬性。
viewDidLoad 只有在視圖控制器將其視圖載入到內(nèi)存之后才調(diào)用該方法琳钉,這是執(zhí)行任何其他初始化操作的入口势木。
viewDidUnload 當(dāng)試圖控制器從內(nèi)存釋放自己的方法的時(shí)候調(diào)用,用于清楚那些可能已經(jīng)在試圖控制器中創(chuàng)建的對(duì)象歌懒。
viewVillAppear 當(dāng)試圖將要添加到窗口中并且還不可見的時(shí)候或者上層視圖移出圖層后本視圖變成頂級(jí)視圖時(shí)調(diào)用該方法啦桌,用于執(zhí)行諸如改變視圖方向等的操作。實(shí)現(xiàn)該方法時(shí)確保調(diào)用 [super viewWillAppear:
viewDidAppear 當(dāng)視圖添加到窗口中以后或者上層視圖移出圖層后本視圖變成頂級(jí)視圖時(shí)調(diào)用及皂,用于放置那些需要在視圖顯示后執(zhí)行的代碼甫男。確保調(diào)用 [super viewDidAppear:] 且改。
viewWillDisappear-UIViewController對(duì)象的視圖即將消失、被覆蓋或是隱藏時(shí)調(diào)用板驳;
viewDidDisappear-UIViewController對(duì)象的視圖已經(jīng)消失钾虐、被覆蓋或是隱藏時(shí)調(diào)用;
viewVillUnload-當(dāng)內(nèi)存過低時(shí)笋庄,需要釋放一些不需要使用的視圖時(shí)效扫,即將釋放時(shí)調(diào)用;
viewDidUnload-當(dāng)內(nèi)存過低直砂,釋放一些不需要的視圖時(shí)調(diào)用菌仁。
app 項(xiàng)目的生命周期?
1> 應(yīng)用的生命周期
各個(gè)程序運(yùn)行狀態(tài)時(shí)代理的回調(diào):
-(BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary )launchOptions 告訴代理進(jìn)程啟動(dòng)但還沒進(jìn)入狀態(tài)保存
-(BOOL)application:(UIApplication)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 告訴代理啟動(dòng)基本完成程序準(zhǔn)備開始運(yùn)行
- (void)applicationWillResignActive:(UIApplication *)application 當(dāng)應(yīng)用程序?qū)⒁敕腔顒?dòng)狀態(tài)執(zhí)行静暂,在此期間济丘,應(yīng)用程序不接收消息或事件,比如來電話了
- (void)applicationDidBecomeActive:(UIApplication *)application 當(dāng)應(yīng)用程序入活動(dòng)狀態(tài)執(zhí)行洽蛀,這個(gè)剛好跟上面那個(gè)方法相反
- (void)applicationDidEnterBackground:(UIApplication *)application 當(dāng)程序被推送到后臺(tái)的時(shí)候調(diào)用摹迷。所以要設(shè)置后臺(tái)繼續(xù)運(yùn)行,則在這個(gè)函數(shù)里面設(shè)置即可
- (void)applicationWillEnterForeground:(UIApplication *)application 當(dāng)程序從后臺(tái)將要重新回到前臺(tái)時(shí)候調(diào)用郊供,這個(gè)剛好跟上面的那個(gè)方法相反峡碉。
- (void)applicationWillTerminate:(UIApplication *)application 當(dāng)程序?qū)⒁顺鍪潜徽{(diào)用,通常是用來保存數(shù)據(jù)和一些退出前的清理工作驮审。
3.簡(jiǎn)要說明一下APP的啟動(dòng)過程鲫寄,main文件說起,main函數(shù)中有什么函數(shù)疯淫?作用是什么地来?
http://www.reibang.com/p/3f262ae413b4
打開程序——->執(zhí)行main函數(shù)———>UIAPPlicationMain函數(shù)——->初始化UIAPPlicationMain函數(shù)(設(shè)置代理,開啟事件循環(huán))———>監(jiān)聽系統(tǒng)事件—->程序結(jié)束
先執(zhí)行main函數(shù)熙掺,main內(nèi)部會(huì)調(diào)用UIApplicationMain函數(shù)
UIApplicationMain函數(shù)作用:
(1)未斑、根據(jù)傳入的第三個(gè)參數(shù)創(chuàng)建UIApplication對(duì)象或它的子類對(duì)象。如果該參數(shù)為nil,直接使用該UIApplication來創(chuàng)建币绩。(該參數(shù)只能傳人UIApplication或者是它的子類)
(2)蜡秽、根據(jù)傳入的第四個(gè)參數(shù)創(chuàng)建AppDelegate對(duì)象,并將該對(duì)象賦值給第1步創(chuàng)建的UIApplication對(duì)象的delegate屬性。
(3)类浪、開啟一個(gè)事件循環(huán),循環(huán)監(jiān)控應(yīng)用程序發(fā)生的事件载城。每監(jiān)聽到對(duì)應(yīng)的系統(tǒng)事件時(shí)肌似,就會(huì)通知AppDelegate费就。
main函數(shù)作用:
(1)創(chuàng)建UIApplication對(duì)象
(2)創(chuàng)建應(yīng)用程序代理
(3)開啟時(shí)間循環(huán),包括應(yīng)用程序的循環(huán)運(yùn)行川队,并開始處理用戶事件力细。
動(dòng)畫有基本類型有哪幾種睬澡;表視圖有哪幾種基本樣式。
答:動(dòng)畫有兩種基本類型:隱式動(dòng)畫和顯式動(dòng)畫眠蚂。實(shí)現(xiàn)簡(jiǎn)單的表格顯示需要設(shè)置UITableView的什么屬性煞聪、實(shí)現(xiàn)什么協(xié)議?
答:實(shí)現(xiàn)簡(jiǎn)單的表格顯示需要設(shè)置 UITableView 的 dataSource 和 delegate 屬性逝慧,實(shí)現(xiàn)UITableViewDataSource 和 UITableViewDelegate 協(xié)議昔脯。Cocoa Touch提供了哪幾種Core Animation過渡類型?
答: Cocoa Touch 提供了 4 種 Core Animation 過渡類型笛臣,分別為:交叉淡化云稚、推擠、顯示和覆蓋。UIView與CLayer有什么區(qū)別?
答:
1).UIView 是 iOS 系統(tǒng)中界面元素的基礎(chǔ)舆床,所有的界面元素都是繼承自它皿淋。它本身完全是由 CoreAnimation 來實(shí)現(xiàn)的。它真正的繪圖部分寂祥,是由一個(gè) CALayer 類來管理。 UIView 本身更像是一個(gè) CALayer 的管理器,訪問它的跟繪圖和跟坐標(biāo)有關(guān)的屬性刑赶。
2).UIView 有個(gè)重要屬性 layer ,可以返回它的主 CALayer 實(shí)例懂衩。
3).UIView 的 CALayer 類似 UIView 的子 View 樹形結(jié)構(gòu)角撞,也可以向它的 layer 上添加子layer ,來完成某些特殊的表示勃痴。即 CALayer 層是可以嵌套的谒所。
4).UIView 的 layer 樹形在系統(tǒng)內(nèi)部,被維護(hù)著三份 copy 沛申。分別是邏輯樹劣领,這里是代碼可以操縱的;動(dòng)畫樹铁材,是一個(gè)中間層尖淘,系統(tǒng)就在這一層上更改屬性,進(jìn)行各種渲染操作著觉;顯示樹村生,其內(nèi)容就是當(dāng)前正被顯示在屏幕上得內(nèi)容。
5).動(dòng)畫的運(yùn)作:對(duì) UIView 的 subLayer (非主 Layer )屬性進(jìn)行更改饼丘,系統(tǒng)將自動(dòng)進(jìn)行動(dòng)畫生成趁桃,動(dòng)畫持續(xù)時(shí)間的缺省值似乎是 0.5 秒。
6).坐標(biāo)系統(tǒng): CALayer 的坐標(biāo)系統(tǒng)比 UIView 多了一個(gè) anchorPoint 屬性,使用CGPoint 結(jié)構(gòu)表示卫病,值域是 0~1 油啤,是個(gè)比例值。這個(gè)點(diǎn)是各種圖形變換的坐標(biāo)原點(diǎn)蟀苛,同時(shí)會(huì)更改 layer 的 position 的位置益咬,它的缺省值是 {0.5,0.5} ,即在 layer 的中央帜平。
7).渲染:當(dāng)更新層幽告,改變不能立即顯示在屏幕上。當(dāng)所有的層都準(zhǔn)備好時(shí)裆甩,可以調(diào)用setNeedsDisplay 方法來重繪顯示评腺。
8).變換:要在一個(gè)層中添加一個(gè) 3D 或仿射變換,可以分別設(shè)置層的 transform 或affineTransform 屬性淑掌。
9).變形: Quartz Core 的渲染能力蒿讥,使二維圖像可以被自由操縱,就好像是三維的抛腕。圖像可以在一個(gè)三維坐標(biāo)系中以任意角度被旋轉(zhuǎn)芋绸,縮放和傾斜。 CATransform3D 的一套方法提供了一些魔術(shù)般的變換效果担敌。Quatrz 2D的繪圖功能的三個(gè)核心概念是什么并簡(jiǎn)述其作用摔敛。
答:上下文:主要用于描述圖形寫入哪里;
路徑:是在圖層上繪制的內(nèi)容全封;
狀態(tài):用于保存配置變換的值马昙、填充和輪廓, alpha 值等刹悴。iPhone OS主要提供了幾種播放音頻的方法行楞?
答: SystemSound Services
AVAudioPlayer 類
Audio Queue Services
OpenAL使用AVAudioPlayer類調(diào)用哪個(gè)框架、使用步驟土匀?
答: AVFoundation.framework
步驟:配置 AVAudioPlayer 對(duì)象子房;
實(shí)現(xiàn) AVAudioPlayer 類的委托方法;
控制 AVAudioPlayer 類的對(duì)象就轧;
監(jiān)控音量水平证杭;
回放進(jìn)度和拖拽播放。有哪幾種手勢(shì)通知方法妒御、寫清楚方法名解愤?
答:
-(void)touchesBegan:(NSSet)touchedwithEvent:(UIEvent)event;
-(void)touchesMoved:(NSSet)touched withEvent:(UIEvent)event;
-(void)touchesEnded:(NSSet)touchedwithEvent:(UIEvent)event;
-(void)touchesCanceled:(NSSet)touchedwithEvent:(UIEvent)event;
-(void)touchesBegan:(NSSet)touchedwithEvent:(UIEvent)event;
-(void)touchesMoved:(NSSet)touched withEvent:(UIEvent)event;
-(void)touchesEnded:(NSSet)touchedwithEvent:(UIEvent)event;
-(void)touchesCanceled:(NSSet)touchedwithEvent:(UIEvent)event;ViewController的didReceiveMemoryWarning怎么被調(diào)用
答:[super didReceiveMemoryWarning];
69.什么時(shí)候用delegate,什么時(shí)候用Notification?
答: delegate針對(duì)one-to-one關(guān)系,用于sender接受到reciever的某個(gè)功能反饋值乎莉。
notification針對(duì)one-to-one/many/none,reciver,用于通知多個(gè)object某個(gè)事件送讲。
70.用預(yù)處理指令#define聲明一個(gè)常數(shù)奸笤,用以表明1年中有多少秒(忽略閏年問題)
答:
define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
我在這想看到幾件事情:
define 語法的基本知識(shí)(例如:不能以分號(hào)結(jié)束,括號(hào)的使用李茫,等等)
懂得預(yù)處理器將為你計(jì)算常數(shù)表達(dá)式的值,因此肥橙,直接寫出你是如何計(jì)算一年中有多少秒而不是計(jì)算出實(shí)際的值魄宏,是更清晰而沒有代價(jià)的。
意識(shí)到這個(gè)表達(dá)式將使一個(gè)16位機(jī)的整型數(shù)溢出-因此要用到長(zhǎng)整型符號(hào)L,告訴編譯器這個(gè)常數(shù)是的長(zhǎng)整型數(shù)存筏。
如果你在你的表達(dá)式中用到UL(表示無符號(hào)長(zhǎng)整型)宠互,那么你有了一個(gè)好的起點(diǎn)。記住椭坚,第一印象很重要予跌。
71.寫一個(gè)”標(biāo)準(zhǔn)"宏MIN ,這個(gè)宏輸入兩個(gè)參數(shù)并返回較小的一個(gè)善茎。
答:
define MIN(A,B) ((A) <= (B) ? (A) : (B))
define MIN(A,B) ((A) <= (B) ? (A) : (B))
這個(gè)測(cè)試是為下面的目的而設(shè)的:
標(biāo)識(shí)#define在宏中應(yīng)用的基本知識(shí)券册。這是很重要的,因?yàn)橹钡角度?inline)操作符變?yōu)闃?biāo)準(zhǔn)C的一部分垂涯,宏是方便產(chǎn)生嵌入代碼的唯一方
法烁焙,
對(duì)于嵌入式系統(tǒng)來說,為了能達(dá)到要求的性能耕赘,嵌入代碼經(jīng)常是必須的方法骄蝇。
三重條件操作符的知識(shí)。這個(gè)操作符存在C語言中的原因是它使得編譯器能產(chǎn)生比 if-then-else 更優(yōu)化的代碼操骡,了解這個(gè)用法是很重要的九火。
懂得在宏中小心地把參數(shù)用括號(hào)括起來
我也用這個(gè)問題開始討論宏的副作用,例如:當(dāng)你寫下面的代碼時(shí)會(huì)發(fā)生什么事册招?
least = MIN(p++, b);
least = MIN(p++, b);
結(jié)果是:
((p++) <= (b) ? (p++) : (p++))
((p++) <= (b) ? (p++) : (p++))
這個(gè)表達(dá)式會(huì)產(chǎn)生副作用岔激,指針p會(huì)作三次++自增操作。
72.關(guān)鍵字const有什么含意是掰?修飾類呢?static的作用,用于類呢?還有extern c的作用
答:
const 意味著"只讀"鹦倚,下面的聲明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前兩個(gè)的作用是一樣冀惭,a是一個(gè)常整型數(shù)冰抢。
第三個(gè)意味著a是一個(gè)指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的浦徊,但指針可以)园匹。
第四個(gè)意思a是一個(gè)指向整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是可以修改的戚丸,但指針是不可修改的)划址。
最后一個(gè)意味著a是一個(gè)指向常整型數(shù)的常指針(也就是說扔嵌,指針指向的整型數(shù)是不可修改的,同時(shí)指針也是不可修改的)夺颤。
結(jié)論:
關(guān)鍵字const的作用是為給讀你代碼的人傳達(dá)非常有用的信息痢缎,實(shí)際上,聲明一個(gè)參數(shù)為常量是為了告訴了用戶這個(gè)參數(shù)的應(yīng)用目的世澜。
如果你曾花很多時(shí)間清理其它人留下的垃圾独旷,你就會(huì)很快學(xué)會(huì)感謝這點(diǎn)多余的信息。(當(dāng)然寥裂,懂得用const的程序員很少會(huì)留下的垃圾讓別人來清理的) 通過給優(yōu)化器一些附加的信息嵌洼,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。合理地使用關(guān)鍵字const可以使編譯器很自然地保護(hù)那些不希望被改變的參數(shù)封恰,防止其被無意的代碼修改麻养。簡(jiǎn)而言之,這樣可以減少bug的出現(xiàn)诺舔。
1).欲阻止一個(gè)變量被改變鳖昌,可以使用 const 關(guān)鍵字。在定義該 const 變量時(shí)低飒,通常需要對(duì)它進(jìn)行初
始化遗遵,因?yàn)橐院缶蜎]有機(jī)會(huì)再去改變它了;
2).對(duì)指針來說逸嘀,可以指定指針本身為 const车要,也可以指定指針?biāo)傅臄?shù)據(jù)為 const,或二者同時(shí)指
定為 const崭倘;
3).在一個(gè)函數(shù)聲明中翼岁,const 可以修飾形參,表明它是一個(gè)輸入?yún)?shù)司光,在函數(shù)內(nèi)部不能改變其值琅坡;
4).對(duì)于類的成員函數(shù),若指定其為 const 類型残家,則表明其是一個(gè)常函數(shù)榆俺,不能修改類的成員變量;
5).對(duì)于類的成員函數(shù)坞淮,有時(shí)候必須指定其返回值為 const 類型茴晋,以使得其返回值不為“左值”。
關(guān)鍵字volatile有什么含意?并給出三個(gè)不同的例子回窘。
答:一個(gè)定義為 volatile的變量是說這變量可能會(huì)被意想不到地改變诺擅,這樣,編譯器就不會(huì)去假設(shè)這個(gè)變量的值了啡直。精確地說就是烁涌,優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值苍碟,而不是使用保存在寄存器里的備份。
下面是volatile變量的幾個(gè)例子:
并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
一個(gè)中斷服務(wù)子程序中會(huì)訪問到的非自動(dòng)變量(Non-automatic variables)
多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量一個(gè)參數(shù)既可以是const還可以是volatile嗎撮执? 一個(gè)指針可以是volatile 嗎微峰?解釋為什么。
答:1).是的抒钱。一個(gè)例子是只讀的狀態(tài)寄存器蜓肆。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖儭K莄onst因?yàn)槌绦虿粦?yīng)該試圖去修改它继效。
2).是的症杏。盡管這并不很常見装获。一個(gè)例子是當(dāng)一個(gè)中服務(wù)子程序修該一個(gè)指向一個(gè)buffer的指針時(shí)瑞信。
75 . static 關(guān)鍵字的作用
答:
1).函數(shù)體內(nèi) static 變量的作用范圍為該函數(shù)體,不同于 auto 變量穴豫,該變量的內(nèi)存只被分配一次凡简,
因此其值在下次調(diào)用時(shí)仍維持上次的值;
2).在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所用函數(shù)訪問精肃,但不能被模塊外其它函數(shù)訪問秤涩;
3).在模塊內(nèi)的 static 函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個(gè)函數(shù)的使用范圍被限制在聲明
它的模塊內(nèi)司抱;
4).在類中的 static 成員變量屬于整個(gè)類所擁有筐眷,對(duì)類的所有對(duì)象只有一份拷貝;
5).在類中的 static 成員函數(shù)屬于整個(gè)類所擁有习柠,這個(gè)函數(shù)不接收 this 指針匀谣,因而只能訪問類的static 成員變量。列舉幾種進(jìn)程的同步機(jī)制资溃,并比較其優(yōu)缺點(diǎn)武翎。
答: 原子操作 信號(hào)量機(jī)制 自旋鎖 管程,會(huì)合溶锭,分布式系統(tǒng)進(jìn)程之間通信的途徑
答:共享存儲(chǔ)系統(tǒng)消息傳遞系統(tǒng)管道:以文件系統(tǒng)為基礎(chǔ)進(jìn)程死鎖的原因
答:資源競(jìng)爭(zhēng)及進(jìn)程推進(jìn)順序非法死鎖的4個(gè)必要條件
答:互斥宝恶、請(qǐng)求保持、不可剝奪趴捅、環(huán)路死鎖的處理
答:鴕鳥策略垫毙、預(yù)防策略、避免策略拱绑、檢測(cè)與解除死鎖cocoa touch框架
答:iPhone OS 應(yīng)用程序的基礎(chǔ) Cocoa Touch 框架重用了許多 Mac 系統(tǒng)的成熟模式露久,但是它更多地專注于觸摸的接口和優(yōu)化。
UIKit 為您提供了在 iPhone OS 上實(shí)現(xiàn)圖形欺栗,事件驅(qū)動(dòng)程序的基本工具毫痕,其建立在和 Mac OS X 中一樣的 Foundation 框架上征峦,包括文件處理,網(wǎng)絡(luò)消请,字符串操作等栏笆。
Cocoa Touch 具有和 iPhone 用戶接口一致的特殊設(shè)計(jì)。有了 UIKit臊泰,您可以使用 iPhone OS 上的獨(dú)特的圖形接口控件蛉加,按鈕,以及全屏視圖的功能缸逃,您還可以使用加速儀和多點(diǎn)觸摸手勢(shì)來控制您的應(yīng)用针饥。
各色俱全的框架 除了UIKit 外,Cocoa Touch 包含了創(chuàng)建世界一流 iPhone 應(yīng)用程序需要的所有框架需频,從三維圖形丁眼,到專業(yè)音效,甚至提供設(shè)備訪問 API 以控制攝像頭昭殉,或通過 GPS 獲知當(dāng)前位置苞七。
Cocoa Touch 既包含只需要幾行代碼就可以完成全部任務(wù)的強(qiáng)大的 Objective-C 框架婴削,也在需要時(shí)提供基礎(chǔ)的 C 語言 API 來直接訪問系統(tǒng)较坛。這些框架包括:
Core Animation:通過 Core Animation,您就可以通過一個(gè)基于組合獨(dú)立圖層的簡(jiǎn)單的編程模型來創(chuàng)建豐富的用戶體驗(yàn)沟沙。
Core Audio:Core Audio 是播放乾蓬,處理和錄制音頻的專業(yè)技術(shù)惠啄,能夠輕松為您的應(yīng)用程序添加強(qiáng)大的音頻功能。
Core Data:提供了一個(gè)面向?qū)ο蟮臄?shù)據(jù)管理解決方案任内,它易于使用和理解撵渡,甚至可處理任何應(yīng)用或大或小的數(shù)據(jù)模型。
功能列表:框架分類
下面是 Cocoa Touch 中一小部分可用的框架:
音頻和視頻:Core Audio 族奢,OpenAL 姥闭,Media Library ,AV Foundation
數(shù)據(jù)管理 :Core Data 越走,SQLite
圖形和動(dòng)畫 :Core Animation 棚品,OpenGL ES ,Quartz 2D
網(wǎng)絡(luò):Bonjour 廊敌,WebKit 铜跑,BSD Sockets
用戶應(yīng)用:Address Book ,Core Location 骡澈,Map Kit 锅纺,Store Kit自動(dòng)釋放池是什么,如何工作
答:當(dāng)您向一個(gè)對(duì)象發(fā)送一個(gè)autorelease消息時(shí),Cocoa就會(huì)將該對(duì)象的一個(gè)引用放入到最新的自動(dòng)釋放.它仍然是個(gè)正當(dāng)?shù)膶?duì)象肋殴,因此自動(dòng)釋放池定義的作用域內(nèi)的其它對(duì)象可以向它發(fā)送消息囤锉。當(dāng)程序執(zhí)行到作用域結(jié)束的位置時(shí)坦弟,自動(dòng)釋放池就會(huì)被釋放,池中的所有對(duì)象也就被釋放官地。sprintf,strcpy,memcpy使用上有什么要注意的地方酿傍。
答:
1). sprintf是格式化函數(shù)。將一段數(shù)據(jù)通過特定的格式驱入,格式化到一個(gè)字符串緩沖區(qū)中去赤炒。sprintf格式化的函數(shù)的長(zhǎng)度不可控,有可能格式化后的字符串會(huì)超出緩沖區(qū)的大小亏较,造成溢出莺褒。
2).strcpy是一個(gè)字符串拷貝的函數(shù),它的函數(shù)原型為strcpy(char *dst, const char *src
將src開始的一段字符串拷貝到dst開始的內(nèi)存中去雪情,結(jié)束的標(biāo)志符號(hào)為 ‘\0'遵岩,由于拷貝的長(zhǎng)度不是由我們自己控制的,所以這個(gè)字符串拷貝很容易出錯(cuò)旺罢。
3). memcpy是具備字符串拷貝功能的函數(shù)旷余,這是一個(gè)內(nèi)存拷貝函數(shù)绢记,它的函數(shù)原型為memcpy(char dst, const char src, unsigned int len);將長(zhǎng)度為len的一段內(nèi)存扁达,從src拷貝到dst中去,這個(gè)函數(shù)的長(zhǎng)度可控蠢熄。但是會(huì)有內(nèi)存疊加的問題跪解。你了解svn,cvs等版本控制工具么?
答: 版本控制 svn,cvs 是兩種版控制的器,需要配套相關(guān)的svn签孔,cvs服務(wù)器叉讥。
scm是xcode里配置版本控制的地方。版本控制的原理就是a和b同時(shí)開發(fā)一個(gè)項(xiàng)目饥追,a寫完當(dāng)天的代碼之后把代碼提交給服務(wù)器图仓,b要做的時(shí)候先從服務(wù)器得到最新版本,就可以接著做但绕。 如果a和b都要提交給服務(wù)器救崔,并且同時(shí)修改了同一個(gè)方法,就會(huì)產(chǎn)生代碼沖突捏顺,如果a先提交六孵,那么b提交時(shí),服務(wù)器可以提示沖突的代碼幅骄,b可以清晰的看到劫窒,并做出相應(yīng)的修改或融合后再提交到服務(wù)器。什么是push拆座。
答: 客戶端程序留下后門端口主巍,客戶端總是監(jiān)聽針對(duì)這個(gè)后門的請(qǐng)求冠息,于是 服務(wù)器可以主動(dòng)像這個(gè)端口推送消息。靜態(tài)鏈接庫
答:此為.a文件孕索,相當(dāng)于java里的jar包铐达,把一些類編譯到一個(gè)包中,在不同的工程中如果導(dǎo)入此文件就可以使用里面的類檬果,具體使用依然是#import “ xx.h”瓮孙。
OC三大特性
1.封裝_點(diǎn)語法
1> 本質(zhì)
//以下代碼有什么問題
- (void)setName:(NSString *)name {
self.name = name;
} - (NSString *)name {
return self.name;
}
點(diǎn)語法的本質(zhì)是調(diào)用類的getter方法和setter方法,如果類中沒有g(shù)etter方法和setter方法就不能使用點(diǎn)語法选脊。
2.繼承
1> 如何實(shí)現(xiàn)多重繼承
消息轉(zhuǎn)發(fā)
forwardingTargetForSelector methodSignatureForSelector forwardInvocation
delegate和protocol
類別
http://www.cocoachina.com/ios/20130528/6295.html
3.多態(tài)
1> 什么是多態(tài)
多態(tài):不同對(duì)象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)杭抠。
由于每個(gè)類都屬于該類的名字空間,這使得多態(tài)稱為可能恳啥。類定義中的名字和類定義外的名字并不會(huì)沖突偏灿。類的實(shí)例變量和類方法有如下特點(diǎn):
? 和C語言中結(jié)構(gòu)體中的數(shù)據(jù)成員一樣,類的實(shí)例變量也位于該類獨(dú)有的名字空間钝的。
? 類方法也同樣位于該類獨(dú)有的名字空間翁垂。與C語言中的方法名不同,類的方法名并不是一個(gè)全局符號(hào)硝桩。一個(gè)類中的方法名不會(huì)和其他類中同樣的方法名沖突沿猜。兩個(gè)完全不同的類可以實(shí)現(xiàn)同一個(gè)方法。
方法名是對(duì)象接口的一部分碗脊。對(duì)象收到的消息的名字就是調(diào)用的方法的名字啼肩。因?yàn)椴煌膶?duì)象可以有同名的方法,所以對(duì)象必須能理解消息的含義衙伶。同樣的消息發(fā)給不同的對(duì)象祈坠,導(dǎo)致的操作并不相同。
多態(tài)的主要好處就是簡(jiǎn)化了編程接口矢劲。它容許在類和類之間重用一些習(xí)慣性的命名赦拘,而不用為每一個(gè)新加的函數(shù)命名一個(gè)新名字。這樣芬沉,編程接口就是一些抽象的行為的集合躺同,從而和實(shí)現(xiàn)接口的類區(qū)分開來。
Objective-C支持方法名的多態(tài)花嘶,但不支持參數(shù)和操作符的多態(tài)笋籽。
2> OC中如何實(shí)現(xiàn)多態(tài)
在Objective-C中是通過一個(gè)叫做selector的選取器實(shí)現(xiàn)的。在Objective-C中椭员,selector有兩個(gè)意思车海, 當(dāng)用在給對(duì)象的源碼消息時(shí),用來指方法的名字。它也指那個(gè)在源碼編譯后代替方法名的唯一的標(biāo)識(shí)符侍芝。 編譯后的選擇器的類型是SEL有同樣名字的方法研铆、也有同樣的選擇器。你可以使用選擇器來調(diào)用一個(gè)對(duì)象的方法州叠。
選取器有以下特點(diǎn):
* 所有同名的方法擁有同樣的選取器
* 所有的選取器都是不一樣的
(1) SEL和@selector
選擇器的類型是 SEL棵红。@selector指示符用來引用選擇器,返回類型是SEL咧栗。
例如:
SEL responseSEL; responseSEL = @selector(loadDataForTableView:);
可以通過字符串來得到選取器逆甜,例如:
responseSEL = NSSelectorFromString(@"loadDataForTableView:");
也可以通過反向轉(zhuǎn)換,得到方法名致板,例如:
NSString *methodName = NSStringFromSelector(responseSEL);
(2) 方法和選取器
選取器確定的是方法名交煞,而不是方法實(shí)現(xiàn)。這是多態(tài)性和動(dòng)態(tài)綁定的基礎(chǔ)斟或,它使得向不同類對(duì)象發(fā)送相同的消息成為現(xiàn)實(shí)素征;否則,發(fā)送 消息和標(biāo)準(zhǔn)C中調(diào)用方法就沒有區(qū)別萝挤,也就不可能支持多態(tài)性和動(dòng)態(tài)綁定里烦。
另外铃岔,同一個(gè)類的同名類方法和實(shí)例方法擁有相同的選取器脚猾。
(3) 方法返回值和參數(shù)類型
消息機(jī)制通過選取器找到方法的返回值類型和參數(shù)類型海洼,因此刽漂,動(dòng)態(tài)綁定(例:向id定義的對(duì)象發(fā)送消息)需要同名方法的實(shí)現(xiàn)擁有相 同返回值類型和相同的參數(shù)類型氯庆;否則涣楷,運(yùn)行時(shí)可能出現(xiàn)找不到對(duì)應(yīng)方法的錯(cuò)誤环肘。
有一個(gè)例外侈沪,雖然同名類方法和實(shí)例方法擁有相同的選取器揭璃,但是它們可以有不同的參數(shù)類型和返回值類型。
3> 動(dòng)態(tài)綁定
- Objective-C的優(yōu)缺點(diǎn)亭罪。
答:objc優(yōu)點(diǎn):
1). Cateogies
2). Posing
3). 動(dòng)態(tài)識(shí)別
4).指標(biāo)計(jì)算
5).彈性訊息傳遞
6).不是一個(gè)過度復(fù)雜的 C 衍生語言
7).Objective-C 與 C++ 可混合編程
objc缺點(diǎn):
1).不支援命名空間
2).不支持運(yùn)算符重載
3).不支持多重繼承
4).使用動(dòng)態(tài)運(yùn)行時(shí)類型瘦馍,所有的方法都是函數(shù)調(diào)用,所以很多編譯時(shí)優(yōu)化方法都用不到应役。(如內(nèi)聯(lián)函數(shù)等)情组,性能低劣。
1.對(duì)于OC,你認(rèn)為最大的優(yōu)點(diǎn)和最大的不足是什么箩祥?對(duì)于不足之處院崇,現(xiàn)在有沒有可用的方法繞過這些不足來實(shí)現(xiàn)需求。如果可以話袍祖,有沒有考慮或者實(shí)現(xiàn)過重新實(shí)現(xiàn)OC的功能底瓣,如果有,具體怎么做蕉陋?
最大的優(yōu)點(diǎn)是它的運(yùn)行時(shí)特性捐凭,不足是沒有命名空間拨扶,對(duì)于命名沖突,可以使用長(zhǎng)命名法或特殊前綴解決茁肠,如果是引入的第三方庫之間的命名沖突患民,可以使用link命令及flag解決沖突。
oc中可修改和不可以修改類型垦梆。
答:可修改不可修改的集合類匹颤,這個(gè)我個(gè)人簡(jiǎn)單理解就是可動(dòng)態(tài)添加修改和不可動(dòng)態(tài)添加修改一樣。比如NSArray和NSMutableArray托猩,前者在初始化后的內(nèi)存控件就是固定不可變的惋嚎,后者可以添加等,可以動(dòng)態(tài)申請(qǐng)新的內(nèi)存空間站刑。我們說的oc是動(dòng)態(tài)運(yùn)行時(shí)語言是什么意思?
答:多態(tài)另伍。主要是將數(shù)據(jù)類型的確定由編譯時(shí),推遲到了運(yùn)行時(shí)绞旅。這個(gè)問題其實(shí)淺涉及到兩個(gè)概念摆尝,運(yùn)行時(shí)和多態(tài)。
簡(jiǎn)單來說因悲,運(yùn)行時(shí)機(jī)制使我們直到運(yùn)行時(shí)才去決定一個(gè)對(duì)象的類別堕汞,以及調(diào)用該類別對(duì)象指定方法。
多態(tài):不同對(duì)象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)晃琳。
意思就是假設(shè)生物類(life)都用有一個(gè)相同的方法-eat讯检。那人類屬于生物,豬也屬于生物卫旱,都繼承了life后人灼,實(shí)現(xiàn)各自的eat,但是調(diào)用是我們只需調(diào)用各自的eat方法顾翼。也就是不同的對(duì)象以自己的方式響應(yīng)了相同的消息(響應(yīng)了eat這個(gè)選擇器)投放。因此也可以說,運(yùn)行時(shí)機(jī)制是多態(tài)的基礎(chǔ)?~~~通知和協(xié)議的不同之處?
答:協(xié)議有控制鏈(has-a)的關(guān)系适贸,通知沒有灸芳。
首先我一開始也不太明白,什么叫控制鏈(專業(yè)術(shù)語了~)拜姿。但是簡(jiǎn)單分析下通知和代理的行為模式烙样,我們大致可以有自己的理解
簡(jiǎn)單來說,通知的話蕊肥,它可以一對(duì)多谒获,一條消息可以發(fā)送給多個(gè)消息接受者。
代理按我們的理解,到不是直接說不能一對(duì)多究反,比如我們知道的明星經(jīng)濟(jì)代理人寻定,很多時(shí)候一個(gè)經(jīng)濟(jì)人負(fù)責(zé)好幾個(gè)明星的事務(wù)。
只是對(duì)于不同明星間精耐,代理的事物對(duì)象都是不一樣的狼速,一一對(duì)應(yīng),不可能說明天要處理A明星要一個(gè)發(fā)布會(huì)卦停,代理人發(fā)出處理發(fā)布會(huì)的消息后向胡,別稱B的發(fā)布會(huì)了。但是通知就不一樣惊完,他只關(guān)心發(fā)出通知僵芹,而不關(guān)心多少接收到感興趣要處理。
因此控制鏈(has-a從英語單詞大致可以看出小槐,單一擁有和可控制的對(duì)應(yīng)關(guān)系拇派。什么是推送消息?
答:推送通知更是一種技術(shù),簡(jiǎn)單點(diǎn)就是客戶端獲取資源的一種手段凿跳。
普通情況下件豌,都是客戶端主動(dòng)的pull。推送則是服務(wù)器端主動(dòng)push控嗜。關(guān)于多態(tài)性
答:多態(tài)茧彤,子類指針可以賦值給父類。
這個(gè)題目其實(shí)可以出到一切面向?qū)ο笳Z言中疆栏,因此關(guān)于多態(tài)曾掂,繼承和封裝基本最好都有個(gè)自我意識(shí)的理解,也并非一定要把書上資料上寫的能背出來壁顶。什么是謂詞?
答:謂詞是通過NSPredicate珠洗,是通過給定的邏輯條件作為約束條件,完成對(duì)數(shù)據(jù)的篩選博助。
predicate = [NSPredicate predicateWithFormat:@"customerID == %d",n];
a = [customers filteredArrayUsingPredicate:predicate];
predicate = [NSPredicate predicateWithFormat:@"customerID == %d",n];
a = [customers filteredArrayUsingPredicate:predicate];做過的項(xiàng)目是否涉及網(wǎng)絡(luò)訪問功能险污,使用什么對(duì)象完成網(wǎng)絡(luò)功能?
答:ASIHTTPRequest與NSURLConnection簡(jiǎn)單介紹下NSURLConnection類及+ sendSynchronousRequest:returningResponse:error:與– initWithRequest:delegate:兩個(gè)方法的區(qū)別?
答: NSURLConnection主要用于網(wǎng)絡(luò)訪問,其中+ sendSynchronousRequest:returningResponse:error:是同步訪問數(shù)據(jù)富岳,即當(dāng)前線程會(huì)阻塞,并等待request的返回的response拯腮,而– initWithRequest:delegate:使用的是異步加載窖式,當(dāng)其完成網(wǎng)絡(luò)訪問后,會(huì)通過delegate回到主線程动壤,并其委托的對(duì)象萝喘。
62.談?wù)凮bject-C的內(nèi)存管理方式及過程?
答: 1).當(dāng)你使用new,alloc和copy方法創(chuàng)建一個(gè)對(duì)象時(shí),該對(duì)象的保留計(jì)數(shù)器值為1.當(dāng)你不再使用該對(duì)象時(shí),你要負(fù)責(zé)向該對(duì)象發(fā)送一條release或autorelease消息.這樣,該對(duì)象將在使用壽命結(jié)束時(shí)被銷毀.
2).當(dāng)你通過任何其他方法獲得一個(gè)對(duì)象時(shí),則假設(shè)該對(duì)象的保留計(jì)數(shù)器值為1,而且已經(jīng)被設(shè)置為自動(dòng)釋放,你不需要執(zhí)行任何操作來確保該對(duì)象被清理.如果你打算在一段時(shí)間內(nèi)擁有該對(duì)象,則需要保留它并確保在操作完成時(shí)釋放它.
3).如果你保留了某個(gè)對(duì)象,你需要(最終)釋放或自動(dòng)釋放該對(duì)象.必須保持retain方法和release方法的使用次數(shù)相等.
63.Object-C有私有方法嗎?私有變量呢阁簸?
答: objective-c – 類里面的方法只有兩種, 靜態(tài)方法和實(shí)例方法. 這似乎就不是完整的面向?qū)ο罅?按照OO的原則就是一個(gè)對(duì)象只暴露有用的東西. 如果沒有了私有方法的話, 對(duì)于一些小范圍的代碼重用就不那么順手了. 在類里面聲名一個(gè)私有方法
@interface Controller : NSObject {
NSString *something;
}
- (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private)
- (void)thisIsAPrivateMethod;
@end
@interface Controller : NSObject {
NSString *something;
}
- (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private)
- (void)thisIsAPrivateMethod;
@end
@private可以用來修飾私有變量
在Objective‐C中爬早,所有實(shí)例變量默認(rèn)都是私有的,所有實(shí)例方法默認(rèn)都是公有的
- 說說響應(yīng)鏈
答:事件響應(yīng)鏈启妹。包括點(diǎn)擊事件筛严,畫面刷新事件等。在視圖棧內(nèi)從上至下饶米,或者從下之上傳播桨啃。
可以說點(diǎn)事件的分發(fā),傳遞以及處理檬输。具體可以去看下touch事件這塊照瘾。因?yàn)閱柕奶橄蠡耍瑖?yán)重懷疑題目出到越后面就越籠統(tǒng)丧慈。
可以從責(zé)任鏈模式析命,來講通過事件響應(yīng)鏈處理,其擁有的擴(kuò)展性逃默。
1> 描述響應(yīng)者鏈條
當(dāng)觸摸事件發(fā)生時(shí),壓力轉(zhuǎn)為電信號(hào),iOS系統(tǒng)將產(chǎn)生UIEvent對(duì)象,記錄事件產(chǎn)生的時(shí)間和類型,然后系統(tǒng)將事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中碳却。
UIApplication會(huì)從事件隊(duì)列中取出最前面的事件,并將事件分發(fā)下去以便處理,通常泞边,先發(fā)送事件給應(yīng)用程序的主窗口(keyWindow)
主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來處理觸摸事件(從父到子,從后到前)鞋诗,這也是整個(gè)事件處理過程的第一步
找到合適的視圖控件后,就會(huì)調(diào)用視圖控件的touches方法來作具體的事件處理
二十四:時(shí)間傳遞&響應(yīng)者鏈
事件的產(chǎn)生和傳遞過程:
1.發(fā)生觸摸事件后关噪,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的隊(duì)列事件中
2.UIApplication會(huì)從事件隊(duì)列中取出最前面的事件,并將事件分發(fā)下去以便處理乌妙,通常會(huì)先發(fā)送事件給應(yīng)用程序的主窗口(keyWindow)
3.主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來處理觸摸事件
4.找到合適的視圖控件后使兔,就會(huì)調(diào)用視圖控件的touches方法來作事件的具體處理:touchesBegin… touchesMoved…touchesEnded等
5.這些touches方法默認(rèn)的做法是將事件順著響應(yīng)者鏈條向上傳遞,將事件叫個(gè)上一個(gè)相應(yīng)者進(jìn)行處理
一般事件的傳遞是從父控件傳遞到子控件的
如果父控件接受不到觸摸事件藤韵,那么子控件就不可能接收到觸摸事件 UIView不能接收觸摸事件的三種情況:
1.不接受用戶交互:userInteractionEnabled = NO;
2.隱藏:hidden = YES;
3.透明:alpha = 0.0~0.01
用戶的觸摸事件首先會(huì)由系統(tǒng)截獲虐沥,進(jìn)行包裝處理等。
然后遞歸遍歷所有的view泽艘,進(jìn)行碰觸測(cè)試(hitTest)欲险,直到找到可以處理事件的view。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event; // default returns YES if point is in bounds
大致的過程application –> window –> root view –>……–>lowest view
響應(yīng)者鏈
響應(yīng)者鏈條其實(shí)就是很多響應(yīng)者對(duì)象(繼承自UIResponder的對(duì)象)一起組合起來的鏈條稱之為響應(yīng)者鏈條
一般默認(rèn)做法是控件將事件順著響應(yīng)者鏈條向上傳遞匹涮,將事件交給上一個(gè)響應(yīng)者進(jìn)行處理天试。那么如何判斷當(dāng)前響應(yīng)者的上一個(gè)響應(yīng)者是誰呢?有以下兩個(gè)規(guī)則:
1.判斷當(dāng)前是否是控制器的View然低,如果是控制器的View喜每,上一個(gè)響應(yīng)者就是控制器
2.如果不是控制器的View务唐,上一個(gè)響應(yīng)者就是父控件
當(dāng)有view能夠處理觸摸事件后,開始響應(yīng)事件带兜。 系統(tǒng)會(huì)調(diào)用view的以下方法:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
可以多對(duì)象共同響應(yīng)事件枫笛。只需要在以上方法重載中調(diào)用super的方法。
大致的過程initial view –> super view –> …..–> view controller –> window –> Application
需要特別注意的一點(diǎn)是刚照,傳遞鏈中時(shí)沒有controller的刑巧,因?yàn)閏ontroller本身不具有大小的概念。但是響應(yīng)鏈中是有controller的涩咖,因?yàn)閏ontroller繼承自UIResponder海诲。
UIApplication–>UIWindow–>遞歸找到最合適處理的控件–>控件調(diào)用touches方法–>判斷是 否實(shí)現(xiàn)touches方法–>沒有實(shí)現(xiàn)默認(rèn)會(huì)將事件傳遞給上一個(gè)響應(yīng)者–>找到上一個(gè)響應(yīng)者–>找不到方法作廢
PS:利用響應(yīng)者鏈條我們可以通過調(diào)用touches的super 方法,讓多個(gè)響應(yīng)者同時(shí)響應(yīng)該事件檩互。
- frame和bounds有什么不同?
答:frame指的是:該view在父view坐標(biāo)系統(tǒng)中的位置和大小特幔。(參照點(diǎn)是父親的坐標(biāo)系統(tǒng))
bounds指的是:該view在本身坐標(biāo)系統(tǒng)中 的位置和大小。(參照點(diǎn)是本身坐標(biāo)系統(tǒng)) - 方法和選擇器有何不同?
答:selector是一個(gè)方法的名字闸昨,method是一個(gè)組合體蚯斯,包含了名字和實(shí)現(xiàn),詳情可以看apple文檔饵较。 - OC的垃圾回收機(jī)制?
答: OC2.0有Garbage collection拍嵌,但是iOS平臺(tái)不提供。
一般我們了解的objective-c對(duì)于內(nèi)存管理都是手動(dòng)操作的循诉,但是也有自動(dòng)釋放池横辆。
但是差了大部分資料,貌似不要和arc機(jī)制搞混就好了茄猫。 - 什么是延遲加載?
答:懶漢模式狈蚤,只在用到的時(shí)候才去初始化,也可以理解成延時(shí)加載划纽。
我覺得最好也最簡(jiǎn)單的一個(gè)列子就是tableView中圖片的加載顯示了脆侮。一個(gè)延時(shí)載,避免內(nèi)存過高勇劣,一個(gè)異步加載靖避,避免線程堵塞。 - 是否在一個(gè)視圖控制器中嵌入兩個(gè)tableview控制器?
答:一個(gè)視圖控制只提供了一個(gè)View視圖比默,理論上一個(gè)tableViewController也不能放吧幻捏,只能說可以嵌入一個(gè)tableview視圖。當(dāng)然退敦,題目本身也有歧義粘咖,如果不是我們定性思維認(rèn)為的UIViewController,而是宏觀的表示視圖控制者侈百,那我們倒是可以把其看成一個(gè)視圖控制者瓮下,它可以控制多個(gè)視圖控制器,比如TabbarController那樣的感覺钝域。 - 一個(gè)tableView是否可以關(guān)聯(lián)兩個(gè)不同的數(shù)據(jù)源?你會(huì)怎么處理?
答:首先我們從代碼來看讽坏,數(shù)據(jù)源如何關(guān)聯(lián)上的,其實(shí)是在數(shù)據(jù)源關(guān)聯(lián)的代理方法里實(shí)現(xiàn)的例证。
因此我們并不關(guān)心如何去關(guān)聯(lián)他路呜,他怎么關(guān)聯(lián)上,方法只是讓我返回根據(jù)自己的需要去設(shè)置如相關(guān)的數(shù)據(jù)源织咧。
因此胀葱,我覺得可以設(shè)置多個(gè)數(shù)據(jù)源啊,但是有個(gè)問題是笙蒙,你這是想干嘛呢?想讓列表如何顯示抵屿,不同的數(shù)據(jù)源分區(qū)塊顯示? - 什么時(shí)候使用NSMutableArray,什么時(shí)候使用NSArray?
答:當(dāng)數(shù)組在程序運(yùn)行時(shí)捅位,需要不斷變化的轧葛,使用NSMutableArray,當(dāng)數(shù)組在初始化后艇搀,便不再改變的尿扯,使用NSArray。需要指出的是焰雕,使用NSArray只表明的是該數(shù)組在運(yùn)行時(shí)不發(fā)生改變衷笋,即不能往NSAarry的數(shù)組里新增和刪除元素,但不表明其數(shù)組內(nèi)的元素的內(nèi)容不能發(fā)生改變矩屁。NSArray是線程安全的辟宗,NSMutableArray不是線程安全的,多線程使用到NSMutableArray需要注意档插。 - 給出委托方法的實(shí)例慢蜓,并且說出UITableVIew的Data Source方法
答:CocoaTouch框架中用到了大量委托,其中UITableViewDelegate就是委托機(jī)制的典型應(yīng)用郭膛,是一個(gè)典型的使用委托來實(shí)現(xiàn)適配器模式晨抡,其中UITableViewDelegate協(xié)議是目標(biāo),tableview是適配器则剃,實(shí)現(xiàn)UITableViewDelegate協(xié)議耘柱,并將自身設(shè)置為talbeview的delegate的對(duì)象,是被適配器棍现,一般情況下該對(duì)象是UITableViewController调煎。
UITableVIew的Data Source方法有
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
在應(yīng)用中可以創(chuàng)建多少autorelease對(duì)象,是否有限制?
答案:無如果我們不創(chuàng)建內(nèi)存池己肮,是否有內(nèi)存池提供給我們?
答:界面線程維護(hù)著自己的內(nèi)存池士袄,用戶自己創(chuàng)建的數(shù)據(jù)線程悲关,則需要?jiǎng)?chuàng)建該線程的內(nèi)存池什么時(shí)候需要在程序中創(chuàng)建內(nèi)存池?
答:用戶自己創(chuàng)建的數(shù)據(jù)線程,則需要?jiǎng)?chuàng)建該線程的內(nèi)存池類NSObject的那些方法經(jīng)常被使用?
答:NSObject是Objetive-C的基類娄柳,其由NSObject類及一系列協(xié)議構(gòu)成寓辱。
其中類方法alloc、class赤拒、 description 對(duì)象方法init秫筏、dealloc、– performSelector:withObject:afterDelay:等經(jīng)常被使用什么是簡(jiǎn)便構(gòu)造方法?
答:簡(jiǎn)便構(gòu)造方法一般由CocoaTouch框架提供挎挖,如NSNumber的
- numberWithBool:
- numberWithChar:
- numberWithDouble:
- numberWithFloat:
- numberWithInt:
- numberWithBool:
- numberWithChar:
- numberWithDouble:
- numberWithFloat:
- numberWithInt:
Foundation下大部分類均有簡(jiǎn)便構(gòu)造方法这敬,我們可以通過簡(jiǎn)便構(gòu)造方法,獲得系統(tǒng)給我們創(chuàng)建好的對(duì)象蕉朵,并且不需要手動(dòng)釋放崔涂。
如何使用Xcode設(shè)計(jì)通用應(yīng)用?
答:使用MVC模式設(shè)計(jì)應(yīng)用,其中Model層完成脫離界面墓造,即在Model層堪伍,其是可運(yùn)行在任何設(shè)備上,在controller層觅闽,根據(jù)iPhone與iPad(獨(dú)有UISplitViewController)的不同特點(diǎn)選擇不同的viewController對(duì)象帝雇。在View層,可根據(jù)現(xiàn)實(shí)要求蛉拙,來設(shè)計(jì)尸闸,其中以xib文件設(shè)計(jì)時(shí),其設(shè)置其為universal孕锄。UIView的動(dòng)畫效果有那些?
答:有很多遏片,如
UIViewAnimationOptionCurveEaseInOut
UIViewAnimationOptionCurveEaseIn
UIViewAnimationOptionCurveEaseOut
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown
UIViewAnimationOptionCurveEaseInOut
UIViewAnimationOptionCurveEaseIn
UIViewAnimationOptionCurveEaseOut
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown
64.Object-C有多繼承嗎氓皱?沒有的話用什么代替?cocoa 中所有的類都是NSObject 的子類
答: 多繼承在這里是用protocol 委托代理 來實(shí)現(xiàn)的
你不用去考慮繁瑣的多繼承 ,虛基類的概念.
ood的多態(tài)特性 在 obj-c 中通過委托來實(shí)現(xiàn).
65.內(nèi)存管理 Autorelease、retain微渠、copy膜蠢、assign的set方法和含義膜楷?
答:
1).你初始化(alloc/init)的對(duì)象砾嫉,你需要釋放(release)它。例如:
NSMutableArray aArray = [[NSArray alloc] init]; 后大咱,需要 [aArray release];
2).你retain或copy的恬涧,你需要釋放它。例如:
[aArray retain] 后碴巾,需要 [aArray release];
3).被傳遞(assign)的對(duì)象溯捆,你需要斟酌的retain和release。例如:
obj2 = [[obj1 someMethod] autorelease];
對(duì)象2接收對(duì)象1的一個(gè)自動(dòng)釋放的值厦瓢,或傳遞一個(gè)基本數(shù)據(jù)類型(NSInteger提揍,NSString)時(shí):你或希望將對(duì)象2進(jìn)行retain啤月,以防止它在被使用之前就被自動(dòng)釋放掉。但是在retain后碳锈,一定要在適當(dāng)?shù)臅r(shí)候進(jìn)行釋放顽冶。
關(guān)于索引計(jì)數(shù)(Reference Counting)的問題
retain值 = 索引計(jì)數(shù)(Reference Counting)
NSArray對(duì)象會(huì)retain(retain值加一)任何數(shù)組中的對(duì)象欺抗。當(dāng)NSArray被卸載(dealloc)的時(shí)候售碳,所有數(shù)組中的對(duì)象會(huì) 被 執(zhí)行一次釋放(retain值減一)。不僅僅是NSArray绞呈,任何收集類(Collection Classes)都執(zhí)行類似操作贸人。例如 NSDictionary,甚至UINavigationController佃声。
Alloc/init建立的對(duì)象艺智,索引計(jì)數(shù)為1。無需將其再次retain圾亏。
[NSArray array]和[NSDate date]等“方法”建立一個(gè)索引計(jì)數(shù)為1的對(duì)象十拣,但是也是一個(gè)自動(dòng)釋放對(duì)象。所以是本地臨時(shí)對(duì)象志鹃,那么無所謂了夭问。如果是打算在全Class中使用的變量(iVar),則必須retain它曹铃。
缺省的類方法返回值都被執(zhí)行了“自動(dòng)釋放”方法缰趋。(如上中的NSArray)
在類中的卸載方法“dealloc”中,release所有未被平衡的NS對(duì)象陕见。(所有未被autorelease秘血,而retain值為1的)C和obj-c 如何混用
答: 1).obj-c的編譯器處理后綴為m的文件時(shí),可以識(shí)別obj-c和c的代碼评甜,處理mm文件可以識(shí)別obj-c,c,c++代碼灰粮,但cpp文件必須只能用c/c++代碼,而且cpp文件include的頭文件中忍坷,也不能出現(xiàn)obj-c的代碼粘舟,因?yàn)閏pp只是cpp
2).在mm文件中混用cpp直接使用即可,所以obj-c混cpp不是問題
3).在cpp中混用obj-c其實(shí)就是使用obj-c編寫的模塊是我們想要的承匣。
如果模塊以類實(shí)現(xiàn)蓖乘,那么要按照cpp class的標(biāo)準(zhǔn)寫類的定義,頭文件中不能出現(xiàn)obj-c的東西韧骗,包括#import cocoa的嘉抒。實(shí)現(xiàn)文件中,即類的實(shí)現(xiàn)代碼中可以使用obj-c的東西袍暴,可以import,只是后綴是mm些侍。
如果模塊以函數(shù)實(shí)現(xiàn)隶症,那么頭文件要按c的格式聲明函數(shù),實(shí)現(xiàn)文件中岗宣,c++函數(shù)內(nèi)部可以用obj-c蚂会,但后綴還是mm或m。
總結(jié):只要cpp文件和cpp include的文件中不包含obj-c的東西就可以用了耗式,cpp混用obj-c的關(guān)鍵是使用接口胁住,而不能直接使用 實(shí)現(xiàn)代 碼,實(shí)際上cpp混用的是obj-c編譯后的o文件刊咳,這個(gè)東西其實(shí)是無差別的彪见,所以可以用。obj-c的編譯器支持cpp類別的作用?繼承和類別在實(shí)現(xiàn)中有何區(qū)別?
答:category 可以在不獲悉娱挨,不改變?cè)瓉泶a的情況下往里面添加新的方法余指,只能添加,不能刪除修改跷坝。并且如果類別和原來類中的方法產(chǎn)生名稱沖突酵镜,則類別將覆蓋原來的方法,因?yàn)轭悇e具有更高的優(yōu)先級(jí)柴钻。
類別主要有3個(gè)作用:
1).將類的實(shí)現(xiàn)分散到多個(gè)不同文件或多個(gè)不同框架中淮韭。
2).創(chuàng)建對(duì)私有方法的前向引用。
3).向?qū)ο筇砑臃钦絽f(xié)議顿颅。
繼承可以增加缸濒,修改或者刪除方法,并且可以增加屬性粱腻。類別和類擴(kuò)展的區(qū)別庇配。
答:category和extensions的不同在于 后者可以添加屬性。另外后者添加的方法是必須要實(shí)現(xiàn)的绍些。extensions可以認(rèn)為是一個(gè)私有的Category捞慌。oc中的協(xié)議和java中的接口概念有何不同?
答:OC中的代理有2層含義,官方定義為 formal和informal protocol柬批。前者和Java接口一樣啸澡。
informal protocol中的方法屬于設(shè)計(jì)模式考慮范疇,不是必須實(shí)現(xiàn)的氮帐,但是如果有實(shí)現(xiàn)嗅虏,就會(huì)改變類的屬性。
其實(shí)關(guān)于正式協(xié)議上沐,類別和非正式協(xié)議我很早前學(xué)習(xí)的時(shí)候大致看過皮服,也寫在了學(xué)習(xí)教程里。
“非正式協(xié)議概念其實(shí)就是類別的另一種表達(dá)方式“這里有一些你可能希望實(shí)現(xiàn)的方法,你可以使用他們更好的完成工作”龄广。
這個(gè)意思是硫眯,這些是可選的。比如我門要一個(gè)更好的方法择同,我們就會(huì)申明一個(gè)這樣的類別去實(shí)現(xiàn)两入。然后你在后期可以直接使用這些更好的方法。
這么看敲才,總覺得類別這玩意兒有點(diǎn)像協(xié)議的可選協(xié)議裹纳。”
現(xiàn)在來看归斤,其實(shí)protocal已經(jīng)開始對(duì)兩者都統(tǒng)一和規(guī)范起來操作痊夭,因?yàn)橘Y料中說“非正式協(xié)議使用interface修飾“,
現(xiàn)在我們看到協(xié)議中兩個(gè)修飾詞:“必須實(shí)現(xiàn)(@requied)”和“可選實(shí)現(xiàn)(@optional)”脏里。
深拷貝與前拷貝區(qū)別
深拷貝同淺拷貝的區(qū)別:淺拷貝是指針拷貝,對(duì)一個(gè)對(duì)象進(jìn)行淺拷貝虹曙,相當(dāng)于對(duì)指向?qū)ο蟮闹羔樳M(jìn)行復(fù)制迫横,產(chǎn)生一個(gè)新的指向這個(gè)對(duì)象的指針,那么就是有兩個(gè)指針指向同一個(gè)對(duì)象酝碳,這個(gè)對(duì)象銷毀后兩個(gè)指針都應(yīng)該置空矾踱。深拷貝是對(duì)一個(gè)對(duì)象進(jìn)行拷貝,相當(dāng)于對(duì)對(duì)象進(jìn)行復(fù)制疏哗,產(chǎn)生一個(gè)新的對(duì)象呛讲,那么就有兩個(gè)指針分別指向兩個(gè)對(duì)象。當(dāng)一個(gè)對(duì)象改變或者被銷毀后拷貝出來的新的對(duì)象不受影響返奉。
實(shí)現(xiàn)深拷貝需要實(shí)現(xiàn)NSCoying協(xié)議贝搁,實(shí)現(xiàn)- (id)copyWithZone:(NSZone *)zone 方法。當(dāng)對(duì)一個(gè)property屬性含有copy修飾符的時(shí)候芽偏,在進(jìn)行賦值操作的時(shí)候?qū)嶋H上就是調(diào)用這個(gè)方法雷逆。
父類實(shí)現(xiàn)深拷貝之后,子類只要重寫copyWithZone方法贱呐,在方法內(nèi)部調(diào)用父類的copyWithZone方法胯甩,之后實(shí)現(xiàn)自己的屬性的處理
父類沒有實(shí)現(xiàn)深拷貝行冰,子類除了需要對(duì)自己的屬性進(jìn)行處理,還要對(duì)父類的屬性進(jìn)行處理
淺拷貝:本質(zhì)上沒有產(chǎn)生新對(duì)象
深拷貝:產(chǎn)生了新對(duì)象
2> 什么是深拷貝淺拷貝
對(duì)于非容器類對(duì)象,不可變對(duì)象進(jìn)行copy操作為淺拷貝,引用計(jì)數(shù)器加1,其他三種為深拷貝
對(duì)于容器類對(duì)象,基本和非容器類對(duì)象一致,但注意其深拷貝是對(duì)象本身是對(duì)象復(fù)制,其中元素仍為指針復(fù)制,系統(tǒng)將initWithArray方法歸為了元素深拷貝,但其實(shí)如果元素為不可變?cè)?仍為指針復(fù)制,使用歸解檔可以實(shí)現(xiàn)真正的深拷貝,元素也是對(duì)象拷貝NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject: array]];
3> 字符串什么時(shí)候使用copy,strong
屬性引用的對(duì)象由兩種情況,可變和不可變字符串
引用對(duì)象不可變情況下,copy和strong一樣,copy為淺拷貝
引用對(duì)象可變情況下,如果希望屬性跟隨引用對(duì)象變化,使用strong,希望不跟隨變化使用copy
4> 字符串所在內(nèi)存區(qū)域
@“abc” 常量區(qū) stringwithformat 堆區(qū)
5> mutablecopy和copy @property(copy) NSMutableArray *arr;這樣寫有什么問題
mutablecopy返回可變對(duì)象,copy返回不可變對(duì)象
6> 如何讓自定義類可以使用copy修飾符
實(shí)現(xiàn)<NSCopying>協(xié)議,重寫copyWithZone方法
1.8 id和NSObject*的區(qū)別
id是一個(gè) objc_object 結(jié)構(gòu)體指針某宪,定義是
typedef struct objc_object *id
id可以理解為指向?qū)ο蟮闹羔槨K衞c的對(duì)象 id都可以指向锐朴,編譯器不會(huì)做類型檢查兴喂,id調(diào)用任何存在的方法都不會(huì)在編譯階段報(bào)錯(cuò),當(dāng)然如果這個(gè)id指向的對(duì)象沒有這個(gè)方法,該崩潰還是會(huì)崩潰的瞻想。
NSObject *指向的必須是NSObject的子類压真,調(diào)用的也只能是NSObjec里面的方法否則就要做強(qiáng)制類型轉(zhuǎn)換。
不是所有的OC對(duì)象都是NSObject的子類蘑险,還有一些繼承自NSProxy滴肿。NSObject *可指向的類型是id的子集
iOS 核心框架
CoreAnimation
CoreGraphics
CoreLocation
AVFoundation
Foundation
iOS核心機(jī)制
UITableView 重用
ObjC內(nèi)存管理;自動(dòng)釋放池佃迄,ARC如何實(shí)現(xiàn)
runloop
runtime
Block的定義泼差、特性、內(nèi)存區(qū)域呵俏、如何實(shí)現(xiàn)
Responder Chain
NSOperation
GCD
5.對(duì)于語句NSString*obj = [[NSData alloc] init]; obj在編譯時(shí)和運(yùn)行時(shí)分別時(shí)什么類型的對(duì)象堆缘?
編譯時(shí)是NSString的類型;運(yùn)行時(shí)是NSData類型的對(duì)象
2.#import 跟#include 又什么區(qū)別普碎,@class呢, #import<> 跟 #import”"又什么區(qū)別吼肥?
import是Objective-C導(dǎo)入頭文件的關(guān)鍵字,#include是C/C++導(dǎo)入頭文件的關(guān)鍵字,使用#import頭文件會(huì)自動(dòng)只導(dǎo)入一次麻车,不會(huì)重復(fù)導(dǎo)入缀皱,相當(dāng)于#include和#pragma once;@class告訴編譯器某個(gè)類的聲明动猬,當(dāng)執(zhí)行時(shí)啤斗,才去查看類的實(shí)現(xiàn)文件,可以解決頭文件的相互包含赁咙;#import<>用來包含系統(tǒng)的頭文件钮莲,#import””用來包含用戶頭文
- Objective-C的類可以多重繼承么?可以實(shí)現(xiàn)多個(gè)接口么?Category是什么?重寫一個(gè)類的方法用繼承好還是分類好?為什么?
答: Objective-C的類不可以多重繼承”怂可以實(shí)現(xiàn)多個(gè)接口崔拥,通過實(shí)現(xiàn)多個(gè)接口可以完成C++的多重繼承。Category是類別猿涨。一般情況重寫一個(gè)類的方法用繼承比較好握童,這樣不會(huì)影響其他地方正常使用這個(gè)方法。 -
import 跟#include 又什么區(qū)別叛赚,@class呢, #import<> 跟 #import””又什么區(qū)別?
答:#import是Objective-C導(dǎo)入頭文件的關(guān)鍵字澡绩,#include是C/C++導(dǎo)入頭文件的關(guān)鍵字,使用#import頭文件會(huì)自動(dòng)只導(dǎo)入一次,不會(huì)重復(fù)導(dǎo)入俺附,相當(dāng)于#include和#pragma once;@class告訴編譯器某個(gè)類的聲明肥卡,當(dāng)執(zhí)行時(shí),才去查看類的實(shí)現(xiàn)文件事镣,可以解決頭文件的相互包含;#import<>用來包含系統(tǒng)的頭文件步鉴,#import””用來包含用戶頭文件。
4.寫一個(gè)setter方法用于完成@property (nonatomic,retain)NSString *name,寫一個(gè)setter方法用于完成@property(nonatomic,copy)NSString *name
答:
- (void)setName:(NSString*)str {
if (_name != str) {
[_name release];
_name = [str retain];
}
} - (void)setName:(NSString *)str {
if (_name != str) {
[_name release];
_name = [str copy];
}
} - (void)setName:(NSString*)str {
if (_name != str) {
[_name release];
_name = [str retain];
}
} - (void)setName:(NSString *)str {
if (_name != str) {
[_name release];
_name = [str copy];
}
}
6.常見的Objective-C的數(shù)據(jù)類型有那些氛琢, 和C的基本數(shù)據(jù)類型有什么區(qū)別?如:NSInteger和int
答:Objective-C的數(shù)據(jù)類型有NSString喊递,NSNumber,NSArray阳似,NSMutableArray骚勘,NSData等等,這些都是class撮奏,創(chuàng)建后便是對(duì)象俏讹,而C語言的基本數(shù)據(jù)類型int,只是一定字節(jié)的內(nèi)存空間畜吊,用于存放數(shù)值;NSInteger是基本數(shù)據(jù)類型泽疆,并不是NSNumber的子類,當(dāng)然也不是NSObject的子類玲献。NSInteger是基本數(shù)據(jù)類型Int或者Long的別名(NSInteger的定義typedef long NSInteger)殉疼,它的區(qū)別在于,NSInteger會(huì)根據(jù)系統(tǒng)是32位還是64位來決定是本身是int還是Long青自。
7.id 聲明的對(duì)象有什么特性?
答:Id 聲明的對(duì)象具有運(yùn)行時(shí)的特性株依,即可以指向任意類型的Objcetive-C的對(duì)象;
8.Objective-C如何對(duì)內(nèi)存管理的,說說你的看法和解決方法?
答:Objective-C的內(nèi)存管理主要有三種方式ARC(自動(dòng)內(nèi)存計(jì)數(shù))、手動(dòng)內(nèi)存計(jì)數(shù)延窜、內(nèi)存池。
1). (Garbage Collection)自動(dòng)內(nèi)存計(jì)數(shù):這種方式和java類似抹锄,在你的程序的執(zhí)行過程中逆瑞。始終有一個(gè)高人在背后準(zhǔn)確地幫你收拾垃圾,你不用考慮它什么時(shí)候開始工作伙单,怎樣工作获高。你只需要明白,我申請(qǐng)了一段內(nèi)存空間吻育,當(dāng)我不再使用從而這段內(nèi)存成為垃圾的時(shí)候念秧,我就徹底的把它忘記掉,反正那個(gè)高人會(huì)幫我收拾垃圾布疼。遺憾的是摊趾,那個(gè)高人需要消耗一定的資源,在攜帶設(shè)備里面游两,資源是緊俏商品所以iPhone不支持這個(gè)功能砾层。所以“Garbage Collection”不是本入門指南的范圍,對(duì)“Garbage Collection”內(nèi)部機(jī)制感興趣的同學(xué)可以參考一些其他的資料贱案,不過說老實(shí)話“Garbage Collection”不大適合適初學(xué)者研究肛炮。
解決: 通過alloc – initial方式創(chuàng)建的, 創(chuàng)建后引用計(jì)數(shù)+1, 此后每retain一次引用計(jì)數(shù)+1, 那么在程序中做相應(yīng)次數(shù)的release就好了.
2). (Reference Counted)手動(dòng)內(nèi)存計(jì)數(shù):就是說,從一段內(nèi)存被申請(qǐng)之后,就存在一個(gè)變量用于保存這段內(nèi)存被使用的次數(shù)侨糟,我們暫時(shí)把它稱為計(jì)數(shù)器碍扔,當(dāng)計(jì)數(shù)器變?yōu)?的時(shí)候,那么就是釋放這段內(nèi)存的時(shí)候秕重。比如說不同,當(dāng)在程序A里面一段內(nèi)存被成功申請(qǐng)完成之后,那么這個(gè)計(jì)數(shù)器就從0變成1(我們把這個(gè)過程叫做alloc)悲幅,然后程序B也需要使用這個(gè)內(nèi)存套鹅,那么計(jì)數(shù)器就從1變成了2(我們把這個(gè)過程叫做retain)。緊接著程序A不再需要這段內(nèi)存了汰具,那么程序A就把這個(gè)計(jì)數(shù)器減1(我們把這個(gè)過程叫做release);程序B也不再需要這段內(nèi)存的時(shí)候卓鹿,那么也把計(jì)數(shù)器減1(這個(gè)過程還是release)。當(dāng)系統(tǒng)(也就是Foundation)發(fā)現(xiàn)這個(gè)計(jì)數(shù)器變 成員了0留荔,那么就會(huì)調(diào)用內(nèi)存回收程序把這段內(nèi)存回收(我們把這個(gè)過程叫做dealloc)吟孙。順便提一句,如果沒有Foundation聚蝶,那么維護(hù)計(jì)數(shù)器杰妓,釋放內(nèi)存等等工作需要你手工來完成。
解決:一般是由類的靜態(tài)方法創(chuàng)建的, 函數(shù)名中不會(huì)出現(xiàn)alloc或init字樣, 如[NSString string]和[NSArray arrayWithObject:], 創(chuàng)建后引用計(jì)數(shù)+0, 在函數(shù)出棧后釋放, 即相當(dāng)于一個(gè)棧上的局部變量. 當(dāng)然也可以通過retain延長(zhǎng)對(duì)象的生存期.
3). (NSAutoRealeasePool)內(nèi)存池:可以通過創(chuàng)建和釋放內(nèi)存池控制內(nèi)存申請(qǐng)和回收的時(shí)機(jī).
解決:是由autorelease加入系統(tǒng)內(nèi)存池, 內(nèi)存池是可以嵌套的, 每個(gè)內(nèi)存池都需要有一個(gè)創(chuàng)建釋放對(duì), 就像main函數(shù)中寫的一樣. 使用也很簡(jiǎn)單, 比如[[[NSString alloc]initialWithFormat:@”Hey you!”] autorelease], 即將一個(gè)NSString對(duì)象加入到最內(nèi)層的系統(tǒng)內(nèi)存池, 當(dāng)我們釋放這個(gè)內(nèi)存池時(shí), 其中的對(duì)象都會(huì)被釋放.
原子(atomic)跟非原子(non-atomic)屬性有什么區(qū)別?
答:
1). atomic提供多線程安全碘勉。是防止在寫未完成的時(shí)候被另外一個(gè)線程讀取巷挥,造成數(shù)據(jù)錯(cuò)誤
2). non-atomic:在自己管理內(nèi)存的環(huán)境中,解析的訪問器保留并自動(dòng)釋放返回的值验靡,如果指定了 nonatomic 倍宾,那么訪問器只是簡(jiǎn)單地返回這個(gè)值。
原子屬性采用的是"多讀單寫"機(jī)制的多線程策略
"多讀單寫"縮小了鎖范圍,比互斥鎖的性能好
規(guī)定只在主線程更新UI,就是因?yàn)槿绻诙嗑€程中更新,就需要給UI對(duì)象加鎖,防止資源搶占寫入錯(cuò)誤,但是這樣會(huì)降低UI交互的性能,所以ios設(shè)計(jì)讓所有UI對(duì)象都是非線程安全的(不加鎖),并規(guī)定只在主線程中更新UI,規(guī)避多線程搶占資源問題看下面的程序,第一個(gè)NSLog會(huì)輸出什么?這時(shí)str的retainCount是多少?第二個(gè)和第三個(gè)呢? 為什么?
NSMutableArray* ary = [[NSMutableArray array] retain];
NSString str = [NSString stringWithFormat:@"test"];
[str retain];
[aryaddObject:str];
NSLog(@”%@%d”,str,[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@”%@%d”,str,[str retainCount]);
[aryremoveAllObjects];
NSLog(@”%@%d”,str,[str retainCount]);
NSMutableArray ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"];
[str retain];
[aryaddObject:str];
NSLog(@”%@%d”,str,[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@”%@%d”,str,[str retainCount]);
[aryremoveAllObjects];
NSLog(@”%@%d”,str,[str retainCount]);
str的retainCount創(chuàng)建+1胜嗓,retain+1高职,加入數(shù)組自動(dòng)+1 3
retain+1,release-1辞州,release-1 2
數(shù)組刪除所有對(duì)象怔锌,所有數(shù)組內(nèi)的對(duì)象自動(dòng)-1 1
- 內(nèi)存管理的幾條原則時(shí)什么?按照默認(rèn)法則.那些關(guān)鍵字生成的對(duì)象需要手動(dòng)釋放?在和property結(jié)合的時(shí)候怎樣有效的避免內(nèi)存泄露?
答:誰申請(qǐng),誰釋放
遵循Cocoa Touch的使用原則;
內(nèi)存管理主要要避免“過早釋放”和“內(nèi)存泄漏”变过,對(duì)于“過早釋放”需要注意@property設(shè)置特性時(shí)埃元,一定要用對(duì)特性關(guān)鍵字,對(duì)于“內(nèi)存泄漏”牵啦,一定要申請(qǐng)了要負(fù)責(zé)釋放亚情,要細(xì)心。
關(guān)鍵字alloc 或new 生成的對(duì)象需要手動(dòng)釋放;
設(shè)置正確的property屬性哈雏,對(duì)于retain需要在合適的地方釋放楞件,
12.如何對(duì)iOS設(shè)備進(jìn)行性能測(cè)試?
答: Profile-> Instruments ->Time Profiler
設(shè)計(jì)模式
設(shè)計(jì)模式:MVC模式衫生、單例模式翘狱、觀察者模式况既、MVVM模式、工廠模式笑撞、代理模式黄伊、策略模式泪酱、適配器模式、模板模式还最、外觀模式墓阀、創(chuàng)建模式
1.mvc模式:model保存應(yīng)用模型和處理數(shù)據(jù)邏輯、view 負(fù)責(zé)model數(shù)據(jù)和交互控件的顯示拓轻、controller 負(fù)責(zé)model和View之間的通訊
2.單例模式:用一個(gè)靜態(tài)方法返回這個(gè)類的對(duì)象斯撮。系統(tǒng)只需要擁有一個(gè)的全局對(duì)象,這樣有利于我們協(xié)調(diào)系統(tǒng)整體的行為扶叉,這個(gè)對(duì)象是全局唯一的勿锅。整個(gè)項(xiàng)目里面之開辟一塊內(nèi)層、方便傳值和修改單例的屬性枣氧,比如登錄之后獲取的用戶數(shù)據(jù)存儲(chǔ)溢十、NSNotificationcenter、NSUserdefaults, sharedApplication 缺點(diǎn)是這塊內(nèi)層直到項(xiàng)目推出時(shí)才能釋放达吞。應(yīng)用場(chǎng)景:確保程序運(yùn)行期某個(gè)類张弛,只有一份實(shí)例,用于進(jìn)行資源共享控制酪劫。優(yōu)勢(shì):使用簡(jiǎn)單乌庶,延時(shí)求值,易于跨模塊 敏捷原則:?jiǎn)我宦氊?zé)原則 注意事項(xiàng):確保使用者只能通過 getInstance方法才能獲得契耿,單例類的唯一實(shí)例。java螃征,C++中使其沒有公有構(gòu)造函數(shù)搪桂,私有化并覆蓋其構(gòu)造函數(shù)。object c中盯滚,重寫allocWithZone方法踢械,保證即使用戶用 alloc方法直接創(chuàng)建單例類的實(shí)例,返回的也只是此單例類的唯一靜態(tài)變量魄藕。
? MVVM模式:vm 直接通訊一般使用RAC
? 觀察者模式:通過添加觀察者來觀察某個(gè)對(duì)象的實(shí)例變量的變化内列、當(dāng)該被觀察的對(duì)象的實(shí)例變量發(fā)生時(shí),觀察者響應(yīng) observeValueForKeyPath 方法背率,如常用的導(dǎo)航欄漸變话瞧。應(yīng)用場(chǎng)景:一般為model層對(duì)controller和view進(jìn)行的通知方式嫩与,不關(guān)心誰去接收,只負(fù)責(zé)發(fā)布信息交排。優(yōu)勢(shì):解耦合 敏捷原則:接口隔離原則划滋,開放-封閉原則 實(shí)例:Notification通知中心,注冊(cè)通知中心埃篓,任何位置可以發(fā)送消息处坪,注冊(cè)觀察者的對(duì)象可以接收。
? 工廠模式:快速創(chuàng)建對(duì)象的方式架专。將對(duì)象的創(chuàng)建和屬性賦值封裝成類方法同窘,如:創(chuàng)建常用按鈕、textFeild等部脚,forState這些枚舉值不用反復(fù)寫想邦,可以使調(diào)用工廠方法的地方代碼更加簡(jiǎn)潔。
應(yīng)用場(chǎng)景:工廠方式創(chuàng)建類的實(shí)例睛低,多與proxy模式配合案狠,創(chuàng)建可替換代理類。
優(yōu)勢(shì):易于替換钱雷,面向抽象編程骂铁,application只與抽象工廠和易變類的共性抽象類發(fā)生調(diào)用關(guān)系。
敏捷原則:DIP依賴倒置原則
實(shí)例:項(xiàng)目部署環(huán)境中依賴多個(gè)不同類型的數(shù)據(jù)庫時(shí)罩抗,需要使用工廠配合proxy完成易用性替換
注意事項(xiàng):項(xiàng)目初期拉庵,軟件結(jié)構(gòu)和需求都沒有穩(wěn)定下來時(shí),不建議使用此模式套蒂,因?yàn)槠淞觿?shì)也很明顯钞支,
增 加了代碼的復(fù)雜度,增加了調(diào)用層次操刀,增加了內(nèi)存負(fù)擔(dān)烁挟。所以要注意防止模式的濫用。
- 代理模式:代理模式給某一個(gè)對(duì)象提供一個(gè)代理對(duì)象骨坑,并由代理對(duì)象控制對(duì)源對(duì)象的引用撼嗓。比如一個(gè)工廠生產(chǎn)了產(chǎn)品,并不想直接賣給用戶欢唾,而是搞了很多代理商且警,用戶可以直接找代理商買東西,代理商從工廠進(jìn)貨礁遣。常見的如QQ的自動(dòng)回復(fù)就屬于代理攔截斑芜,代理模式在iphone中得到廣泛應(yīng)用。有點(diǎn)像c++中多繼承祟霍。增加對(duì)象的方法和屬性杏头。代理模式使項(xiàng)目的邏輯結(jié)構(gòu)比較直觀盈包,比如tableView的delegate和DataSource。優(yōu)勢(shì):解耦合 敏捷原則:開放-封閉原則大州。代理的目的是改變或傳遞控制鏈续语,允許一個(gè)類在某些特定時(shí)刻通知到其他類,而不需要獲取到那些類的指針厦画,可以減少框架復(fù)雜度和耦合度疮茄。另外一點(diǎn),代理可以理解為java中的回調(diào)監(jiān)聽機(jī)制的一種類似根暑。
? 策略模式:把一些獨(dú)立的算法單獨(dú)封裝起來力试,如我以前有個(gè)車管的app里面根據(jù)北斗定位步標(biāo)設(shè)備最后一次上傳數(shù)據(jù)庫的時(shí)間和車輛狀態(tài),來解析車輛當(dāng)前的狀態(tài)排嫌,數(shù)據(jù)庫中的16進(jìn)制的狀態(tài)(應(yīng)用的是交通部的808協(xié)議)畸裳,移動(dòng)端獲得將此狀態(tài)字段轉(zhuǎn)換成2進(jìn)制,判斷出車輛的24中狀態(tài)淳地。cell多種響應(yīng)效果
應(yīng)用場(chǎng)景:定義算法族怖糊,封裝起來,使他們之間可以相互替換颇象。優(yōu)勢(shì):使算法的變化獨(dú)立于使用算法的用戶
敏捷原則:接口隔離原則伍伤;多用組合,少用繼承遣钳;針對(duì)接口編程扰魂,而非實(shí)現(xiàn)。
實(shí)例:排序算法蕴茴,NSArray的sortedArrayUsingSelector劝评;經(jīng)典的鴨子會(huì)叫,會(huì)飛案例倦淀。 注意事項(xiàng):1蒋畜,剝離類中易于變化的行為,通過組合的方式嵌入抽象基類
變化的行為抽象基類為撞叽,所有可變變化的父類
用戶類的最終實(shí)例百侧,通過注入行為實(shí)例的方式,設(shè)定易變行為 防止了繼承行為方式能扒,導(dǎo)致無關(guān)行為污染子類。完成了策略封裝和可替換性
? 適配器模式:根據(jù)不同的場(chǎng)景選擇不同的對(duì)象辫狼,不如接手了一個(gè)舊代碼初斑,一進(jìn)公司就得修改需求,這時(shí)候的代碼邏輯沒法去反復(fù)理解膨处,如我的一個(gè)老項(xiàng)目里面有一個(gè)認(rèn)證功能將貨主認(rèn)證的model和車主認(rèn)證model放同一個(gè)model里面见秤,現(xiàn)在需要增加貨主認(rèn)證model屬性修改砂竖,此時(shí)就可以使用適配器了,原來其他地方還是走貨住認(rèn)證鹃答,因?yàn)槠髽I(yè)也是貨主的一種乎澄,可以建一個(gè)新的貨主model 新需求走新的貨主認(rèn)證。
? 模板模式:比如現(xiàn)在的項(xiàng)目建的基類baseViewController测摔,baseTableViewController置济,
? 外觀模式:專門為外部提供子類模塊功能的api類,如果保險(xiǎn)下單锋八,只需要支付用你選的支付方式和保險(xiǎn)種類及填寫的保險(xiǎn)的必要信息一起傳給下單的外觀對(duì)象即可浙于,在外觀類里面封裝了有下單和支付兩個(gè)子步簇,只需要將下保險(xiǎn)的是否成功的結(jié)果返給下單界面就行。
? 創(chuàng)建模式:將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示熊赖,假如在一個(gè)工具對(duì)象內(nèi)對(duì)軌跡點(diǎn)去重復(fù)掐隐、糾偏、漂移過濾等线欲,例加一個(gè)對(duì)象對(duì)外提供該時(shí)間段軌跡停車時(shí)長(zhǎng)和平均速度、平局耗油量等參數(shù)的接口。 拿到數(shù)組點(diǎn)在地圖上展示一下就可以了参萄,此數(shù)組對(duì)象的生成和使用可以分開。當(dāng)然了這些復(fù)雜的操作都在服務(wù)端做了剂府。
? MVP模式從經(jīng)典的MVC模式演變而來拧揽,將Controller替換成Presenter,依據(jù)MVP百度百科中的解釋腺占,MVP的優(yōu)點(diǎn)相比較于MVC是完全分離Model與View淤袜,Model與View的信息傳遞只能通過Controller/Presenter,我查閱資料發(fā)現(xiàn)在其他平臺(tái)上的MVC模式View與Model能否直接通訊有著不同的說法衰伯,但在iOS開發(fā)中铡羡,Apple是這么說的。在MVC下意鲸,所有的對(duì)象被歸類為一個(gè)model烦周,一個(gè)view,或一個(gè)controller怎顾。Model持有數(shù)據(jù)读慎,View顯示與用戶交互的界面,而View Controller調(diào)解Model和View之間的交互槐雾,在iOS開發(fā)中我按照Model與View無法相互通訊來理解夭委。
? MVVM
MVVM中,我們將視圖處理邏輯從C中剝離出來給V募强,剩下的業(yè)務(wù)邏輯部分被稱做View-Model株灸。
使用MVVM模式的iOS應(yīng)用的可測(cè)試性要好于MVC崇摄,因?yàn)閂iewModel中并不包含對(duì)View的更新,相比于MVC慌烧,減輕了Controller的負(fù)擔(dān)逐抑,使功能劃分更加合理。
我們應(yīng)該為app delegate的根視圖創(chuàng)建一個(gè)ViewModel屹蚊,當(dāng)我們要生成或展示另一個(gè)次級(jí)ViewController時(shí)厕氨,采用當(dāng)前的ViewModel為其創(chuàng)建一個(gè)子ViewModel。
viewModel tableView的布局實(shí)現(xiàn)淑翼,主要是計(jì)算行高腐巢。
ListViewModel加載網(wǎng)絡(luò)數(shù)據(jù),緩存圖片,用調(diào)度組實(shí)現(xiàn)玄括。監(jiān)聽下載完成冯丙,異步回調(diào)。
參考:http://blog.jobbole.com/20496/ 有23中設(shè)計(jì)模式
MVVM模式原理分析
視圖(View)遭京、視圖模型(ViewModel)胃惜、模型(Model)三部分組成
使用MVVM模式有幾大好處:
? 低耦合。View可以獨(dú)立于Model變化和修改哪雕,一個(gè)ViewModel可以綁定到不同的View上船殉,當(dāng)View變化的時(shí)候Model可以不變,當(dāng)Model變化的時(shí)候View也可以不變斯嚎。
? 可重用性利虫。可以把一些視圖的邏輯放在ViewModel里面堡僻,讓很多View重用這段視圖邏輯糠惫。
? 獨(dú)立開發(fā)。開發(fā)人員可以專注與業(yè)務(wù)邏輯和數(shù)據(jù)的開發(fā)(ViewModel)钉疫。設(shè)計(jì)人員可以專注于界面(View)的設(shè)計(jì)硼讽。
? 可測(cè)試性∩螅可以針對(duì)ViewModel來對(duì)界面(View)進(jìn)行測(cè)試
? 在 iOS 上使用 MVVM 的動(dòng)機(jī),就是讓它能減少 View Controller 的復(fù)雜性并使得表示邏輯更易于測(cè)試
? 將網(wǎng)絡(luò)請(qǐng)求抽象到單獨(dú)的類中
? 將界面的拼裝抽象到專門的類中
? 構(gòu)造 ViewModel 具體做法就是將 ViewController 給 View 傳遞數(shù)據(jù)這個(gè)過程固阁,抽象成構(gòu)造 ViewModel 的過程。抽象之后城菊,View 只接受 ViewModel备燃,而 Controller 只需要傳遞 ViewModel 這么一行代碼。而另外構(gòu)造 ViewModel 的過程凌唬,我們就可以移動(dòng)到另外的類中了赚爵。
? MVC 設(shè)計(jì)模式中的 ViewController 進(jìn)一步拆分,構(gòu)造出 網(wǎng)絡(luò)請(qǐng)求層、ViewModel 層冀膝、Service 層、Storage 層等其它類霎挟,來配合 Controller 工作窝剖,從而使 Controller 更加簡(jiǎn)單,我們的 App 更容易維護(hù)酥夭。 Controller 的代碼抽取出來赐纱,是有助于我們做測(cè)試工作的。
? ViewModel:存放各種業(yè)務(wù)邏輯和網(wǎng)絡(luò)請(qǐng)求
在MVC里熬北,View是可以直接訪問Model的疙描!從而,View里會(huì)包含Model信息讶隐,不可避免的還要包括一些業(yè)務(wù)邏輯起胰。 MVC模型關(guān)注的是Model的不變,所以巫延,在MVC模型里效五,Model不依賴于View,但是 View是依賴于Model的炉峰。不僅如此畏妖,因?yàn)橛幸恍I(yè)務(wù)邏輯在View里實(shí)現(xiàn)了,導(dǎo)致要更改View也是比較困難的疼阔,至少那些業(yè)務(wù)邏輯是無法重用的戒劫。
MVVM在概念上是真正將頁面與數(shù)據(jù)邏輯分離的模式,它把數(shù)據(jù)綁定工作放到一個(gè)JS里去實(shí)現(xiàn)婆廊,而這個(gè)JS文件的主要功能是完成數(shù)據(jù)的綁定迅细,即把model綁定到UI的元素上。
有人做過測(cè)試:使用Angular(MVVM)代替Backbone(MVC)來開發(fā)否彩,代碼可以減少一半疯攒。
此外,MVVM另一個(gè)重要特性列荔,雙向綁定敬尺。它更方便你同時(shí)維護(hù)頁面上都依賴于某個(gè)字段的N個(gè)區(qū)域,而不用手動(dòng)更新它們贴浙。
總結(jié):
優(yōu)點(diǎn):MVVM就是在MVC的基礎(chǔ)上加入了一個(gè)視圖模型viewModel砂吞,用于數(shù)據(jù)有效性的驗(yàn)證,視圖的展示邏輯崎溃,網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求及處理蜻直,其他的 數(shù)據(jù)處理邏輯集合,并定下相關(guān)接口和協(xié)議。相比起MVC概而,MVVM中vc的職責(zé)和復(fù)雜度更小呼巷,對(duì)數(shù)據(jù)處理邏輯的測(cè)試更加方便,對(duì)bug的原因排查更加方便赎瑰,代碼可閱讀性王悍,重用性和可維護(hù)性更高。MVVM耦合性更低餐曼。MVVM不同層級(jí)的職責(zé)更加明確压储,更有利于代碼的編寫和團(tuán)隊(duì)的協(xié)作。 缺點(diǎn):MVVM相比MVC代碼量有所增加源譬。MVVM相比MVC在代碼編寫之前需要有更清晰的模式思路集惋。
2、說說常用的幾種傳值方式
1.方法傳值
2.屬性傳值:常用在從上一個(gè)頁面向下一個(gè)頁面?zhèn)髦挡饶铮枰谙乱粋€(gè)頁面添加屬性刮刑,
3.delegate傳值:需要定義協(xié)議方法,服從代理霸饲、建立代理關(guān)系實(shí)現(xiàn)傳值为朋,一對(duì)一的使用場(chǎng)景,代理是類似于c++實(shí)現(xiàn)多繼承的(oc沒有多繼承)厚脉,代理方式可以直觀的看出對(duì)象的邏輯關(guān)系习寸。例如UITableView的delegate和DataSource
4.通知傳值:可以適用于一對(duì)多的場(chǎng)景,界面直接不需直接的聯(lián)系傻工,缺點(diǎn)是不直觀霞溪,并且當(dāng)通知不需要時(shí)要從通知中心移除。子線程發(fā)通知可能會(huì)導(dǎo)致內(nèi)層泄露。
5.單例傳值:同上題2點(diǎn)
6.block傳值:一般應(yīng)用于需要回調(diào)的場(chǎng)景。
7.數(shù)據(jù)存儲(chǔ)傳值灭将,如使用userDefault,sql 等
什么時(shí)候用delegate殴蓬,什么時(shí)候用Notification
delegate針對(duì)one-to-one關(guān)系,并且reciever可以返回值給sender蟋滴,notification 可以針對(duì)one-to-one/many/none,reciever無法返回值給sender.所以,delegate用于sender希望接受到 reciever的某個(gè)功能反饋值染厅,notification用于通知多個(gè)object某個(gè)事件。
5> delegate和block
block使代碼更緊湊,便于閱讀,delegate可以設(shè)置必選和可選的方法實(shí)現(xiàn),相比block
block可以訪存局部變量. 不需要像以前的回調(diào)一樣津函,把在操作后所有需要用到的數(shù)據(jù)封裝成特定的數(shù)據(jù)結(jié)構(gòu), 你完全可以直接訪問局部變量.
- 對(duì)于單例的理解
答:在objective-c中要實(shí)現(xiàn)一個(gè)單例類肖粮,至少需要做以下四個(gè)步驟:
1).為單例對(duì)象實(shí)現(xiàn)一個(gè)靜態(tài)實(shí)例,并初始化尔苦,然后設(shè)置成nil涩馆,
2).實(shí)現(xiàn)一個(gè)實(shí)例構(gòu)造方法檢查上面聲明的靜態(tài)實(shí)例是否為nil行施,如果是則新建并返回一個(gè)本類的實(shí)例,
3).重寫allocWithZone方法魂那,用來保證其他人直接使用alloc和init試圖獲得一個(gè)新實(shí)力的時(shí)候不產(chǎn)生一個(gè)新實(shí)例蛾号,
4).適當(dāng)實(shí)現(xiàn)allocWitheZone、copyWithZone涯雅、release和autorelease须教。
10.從設(shè)計(jì)模式角度分析代理,通知和KVO區(qū)別斩芭?ios SDK 提供 的framework使用了哪些設(shè)計(jì)模式,為什么使用乐疆?有哪些好處和壞處?
NSNotification是通知模式在iOS的實(shí)現(xiàn)划乖,
KVC(key-value coding)是一個(gè)通過屬性名訪問屬性變量的機(jī)制。
KVO的全稱是鍵值觀察(Key-value observing),其是基于KVC的挤土,
例如 將Module層的變化琴庵,通知到多個(gè)Controller對(duì)象時(shí),可以使用NSNotification仰美;如果是只需要觀察某個(gè)對(duì)象的某個(gè)屬性迷殿,可以使用KVO。
對(duì)于委托模式咖杂,在設(shè)計(jì)模式中是對(duì)象適配器模式庆寺,其是delegate是指向某個(gè)對(duì)象的,這是一對(duì)一的關(guān)系诉字,
而在通知模式中懦尝,往往是一對(duì)多的關(guān)系。
委托模式壤圃,從技術(shù)上可以實(shí)現(xiàn)改變delegate指向的對(duì)象陵霉,但不建議這樣做,會(huì)讓人迷惑伍绳,如果一個(gè)delegate對(duì)象不斷改變踊挠,指向不同的對(duì)象。
三種模式都是一個(gè)對(duì)象傳遞事件給另外一個(gè)對(duì)象冲杀,并且不要他們有耦合效床。三種模式都是對(duì)象來通知某個(gè)事件發(fā)生了的方法,或者更準(zhǔn)確的說漠趁,是允許其他的對(duì)象收到這種事件的方法扁凛。
delegate的優(yōu)勢(shì):
1.非常嚴(yán)格的語法。所有將聽到的事件必須是在delegate協(xié)議中有清晰的定義闯传。
2.如果delegate中的一個(gè)方法沒有實(shí)現(xiàn)那么就會(huì)出現(xiàn)編譯警告/錯(cuò)誤
3.協(xié)議必須在controller的作用域范圍內(nèi)定義
4.在一個(gè)應(yīng)用中的控制流程是可跟蹤的并且是可識(shí)別的谨朝;
5.在一個(gè)控制器中可以定義定義多個(gè)不同的協(xié)議卤妒,每個(gè)協(xié)議有不同的delegates
6.沒有第三方對(duì)象要求保持/監(jiān)視通信過程。
7.能夠接收調(diào)用的協(xié)議方法的返回值字币。這意味著delegate能夠提供反饋信息給controller
缺點(diǎn):
1.需要定義很多代碼:1.協(xié)議定義则披;2.controller的delegate屬性;3.在delegate本身中實(shí)現(xiàn)delegate方法定義
2.在釋放代理對(duì)象時(shí)洗出,需要小心的將delegate改為nil士复。一旦設(shè)定失敗,那么調(diào)用釋放對(duì)象的方法將會(huì)出現(xiàn)內(nèi)存crash
3.在一個(gè)controller中有多個(gè)delegate對(duì)象翩活,并且delegate是遵守同一個(gè)協(xié)議阱洪,但還是很難告訴多個(gè)對(duì)象同一個(gè)事件,不過有可能菠镇。
它是一個(gè)單例對(duì)象冗荸,允許當(dāng)事件發(fā)生時(shí)通知一些對(duì)象。它允許我們?cè)诘统潭锐詈系那闆r下利耍,滿足控制器與一個(gè)任意的對(duì)象進(jìn)行通信的目的蚌本。這種模式的基本特征是為了讓其他的對(duì)象能夠接收到在該controller中發(fā)生某種事件而產(chǎn)生的消息,controller用一個(gè)key(通知名稱)隘梨。這樣對(duì)于controller來說是匿名的程癌,其他的使用同樣的key來注冊(cè)了該通知的對(duì)象(即觀察者)能夠?qū)νㄖ氖录鞒龇磻?yīng)。
優(yōu)勢(shì):
1.不需要編寫多少代碼轴猎,實(shí)現(xiàn)比較簡(jiǎn)單嵌莉;
2.對(duì)于一個(gè)發(fā)出的通知,多個(gè)對(duì)象能夠做出反應(yīng)税稼,即1對(duì)多的方式實(shí)現(xiàn)簡(jiǎn)單
3.controller能夠傳遞context對(duì)象(dictionary)烦秩,context對(duì)象攜帶了關(guān)于發(fā)送通知的自定義的信息
缺點(diǎn):
1.在編譯期不會(huì)檢查通知是否能夠被觀察者正確的處理;
2.在釋放注冊(cè)的對(duì)象時(shí)郎仆,需要在通知中心取消注冊(cè)只祠;
3.在調(diào)試的時(shí)候應(yīng)用的工作以及控制過程難跟蹤;
4.需要第三方對(duì)喜愛那個(gè)來管理controller與觀察者對(duì)象之間的聯(lián)系扰肌;
5.controller和觀察者需要提前知道通知名稱抛寝、UserInfo dictionary keys。如果這些沒有在工作區(qū)間定義曙旭,那么會(huì)出現(xiàn)不同步的情況盗舰;
6.通知發(fā)出后,controller不能從觀察者獲得任何的反饋信息桂躏。
KVO是一個(gè)對(duì)象能夠觀察另外一個(gè)對(duì)象的屬性的值钻趋,并且能夠發(fā)現(xiàn)值的變化。前面兩種模式更加適合一個(gè)controller與任何其他的對(duì)象進(jìn)行通信剂习,而KVO更加適合任何類型的對(duì)象偵聽另外一個(gè)任意對(duì)象的改變(這里也可以是controller蛮位,但一般不是controller)较沪。這是一個(gè)對(duì)象與另外一個(gè)對(duì)象保持同步的一種方法,即當(dāng)另外一種對(duì)象的狀態(tài)發(fā)生改變時(shí)失仁,觀察對(duì)象馬上作出反應(yīng)尸曼。它只能用來對(duì)屬性作出反應(yīng),而不會(huì)用來對(duì)方法或者動(dòng)作作出反應(yīng)萄焦。
優(yōu)點(diǎn):
1.能夠提供一種簡(jiǎn)單的方法實(shí)現(xiàn)兩個(gè)對(duì)象間的同步控轿。例如:model和view之間同步;
2.能夠?qū)Ψ俏覀儎?chuàng)建的對(duì)象拂封,即內(nèi)部對(duì)象的狀態(tài)改變作出響應(yīng)茬射,而且不需要改變內(nèi)部對(duì)象(SKD對(duì)象)的實(shí)現(xiàn);
3.能夠提供觀察的屬性的最新值以及先前值冒签;
4.用key paths來觀察屬性躲株,因此也可以觀察嵌套對(duì)象;
5.完成了對(duì)觀察對(duì)象的抽象镣衡,因?yàn)椴恍枰~外的代碼來允許觀察值能夠被觀察
缺點(diǎn):
1.我們觀察的屬性必須使用strings來定義。因此在編譯器不會(huì)出現(xiàn)警告以及檢查档悠;
2.對(duì)屬性重構(gòu)將導(dǎo)致我們的觀察代碼不再可用廊鸥;
3.復(fù)雜的“IF”語句要求對(duì)象正在觀察多個(gè)值。這是因?yàn)樗械挠^察代碼通過一個(gè)方法來指向辖所;
1.2 KVO惰说,NSNotification,delegate及block區(qū)別
KVO就是cocoa框架實(shí)現(xiàn)的觀察者模式缘回,一般同KVC搭配使用吆视,通過KVO可以監(jiān)測(cè)一個(gè)值的變化,比如View的高度變化酥宴。是一對(duì)多的關(guān)系啦吧,一個(gè)值的變化會(huì)通知所有的觀察者。
NSNotification是通知拙寡,也是一對(duì)多的使用場(chǎng)景授滓。在某些情況下,KVO和NSNotification是一樣的肆糕,都是狀態(tài)變化之后告知對(duì)方般堆。NSNotification的特點(diǎn),就是需要被觀察者先主動(dòng)發(fā)出通知诚啃,然后觀察者注冊(cè)監(jiān)聽后再來進(jìn)行響應(yīng)淮摔,比KVO多了發(fā)送通知的一步,但是其優(yōu)點(diǎn)是監(jiān)聽不局限于屬性的變化始赎,還可以對(duì)多種多樣的狀態(tài)變化進(jìn)行監(jiān)聽和橙,監(jiān)聽范圍廣袍睡,使用也更靈活。
delegate 是代理疗涉,就是我不想做的事情交給別人做脐帝。比如狗需要吃飯,就通過delegate通知主人仆百,主人就會(huì)給他做飯厕隧、盛飯、倒水俄周,這些操作吁讨,這些狗都不需要關(guān)心,只需要調(diào)用delegate(代理人)就可以了峦朗,由其他類完成所需要的操作建丧。所以delegate是一對(duì)一關(guān)系。
block是delegate的另一種形式波势,是函數(shù)式編程的一種形式翎朱。使用場(chǎng)景跟delegate一樣,相比delegate更靈活尺铣,而且代理的實(shí)現(xiàn)更直觀拴曲。
KVO一般的使用場(chǎng)景是數(shù)據(jù),需求是數(shù)據(jù)變化凛忿,比如股票價(jià)格變化澈灼,我們一般使用KVO(觀察者模式)。delegate一般的使用場(chǎng)景是行為店溢,需求是需要?jiǎng)e人幫我做一件事情叁熔,比如買賣股票,我們一般使用delegate床牧。
Notification一般是進(jìn)行全局通知荣回,比如利好消息一出,通知大家去買入戈咳。delegate是強(qiáng)關(guān)聯(lián)驹马,就是委托和代理雙方互相知道,你委托別人買股票你就需要知道經(jīng)紀(jì)人除秀,經(jīng)紀(jì)人也不要知道自己的顧客糯累。Notification是弱關(guān)聯(lián),利好消息發(fā)出册踩,你不需要知道是誰發(fā)的也可以做出相應(yīng)的反應(yīng)泳姐,同理發(fā)消息的人也不需要知道接收的人也可以正常發(fā)出消息
三、運(yùn)行時(shí)(runTime)
運(yùn)行時(shí)的定義:運(yùn)行時(shí)機(jī)制暂吉,最主要的是消息機(jī)制胖秒,oc底層的一套C語言的API(引入<objc/runtime.h>或者<objc/message.h>), 編譯器是會(huì)將oc代碼轉(zhuǎn)化為運(yùn)行時(shí)代碼缎患。在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù),只有在真正運(yùn)行的時(shí)候才能根據(jù)函數(shù)的名稱找到對(duì)應(yīng)的函數(shù)來調(diào)用阎肝。
運(yùn)行時(shí)的作用:
1挤渔、替換系統(tǒng)的方法或者某個(gè)對(duì)象的方法 例如:熱更新
2、動(dòng)態(tài)添加分類风题、為對(duì)象添加屬性判导、添加實(shí)例方法 例如:熱創(chuàng)建
3、遍歷屬性實(shí)現(xiàn)自動(dòng)歸檔沛硅、自動(dòng)解檔和字典轉(zhuǎn)模型 如YYmodel眼刃、MJextension、JsonModel 里面都是遍歷屬性列表進(jìn)行屬性賦值摇肌。
4擂红、查找對(duì)象 實(shí)現(xiàn)萬能跳轉(zhuǎn)跳轉(zhuǎn),例如收到推送的通知跳轉(zhuǎn)到對(duì)應(yīng)的頁面
五.runtime/消息轉(zhuǎn)發(fā)機(jī)制
1.runtime http://www.cocoachina.com/ios/20150715/12540.html
1> 什么是runtime
runtime是一套比較底層的純C語言API, 屬于1個(gè)C語言庫, 包含了很多底層的C語言API围小。
在我們平時(shí)編寫的OC代碼中, 程序運(yùn)行過程時(shí), 其實(shí)最終都是轉(zhuǎn)成了runtime的C語言代碼, runtime算是OC的幕后工作者,objc_msgSend
2> runtime干什么用,使用場(chǎng)景
runtime是屬于OC的底層, 可以進(jìn)行一些非常底層的操作(用OC是無法現(xiàn)實(shí)的, 不好實(shí)現(xiàn))
在程序運(yùn)行過程中, 動(dòng)態(tài)創(chuàng)建一個(gè)類(比如KVO的底層實(shí)現(xiàn)) objc_allocateClassPair昵骤,class_addIvar,objc_registerClassPair
在程序運(yùn)行過程中, 動(dòng)態(tài)地為某個(gè)類添加屬性\方法, 修改屬性值\方法(修改封裝的框架) objc_setAssociatedObject object_setIvar
遍歷一個(gè)類的所有成員變量(屬性)\所有方法(字典轉(zhuǎn)模型,歸解檔) class_copyIvarList class_copyPropertyList class_copyMethodList
2.消息機(jī)制
1> 消息轉(zhuǎn)發(fā)的原理
當(dāng)向一個(gè)對(duì)象發(fā)送消息時(shí)肯适,objc_msgSend方法根據(jù)對(duì)象的isa指針找到對(duì)象的類涉茧,然后在類的調(diào)度表(dispatch table)中查找selector。如果無法找到selector疹娶,objc_msgSend通過指向父類的指針找到父類,并在父類的調(diào)度表(dispatch table)中查找selector伦连,以此類推直到NSObject類雨饺。一旦查找到selector,objc_msgSend方法根據(jù)調(diào)度表的內(nèi)存地址調(diào)用該實(shí)現(xiàn)惑淳。 通過這種方式额港,message與方法的真正實(shí)現(xiàn)在執(zhí)行階段才綁定。
為了保證消息發(fā)送與執(zhí)行的效率歧焦,系統(tǒng)會(huì)將全部selector和使用過的方法的內(nèi)存地址緩存起來移斩。每個(gè)類都有一個(gè)獨(dú)立的緩存,緩存包含有當(dāng)前類自己的 selector以及繼承自父類的selector绢馍。查找調(diào)度表(dispatch table)前向瓷,消息發(fā)送系統(tǒng)首先檢查receiver對(duì)象的緩存。
緩存命中的情況下舰涌,消息發(fā)送(messaging)比直接調(diào)用方法(function call)只慢一點(diǎn)點(diǎn)點(diǎn)點(diǎn)猖任。
2> SEL isa super cmd 是什么
sel: 一種類型,表示方法名稱,類似字符串(可互轉(zhuǎn))
isa:在方法底層對(duì)應(yīng)的objc_msgSend調(diào)用時(shí),會(huì)根據(jù)isa找到對(duì)象所在的類對(duì)象,類對(duì)象中包含了調(diào)度表(dispatch table),該表將類的sel和方法的實(shí)際內(nèi)存地址關(guān)聯(lián)起來
super_class:每一個(gè)類中還包含了一個(gè)super_class指針,用來指向父類對(duì)象
_cmd在Objective-C的方法中表示當(dāng)前方法的selector,正如同self表示當(dāng)前方法調(diào)用的對(duì)象實(shí)例
IMP定義為 id (*IMP) (id, SEL, …)瓷耙。這樣說來朱躺, IMP是一個(gè)指向函數(shù)的指針刁赖,這個(gè)被指向的函數(shù)包括id(“self”指針),調(diào)用的SEL(方法名)长搀,再加上一些其他參數(shù).說白了IMP就是實(shí)現(xiàn)方法
3> 動(dòng)態(tài)綁定
—在運(yùn)行時(shí)確定要調(diào)用的方法
動(dòng)態(tài)綁定將調(diào)用方法的確定也推遲到運(yùn)行時(shí)宇弛。在編譯時(shí),方法的 調(diào)用并不和代碼綁定在一起源请,只有在消實(shí)發(fā)送出來之后枪芒,才確定被調(diào)用的代碼。通過動(dòng)態(tài)類型和動(dòng)態(tài)綁定技術(shù)巢钓,您的代碼每次執(zhí)行都可以得到不同的結(jié)果病苗。運(yùn)行時(shí)因 子負(fù)責(zé)確定消息的接收者和被調(diào)用的方法。運(yùn)行時(shí)的消息分發(fā)機(jī)制為動(dòng)態(tài)綁定提供支持症汹。當(dāng)您向一個(gè)動(dòng)態(tài)類型確定了的對(duì)象發(fā)送消息時(shí)硫朦,運(yùn)行環(huán)境系統(tǒng)會(huì)通過接收者 的isa指針定位對(duì)象的類,并以此為起點(diǎn)確定被調(diào)用的方法背镇,方法和消息是動(dòng)態(tài)綁定的咬展。而且,您不必在Objective-C 代碼中做任何工作瞒斩,就可以自動(dòng)獲取動(dòng)態(tài)綁定的好處破婆。您在每次發(fā)送消息時(shí),特別是當(dāng)消息的接收者是動(dòng)態(tài)類型已經(jīng)確定的對(duì)象時(shí)胸囱,動(dòng)態(tài)綁定就會(huì)例行而透明地發(fā)生
五祷舀、使用bugly進(jìn)行崩潰分析
1.測(cè)試的時(shí)候我們通常通過打印日志、斷點(diǎn)烹笔、崩潰信息等定位bug裳扯。(null、數(shù)組取了null,未實(shí)現(xiàn)的方法)
2.打包后的崩潰谤职,特別是不是一直出現(xiàn)的bug饰豺,這些可以通過友盟,將友盟的崩潰信息列表下載到本地允蜈,使用終端解析冤吨,太麻煩了
3.集成bugly 可以快速查看 崩潰信息,需要將DYSM 映射表傳到bugly 網(wǎng)站饶套,
buly 可以定定義日志 可以用來記錄重要事件的崩潰 環(huán)境漩蟆,bugly可以自定義異常如某個(gè)接口不能出現(xiàn)空值。
六妓蛮、jenkens 持續(xù)打包爆安,
普通的打包方式,如使用xcode打包 傳蒲公英 再將下載二維碼 發(fā)給相關(guān)測(cè)試人員比較耗時(shí),使用jenkens 是一個(gè)shell 語言開發(fā)的腳本工具扔仓,經(jīng)這幾個(gè)步族連到一起 使打包更節(jié)約時(shí)間褐奥。
KVO&KVC
底層實(shí)現(xiàn):
KVC運(yùn)用了一個(gè)isa-swizzling技術(shù)。isa-swizzling就是類型混合指針機(jī)制翘簇。KVC主要通過isa- swizzling撬码,來實(shí)現(xiàn)其內(nèi)部查找定位的。isa指針版保,如其名稱所指呜笑,(就是is a kind of的意思),指向維護(hù)分發(fā)表的對(duì)象的類彻犁。該分發(fā)表實(shí)際上包含了指向?qū)崿F(xiàn)類中的方法的指針叫胁,和其它數(shù)據(jù)。
當(dāng)觀察者為一個(gè)對(duì)象的屬性進(jìn)行了注冊(cè)汞幢,被觀察對(duì)象的isa指針被修改的時(shí)候驼鹅,isa指針就會(huì)指向一個(gè)中間類,而不是真實(shí)的類森篷。所以isa指 針其實(shí)不需要指向?qū)嵗龑?duì)象真實(shí)的類绰更。所以我們的程序最好不要依賴于isa指針反番。在調(diào)用類的方法的時(shí)候,最好要明確對(duì)象實(shí)例的類名捞蚂。
KVO概述
KVO,即:Key-Value Observing显拜,它提供一種機(jī)制夕玩,當(dāng)指定的對(duì)象的屬性被修改后穆壕,則對(duì)象就會(huì)接受到通知考传。簡(jiǎn)單的說就是每次指定的被觀察的對(duì)象的屬性被修改后,KVO就會(huì)自動(dòng)通知相應(yīng)的觀察者了前联。
使用方法
系統(tǒng)框架已經(jīng)支持KVO功戚,所以程序員在使用的時(shí)候非常簡(jiǎn)單。
1: 注冊(cè)蛀恩,指定被觀察者的屬性,
2: 實(shí)現(xiàn)回調(diào)方法
3: 移除觀察
KVC概述
KVC是KeyValueCoding的簡(jiǎn)稱茂浮,它是一種可以直接通過字符串的名字(key)來訪問類屬性(實(shí)例變量)的機(jī)制双谆。而不是通過調(diào)用Setter、Getter方法訪問席揽。
當(dāng)使用KVO顽馋、Core Data、CocoaBindings幌羞、AppleScript(Mac支持)時(shí)寸谜,KVC是關(guān)鍵技術(shù)。
使用方法
關(guān)鍵方法定義在:NSKeyValueCodingprotocol
KVC支持類對(duì)象和內(nèi)建基本數(shù)據(jù)類型属桦。
獲取值
valueForKey:熊痴,傳入NSString屬性的名字他爸。
valueForKeyPath:,傳入NSString屬性的路徑果善,xx.xx形式诊笤。
valueForUndefinedKey它的默認(rèn)實(shí)現(xiàn)是拋出異常,可以重寫這個(gè)函數(shù)做錯(cuò)誤處理巾陕。
修改值
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setNilValueForKey:當(dāng)對(duì)非類對(duì)象屬性設(shè)置nil時(shí)讨跟,調(diào)用,默認(rèn)拋出異 常鄙煤。
一對(duì)多關(guān)系成員的情況
mutableArrayValueForKey:有序一對(duì)多關(guān)系成員 NSArray
mutableSetValueForKey:無序一對(duì)多關(guān)系成員 NSSet
補(bǔ)充:KVO與Notification之間的區(qū)別:
notification是需要一個(gè)發(fā)送notification的對(duì)象晾匠,一般是notificationCenter,來通知觀察者梯刚。
KVO是直接通知到觀察對(duì)象凉馆,并且邏輯非常清晰,實(shí)現(xiàn)步驟簡(jiǎn)單乾巧。
- 什么是KVO和KVC?
答:KVC:鍵值編碼是一種間接訪問對(duì)象的屬性使用字符串來標(biāo)識(shí)屬性句喜,而不是通過調(diào)用存取方法,直接或通過實(shí)例變量訪問的機(jī)制沟于。
KVO:鍵值觀察機(jī)制咳胃,他提供了觀察某一屬性變化的方法,極大的簡(jiǎn)化了代碼旷太。
比如我自定義的一個(gè)button
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];
pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];
pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
對(duì)于系統(tǒng)是根據(jù)keyPath去取的到相應(yīng)的值發(fā)生改變展懈,理論上來說是和kvc機(jī)制的道理是一樣的。
對(duì)于kvc機(jī)制如何通過key尋找到value:
“當(dāng)通過KVC調(diào)用對(duì)象時(shí)供璧,比如:[self valueForKey:@”someKey”]時(shí)存崖,程序會(huì)自動(dòng)試圖通過幾種不同的方式解析這個(gè)調(diào)用。首先查找對(duì)象是否帶有 someKey 這個(gè)方法睡毒,如果沒找到来惧,會(huì)繼續(xù)查找對(duì)象是否帶有someKey這個(gè)實(shí)例變量(iVar),如果還沒有找到演顾,程序會(huì)繼續(xù)試圖調(diào)用 -(id) valueForUndefinedKey:這個(gè)方法供搀。如果這個(gè)方法還是沒有被實(shí)現(xiàn)的話,程序會(huì)拋出一個(gè)NSUndefinedKeyException異常錯(cuò)誤钠至。
(注意:Key-Value Coding查找方法的時(shí)候葛虐,不僅僅會(huì)查找someKey這個(gè)方法,還會(huì)查找getsomeKey這個(gè)方法棉钧,前面加一個(gè)get屿脐,或者_(dá)someKey以及_getsomeKey這幾種形式。同時(shí),查找實(shí)例變量的時(shí)候也會(huì)不僅僅查找someKey這個(gè)變量的诵,也會(huì)查找_someKey這個(gè)變量是否存在万栅。)
設(shè)計(jì)valueForUndefinedKey:方法的主要目的是當(dāng)你使用-(id)valueForKey方法從對(duì)象中請(qǐng)求值時(shí),對(duì)象能夠在錯(cuò)誤發(fā)生前奢驯,有最后的機(jī)會(huì)響應(yīng)這個(gè)請(qǐng)求申钩。
3.KVC和KVO
1> 如何調(diào)用私有變量 如何修改系統(tǒng)的只讀屬性 KVC的查找順序
KVC在某種程度上提供了訪問器的替代方案。不過訪問器方法是一個(gè)很好的東西瘪阁,以至于只要是有可能撒遣,KVC也盡量再訪問器方法的幫助下工作。為了設(shè)置或者返回對(duì)象屬性管跺,KVC按順序使用如下技術(shù):
①檢查是否存在-<key>义黎、-is<key>(只針對(duì)布爾值有效)或者-get<key>的訪問器方法,如果有可能豁跑,就是用這些方法返回值廉涕;
檢查是否存在名為-set<key>:的方法,并使用它做設(shè)置值艇拍。對(duì)于 -get<key>和 -set<key>:方法狐蜕,將大寫Key字符串的第一個(gè)字母,并與Cocoa的方法命名保持一致卸夕;
②如果上述方法不可用层释,則檢查名為-_<key>、-_is<key>(只針對(duì)布爾值有效)快集、-_get<key>和-set<key>:方法贡羔;
③如果沒有找到訪問器方法,可以嘗試直接訪問實(shí)例變量个初。實(shí)例變量可以是名為:<key>或<key>;
④如果仍為找到乖寒,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法。這些方法的默認(rèn)實(shí)現(xiàn)都是拋出異常院溺,我們可以根據(jù)需要重寫它們楣嘁。
2> 什么是鍵-值,鍵路徑是什么
模型的性質(zhì)是通過一個(gè)簡(jiǎn)單的鍵(通常是個(gè)字符串)來指定的。視圖和控制器通過鍵來查找相應(yīng)的屬性值珍逸。在一個(gè)給定的實(shí)體中逐虚,同一個(gè)屬性的所有值具有相同的數(shù)據(jù)類型。鍵-值編碼技術(shù)用于進(jìn)行這樣的查找—它是一種間接訪問對(duì)象屬性的機(jī)制弄息。
鍵路徑是一個(gè)由用點(diǎn)作分隔符的鍵組成的字符串痊班,用于指定一個(gè)連接在一起的對(duì)象性質(zhì)序列勤婚。第一個(gè)鍵的性質(zhì)是由先前的性質(zhì)決定的摹量,接下來每個(gè)鍵的值也是相對(duì)于其前面的性質(zhì)。鍵路徑使您可以以獨(dú)立于模型實(shí)現(xiàn)的方式指定相關(guān)對(duì)象的性質(zhì)。通過鍵路徑缨称,您可以指定對(duì)象圖中的一
個(gè)任意深度的路徑凝果,使其指向相關(guān)對(duì)象的特定屬性。
3> 什么是KVC
3> 什么是KVO
4> kvo的實(shí)現(xiàn)機(jī)制
當(dāng)某個(gè)類的對(duì)象第一次被觀察時(shí)睦尽,系統(tǒng)就會(huì)在運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建該類的一個(gè)派生類器净,在這個(gè)派生類中重寫原類中被觀察屬性的setter方法,派生類在被重寫的setter方法實(shí)現(xiàn)真正的通知機(jī)制(Person->NSKVONotifying_Person).
派生類重寫了 class 方法以“欺騙”外部調(diào)用者它就是起初的那個(gè)類。然后系統(tǒng)將這個(gè)對(duì)象的isa指針指向這個(gè)新誕生的派生類当凡,因此這個(gè)對(duì)象就成為該派生類的對(duì)象了山害,因而在該對(duì)象上對(duì)setter的調(diào)用就會(huì)調(diào)用重寫的setter,從而激活鍵值通知機(jī)制沿量。此外浪慌,派生類還重寫了dealloc方法來釋放資源。
5> KVO計(jì)算屬性 設(shè)置依賴鍵
監(jiān)聽的某個(gè)屬性可能會(huì)依賴于其它多個(gè)屬性的變化(類似于swift朴则,可以稱之為計(jì)算屬性)权纤,不管所依賴的哪個(gè)屬性發(fā)生了變化,都會(huì)導(dǎo)致計(jì)算屬性的變化,此時(shí)該屬性如果不能通過set方法來監(jiān)聽(如get中進(jìn)行計(jì)算
-
(NSString *)accountForBank {
return [NSString stringWithFormat:@“%@ for %@", self.accountName, self.bankCodeEn];
}
),則可以設(shè)置依賴鍵,兩種方法:
1>
-
(NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:@"accountForBank"]) {
keyPaths = [keyPaths setByAddingObjectsFromArray:@[@"accountName", @"bankCodeEn"]];
}
return keyPaths;
}
2> -
(NSSet *)keyPathsForValuesAffectingAccountForBank {
return [NSSet setWithObjects:@"accountBalance", @"bankCodeEn", nil];
}
6> KVO集合屬性
可對(duì)可變集合的元素改變進(jìn)行監(jiān)聽(如添加乌妒、刪除和替換元素),使用集合監(jiān)聽對(duì)象
使用KVO
重寫class
5> kvo使用場(chǎng)景
①實(shí)現(xiàn)上下拉刷新控件 contentoffset
②webview混合排版 contentsize
③監(jiān)聽模型屬性實(shí)時(shí)更新UI
1汹想、SDWebImage(SDWebImage的實(shí)現(xiàn)機(jī)制)
主要功能:
提供UIImageView的一個(gè)分類,以支持網(wǎng)絡(luò)圖片的加載與緩存管理
一個(gè)異步的圖片加載器
一個(gè)異步的內(nèi)存+磁盤圖片緩存
支持GIF圖片
支持WebP圖片
后臺(tái)圖片解壓縮處理
確保同一個(gè)URL的圖片不被下載多次
確保虛假的URL不會(huì)被反復(fù)加載
確保下載及緩存時(shí)撤蚊,主線程不被阻塞
SDWebImage下載的核心其實(shí)就是利用NSURLConnection對(duì)象來加載數(shù)據(jù)古掏。每個(gè)圖片的下載都由一個(gè)Operation操作來完成,并將這些操作放到一個(gè)操作隊(duì)列中拴魄。這樣可以實(shí)現(xiàn)圖片的并發(fā)下載冗茸。
緩存
為了減少網(wǎng)絡(luò)流量的消耗,我們都希望下載下來的圖片緩存到本地匹中,下次再去獲取同一張圖片時(shí)夏漱,可以直接從本地獲取,而不再從遠(yuǎn)程服務(wù)器獲取顶捷。這樣做的另一個(gè)好處是提升了用戶體驗(yàn)挂绰,用戶第二次查看同一幅圖片時(shí),能快速從本地獲取圖片直接呈現(xiàn)給用戶服赎。
SDWebImage提供了對(duì)圖片緩存的支持拨齐,而該功能是由SDImageCache類來完成的。該類負(fù)責(zé)處理內(nèi)存緩存及一個(gè)可選的磁盤緩存辞槐。其中磁盤緩存的寫操作是異步的廷支,這樣就不會(huì)對(duì)UI操作造成影響。
內(nèi)存緩存與磁盤緩存
內(nèi)存緩存的處理是使用NSCache對(duì)象來實(shí)現(xiàn)的缺厉。NSCache是一個(gè)類似于集合的容器永高。它存儲(chǔ)key-value對(duì)隧土,這一點(diǎn)類似于NSDictionary類。我們通常用使用緩存來臨時(shí)存儲(chǔ)短時(shí)間使用但創(chuàng)建昂貴的對(duì)象命爬。重用這些對(duì)象可以優(yōu)化性能曹傀,因?yàn)樗鼈兊闹挡恍枰匦掠?jì)算。另外一方面饲宛,這些對(duì)象對(duì)于程序來說不是緊要的皆愉,在內(nèi)存緊張時(shí)會(huì)被丟棄。
磁盤緩存的處理則是使用NSFileManager對(duì)象來實(shí)現(xiàn)的艇抠。圖片存儲(chǔ)的位置是位于Cache文件夾幕庐。另外,SDImageCache還定義了一個(gè)串行隊(duì)列家淤,來異步存儲(chǔ)圖片翔脱。
SDImageCache提供了大量方法來緩存、獲取媒鼓、移除及清空?qǐng)D片届吁。而對(duì)于每個(gè)圖片,為了方便地在內(nèi)存或磁盤中對(duì)它進(jìn)行這些操作绿鸣,我們需要一個(gè)key值來索引它疚沐。在內(nèi)存中,我們將其作為NSCache的key值潮模,而在磁盤中亮蛔,我們用這個(gè)key作為圖片的文件名。對(duì)于一個(gè)遠(yuǎn)程服務(wù)器下載的圖片擎厢,其url是作為這個(gè)key的最佳選擇了究流。我們?cè)诤竺鏁?huì)看到這個(gè)key值的重要性。
SDWebImage的主要任務(wù)就是圖片的下載和緩存动遭。為了支持這些操作芬探,
它主要使用了以下知識(shí)點(diǎn):
dispatch_barrier_sync函數(shù):該方法用于對(duì)操作設(shè)置屏幕,確保在執(zhí)行完任務(wù)后才會(huì)執(zhí)行后續(xù)操作厘惦。該方法常用于確保類的線程安全性操作偷仿。
NSMutableURLRequest:用于創(chuàng)建一個(gè)網(wǎng)絡(luò)請(qǐng)求對(duì)象,我們可以根據(jù)需要來配置請(qǐng)求報(bào)頭等信息宵蕉。
NSOperation及NSOperationQueue:操作隊(duì)列是Objective-C中一種高級(jí)的并發(fā)處理方法酝静,現(xiàn)在它是基于GCD來實(shí)現(xiàn)的。相對(duì)于GCD來說羡玛,操作隊(duì)列的優(yōu)點(diǎn)是可以取消在任務(wù)處理隊(duì)列中的任務(wù)别智,另外在管理操作間的依賴關(guān)系方面也容易一些。對(duì)SDWebImage中我們就看到了如何使用依賴將下載順序設(shè)置成后進(jìn)先出的順序稼稿。
NSURLConnection:用于網(wǎng)絡(luò)請(qǐng)求及響應(yīng)處理薄榛。在iOS7.0后浓若,蘋果推出了一套新的網(wǎng)絡(luò)請(qǐng)求接口,即NSURLSession類蛇数。
開啟一個(gè)后臺(tái)任務(wù)。
NSCache類:一個(gè)類似于集合的容器是越。它存儲(chǔ)key-value對(duì)耳舅,這一點(diǎn)類似于NSDictionary類。我們通常用使用緩存來臨時(shí)存儲(chǔ)短時(shí)間使用但創(chuàng)建昂貴的對(duì)象倚评。重用這些對(duì)象可以優(yōu)化性能浦徊,因?yàn)樗鼈兊闹挡恍枰匦掠?jì)算。另外一方面天梧,這些對(duì)象對(duì)于程序來說不是緊要的盔性,在內(nèi)存緊張時(shí)會(huì)被丟棄。
清理緩存圖片的策略:特別是最大緩存空間大小的設(shè)置呢岗。如果所有緩存文件的總大小超過這一大小冕香,則會(huì)按照文件最后修改時(shí)間的逆序,以每次一半的遞歸來移除那些過早的文件后豫,直到緩存的實(shí)際大小小于我們?cè)O(shè)置的最大使用空間悉尾。
對(duì)圖片的解壓縮操作:這一操作可以查看SDWebImageDecoder.m中+decodedImageWithImage方法的實(shí)現(xiàn)。
對(duì)GIF圖片的處理
對(duì)WebP圖片的處理
圖片下載-->顯示:
異步下載: NSOperation + 操作隊(duì)列
業(yè)務(wù)邏輯: 圖片緩存(防止圖片錯(cuò)位,提升效率) + 操作緩存(防止重復(fù)創(chuàng)建操作) + 沙盒緩存(磁盤緩存)
業(yè)務(wù)拆分: 不同的功能寫在不同的類中.高層次的封裝.
要求:一句話自動(dòng)實(shí)現(xiàn)異步圖片的下載并且顯示圖片. 沙盒緩存(磁盤緩存)
一句話代碼的接口: UIImageView 的一個(gè)分類.這個(gè)分類專門負(fù)責(zé)提供一句話代碼的接口.
異步圖片下載: 自定義的操作.專門負(fù)責(zé)下載圖片
顯示圖片: 管理工具類.負(fù)責(zé)將圖片下載和圖片顯示聯(lián)系起來(業(yè)務(wù)功能邏輯由它實(shí)現(xiàn)(協(xié)調(diào))). 圖片緩存+操作緩存
沙盒緩存: 自定義的沙盒緩存工具類.專門負(fù)責(zé)沙盒中圖片的讀和寫.
// 解決圖片錯(cuò)位問題,需要判定 cell 對(duì)應(yīng)的圖片地址已經(jīng)改變!
給每一個(gè)imageView 都綁定一個(gè)下載地址. 如果外界傳入的下載地址改變, 讓 iamgeView 綁定的地址變成新的地址,原來的下載操作取消.開始新的下載操作.
// 如何給 imageView 綁定下載地址:利用運(yùn)行時(shí),在分類中動(dòng)態(tài)的為 imageView 添加一個(gè)屬性(urlString).
框架 SDWebimage的緩存機(jī)制
? UIImageView+WebCache: setImageWithURL:placeholderImage:options: 先顯示 placeholderImage 挫酿,同時(shí)由SDWebImageManager 根據(jù) URL 來在本地查找圖片构眯。
? SDWebImageManager: downloadWithURL:delegate:options:userInfo: SDWebImageManager是將UIImageView+WebCache同SDImageCache鏈接起來的類, SDImageCache: queryDiskCacheForKey:delegate:userInfo:用來從緩存根據(jù)CacheKey查找圖片是否已經(jīng)在緩存中
? 如果內(nèi)存中已經(jīng)有圖片緩存早龟, SDWebImageManager會(huì)回調(diào)SDImageCacheDelegate : imageCache:didFindImage:forKey:userInfo:
? 而 UIImageView+WebCache 則回調(diào)SDWebImageManagerDelegate: webImageManager:didFinishWithImage:來顯示圖片惫霸。
? 如果內(nèi)存中沒有圖片緩存,那么生成 NSInvocationOperation 添加到隊(duì)列葱弟,從硬盤查找圖片是否已被下載緩存壹店。
? 根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在 NSOperation 進(jìn)行的操作芝加,所以回主線程進(jìn)行結(jié)果回調(diào)
? notifyDelegate:
? 如果上一操作從硬盤讀取到了圖片茫打,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過小,會(huì)先清空內(nèi)存緩存)妖混。SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:進(jìn)而回調(diào)展示圖片老赤。
? 如果從硬盤緩存目錄讀取不到圖片,說明所有緩存都不存在該圖片制市,需要下載圖片抬旺,回調(diào)
? imageCache:didNotFindImageForKey:userInfo:
? 共享或重新生成一個(gè)下載器 SDWebImageDownloader 開始下載圖片。
? 圖片下載由 NSURLConnection 來做祥楣,實(shí)現(xiàn)相關(guān) delegate 來判斷圖片下載中开财、下載完成和下載失敗汉柒。
? connection:didReceiveData: 中利用 ImageIO 做了按圖片下載進(jìn)度加載效果。
? connectionDidFinishLoading: 數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理责鳍。
? 圖片解碼處理在一個(gè) NSOperationQueue 完成碾褂,不會(huì)拖慢主線程 UI。如果有需要對(duì)下載的圖片進(jìn)行二次處理历葛,最好也在這里完成正塌,效率會(huì)好很多。
? 在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成恤溶,imageDecoder:didFinishDecodingImage:userInfo: 回調(diào)給 SDWebImageDownloader乓诽。
? imageDownloader:didFinishWithImage: 回調(diào)給 SDWebImageManager 告知圖片下載完成。
? 通知所有的 downloadDelegates 下載完成咒程,回調(diào)給需要的地方展示圖片鸠天。
? 將圖片保存到 SDImageCache 中,內(nèi)存緩存和硬盤緩存同時(shí)保存帐姻。
? 寫文件到硬盤在單獨(dú) NSInvocationOperation 中完成稠集,避免拖慢主線程。
? 如果是在iOS上運(yùn)行饥瓷,SDImageCache 在初始化的時(shí)候會(huì)注冊(cè)notification 到 UIApplicationDidReceiveMemoryWarningNotification 以及 UIApplicationWillTerminateNotification,在內(nèi)存警告的時(shí)候清理內(nèi)存圖片緩存巍杈,應(yīng)用結(jié)束的時(shí)候清理過期圖片。
? SDWebImagePrefetcher 可以預(yù)先下載圖片扛伍,方便后續(xù)使用筷畦。
位運(yùn)算
NSCache
特點(diǎn): a> 線程安全的 b> 當(dāng)內(nèi)存不足的時(shí)候,自動(dòng)釋放 c> 緩存數(shù)量和緩存成本
區(qū)別NSMutableDictionary
? 不能也不應(yīng)該遍歷 2> NSCache對(duì)key強(qiáng)引用,NSMutableDictionary對(duì)key進(jìn)行copy
二、網(wǎng)絡(luò)安全
問題: 用戶密碼不能以明文的形式保存,需要對(duì)用戶密碼加密之后再保存!
密碼的安全原則:
1> 本地和服務(wù)器都不允許保存用戶的密碼明文.
? 在網(wǎng)絡(luò)上,不允許傳輸用戶的密碼明文.
? <4> 數(shù)據(jù)加密算法:
1>對(duì)稱加密:
1.加密刺洒、解密使用相同的密鑰和算法鳖宾。
2.最快速簡(jiǎn)單的加密方式。
3.算法公開逆航。
4.通常使用小于256bit的密鑰鼎文。密鑰越大安全性越強(qiáng),但加密和解密的過程越慢因俐。適合大數(shù)據(jù)加密拇惋。常用的有AES、DES抹剩、IDEA撑帖。
2> 非對(duì)稱加密算法:
1.加密、解密使用相同的密鑰和算法澳眷。
2.最快速簡(jiǎn)單的加密方式胡嘿。
3.算法公開。
4.通常使用小于256bit的密鑰钳踊。密鑰越大安全性越強(qiáng)衷敌,但加密和解密
加密綜合方案:解決的辦法是將對(duì)稱加密的密鑰使用非對(duì)稱加密的公鑰進(jìn)行加密勿侯,然后發(fā)送出去,接收方使用私鑰進(jìn)行解密得到對(duì)稱加密的密鑰缴罗,然后雙方可以使用對(duì)稱加密來進(jìn)行溝通助琐。
openssl :是一個(gè)強(qiáng)大的安全套接字層密碼庫,囊括主要的密碼算法,常用的密鑰和證書封裝管理功能以及 SSL (Secure socket Laye)協(xié)議.提供豐富的應(yīng)用程序測(cè)試功能
終端命令:
echo hello |openssl md5
echo hello |openssl sha1
echo hello |openssl sha -sha256
echo hello |openssl sha -sha512
}
/--------------------------- 04 信息安全加 -----------------------------/
了解:常用加密方法: 1> base64 2> MD5 3> MD5加鹽 4> HMAC 5> 時(shí)間戳密碼(用戶密碼動(dòng)態(tài)變化)
{
1> base64
{
base64 編碼是現(xiàn)代密碼學(xué)的基礎(chǔ)
原本是 8個(gè)bit 一組表示數(shù)據(jù),改為 6個(gè)bit一組表示數(shù)據(jù),不足的部分補(bǔ)零,每 兩個(gè)0 用 一個(gè) = 表示.
用base64 編碼之后,數(shù)據(jù)長(zhǎng)度會(huì)變大,增加了大約 1/3 左右.
base64 基本能夠達(dá)到安全要求,但是,base64能夠逆運(yùn)算,非常不安全!
base64 編碼有個(gè)非常顯著的特點(diǎn),末尾有個(gè) '=' 號(hào).
利用終端命令進(jìn)行base64運(yùn)算:
// 將文件 meinv.jpg 進(jìn)行 base64運(yùn)算之后存儲(chǔ)為 meinv.txt
base64 meinv.jpg -o meinv.txt
// 講meinv.txt 解碼生成 meinv.png
base64 -D meinv.txt -o meinv.png
// 將字符串 "hello" 進(jìn)行 base 64 編碼 結(jié)果:aGVsbG8=
echo "hello" | base64
// 將 base64編碼之后的結(jié)果 aGVsbG8= 反編碼為字符串
echo aGVsbG8= | base64 -D
}
2> MD5 -- (信息-摘要算法) 哈希算法之一.
{
把一個(gè)任意長(zhǎng)度的字節(jié)串變換成一定長(zhǎng)度的十六進(jìn)制的大整數(shù). 注意,字符串的轉(zhuǎn)換過程是不可逆的.
用于確保'信息傳輸'完整一致.
MD5特點(diǎn):
*1.壓縮性: 任意長(zhǎng)度的數(shù)據(jù),算出的 MD5 值長(zhǎng)度都是固定的.
*2.容易計(jì)算: 從原數(shù)據(jù)計(jì)算出 MD5 值很容易.
*3.抗修改性: 對(duì)原數(shù)據(jù)進(jìn)行任何改動(dòng),哪怕只修改一個(gè)字節(jié),所得到的 MD5 值都有很大區(qū)別.
*4.弱抗碰撞: 已知原數(shù)據(jù)和其 MD5 值,想找到一個(gè)具有相同 MD5 值的數(shù)據(jù)(即偽造數(shù)據(jù))是非常困難的.
*5.強(qiáng)抗碰撞: 想找到兩個(gè)不同數(shù)據(jù),使他們具有相同的 MD5 值,是非常困難的.
MD5 應(yīng)用:
*1. 一致性驗(yàn)證: MD5 將整個(gè)文件當(dāng)做一個(gè)大文本信息,通過不可逆的字符串變換算法,產(chǎn)生一個(gè)唯一的 MD5 信息摘要.就像每個(gè)人都有自己獨(dú)一無二的指紋,MD5 對(duì)任何文件產(chǎn)生一個(gè)獨(dú)一無二的"數(shù)字指紋".
利用 MD5 來進(jìn)行文件校驗(yàn), 被大量應(yīng)用在軟件下載站,論壇數(shù)據(jù)庫,系統(tǒng)文件安全等方面.
*2. 數(shù)字簽名;
*3. 安全訪問認(rèn)證
}
3> MD5加鹽
{
MD5 本身是不可逆運(yùn)算,但是,目前網(wǎng)絡(luò)上有很多數(shù)據(jù)庫支持反查詢.
MD5加鹽 就是在密碼哈希過程中添加的額外的隨機(jī)值.
注意:加鹽要足夠長(zhǎng),足夠復(fù)雜.
}
4> HMAC(Message Authentication Code,消息認(rèn)證碼算法)
{
HMAC 利用哈希算法,以一個(gè)密鑰和一個(gè)消息為輸入,生成一個(gè)消息摘要作為輸出.
HMAC 主要使用在身份認(rèn)證中;
認(rèn)證流程:
*1. 客戶端向服務(wù)器發(fā)送一個(gè)請(qǐng)求.
*2. 服務(wù)器接收到請(qǐng)求后,生成一個(gè)'隨機(jī)數(shù)'并通過網(wǎng)絡(luò)傳輸給客戶端.
*3. 客戶端將接收到的'隨機(jī)數(shù)'和'密鑰'進(jìn)行 HMAC-MD5 運(yùn)算,將得到的結(jié)構(gòu)作為認(rèn)證數(shù)據(jù)傳遞給服務(wù)器.
(實(shí)際是將隨機(jī)數(shù)提供給 ePass,密鑰也是存儲(chǔ)在 ePass中的)
*4. 與此同時(shí),服務(wù)器也使用該'隨機(jī)數(shù)'與存儲(chǔ)在服務(wù)器數(shù)據(jù)庫中的該客戶'密鑰'進(jìn)行 HMAC-MD5 運(yùn)算,如果
服務(wù)器的運(yùn)算結(jié)果與客戶端傳回的認(rèn)證數(shù)據(jù)相同,則認(rèn)為客戶端是一個(gè)合法用法.
}
5> 時(shí)間戳密碼(用戶密碼動(dòng)態(tài)變化)
{
相同的密碼明文 + 相同的加密算法 ===》 每次計(jì)算都得出不同的結(jié)果.可以充分保證密碼的安全性.
原理:將當(dāng)前時(shí)間加入到密碼中;
因?yàn)槊看蔚顷憰r(shí)間都不同,所以每次計(jì)算出的結(jié)果也都不相同.
服務(wù)器也需要采用相同的算法.這就需要服務(wù)器和客戶端時(shí)間一致.
注意:服務(wù)器端時(shí)間和客戶端時(shí)間,可以有一分鐘的誤差(比如:第59S發(fā)送的網(wǎng)絡(luò)請(qǐng)求,一秒鐘后服務(wù)器收到并作出響應(yīng),這時(shí)服務(wù)器當(dāng)前時(shí)間比客戶端發(fā)送時(shí)間晚一分鐘)
這就意味著,服務(wù)器需要計(jì)算兩次(當(dāng)前時(shí)間和一分鐘之前兩個(gè)時(shí)間點(diǎn)各計(jì)算一次).只要有一個(gè)結(jié)果是正確的,就可以驗(yàn)證成功
}
// IP輔助/手機(jī)綁定..
}
/-------------------------------------- 05 鑰匙串訪問 -------------------------------------/
重點(diǎn): 1.鑰匙串訪問
{
蘋果在 iOS 7.0.3 版本以后公布鑰匙串訪問的SDK. 鑰匙串訪問接口是純C語言的.
鑰匙串使用 AES 256加密算法,能夠保證用戶密碼的安全.
鑰匙串訪問的第三方框架(SSKeychain),是對(duì) C語言框架 的封裝.注意:不需要看源碼.
鑰匙串訪問的密碼保存在哪里?只有蘋果才知道.這樣進(jìn)一步保障了用戶的密碼安全.
使用步驟:
{
// 獲取應(yīng)用程序唯一標(biāo)識(shí).
NSString *bundleId = [NSBundle mainBundle].bundleIdentifier
// 1.利用第三方框架,將用戶密碼保存在鑰匙串
[SSKeychain setPassword:self.pwdText.text forService:bundleId account:self.usernameText.text];
"注意"三個(gè)參數(shù):
1.密碼:可以直接使用明文.鑰匙串訪問本身是使用 AES 256加密,就是安全的.所以使用的時(shí)候,直接傳遞密碼明文就可以了.
2.服務(wù)名:可以隨便亂寫,建議唯一! 建議使用 bundleId
bundleId是應(yīng)用程序的唯一標(biāo)識(shí),每一個(gè)上架的應(yīng)用程序都有一個(gè)唯一的 bundleId
3.賬戶名:直接用用戶名稱就可以.
// 2.從鑰匙串加載密碼
self.pwdText.text = [SSKeychain passwordForService:bundleId account:self.usernameText.text];
}
}
HMAC_SHA1是一種安全的基于加密hash函數(shù)和共享密鑰的消息認(rèn)證協(xié)議面氓。它可以有效地防止數(shù)據(jù)在傳輸過程中被截獲和篡改兵钮,維護(hù)數(shù)據(jù)的完整性、可靠性和安全性侧但。HMAC_SHA1消息認(rèn)證機(jī)制的成功在于一個(gè)加密的hash函數(shù)、一個(gè)加密的隨機(jī)密鑰和一個(gè)安全的密鑰交換機(jī)制。
- 在原始URL 里加入一個(gè)名稱為 e 的時(shí)間戳參數(shù),避免緩存而得到舊的數(shù)據(jù)术徊;
- 分解請(qǐng)求的URL心包,從中取出 path 部分和 query_string 部分;
- 將 query_string 中的參數(shù)按名稱排序滴须,然后按順序用 = 和 & 連接成新的 query_string ;
4 用字符串拼接的方式組裝 path 和 query_string,兩者之間以 ? 連接成新的 URL趾娃; - 用HMAC_SHA1算法生成摘要 digest ,其中第一個(gè)參數(shù) SECRET_KEY 為私鑰缔御,第二個(gè)參數(shù)是已拼接的字符串 URL抬闷;
- 對(duì) digest 進(jìn)行base64編碼;
7 對(duì)base64編碼后的 digest 進(jìn)行URL安全處理耕突,即將其中的 / 替換為 _笤成,將 + 替換為 -;
8 用 ACCESS_KEY 明文與編碼后的 digest 進(jìn)行拼接眷茁,中間使用冒號(hào) : 連接炕泳,得到最終的的 access_token;
(1)在原始URL里面加入時(shí)間戳參數(shù)上祈,請(qǐng)求url,取出path和query_string
(2)將query_string中的參數(shù)按名稱排序培遵,然后連接成新的query_string
(3)拼接path和query_string,生成新的url
(4)用HMAC_SHA1算法生成摘要
(5)對(duì)摘要進(jìn)行base64
(6)對(duì)base64后的url進(jìn)行安全處理
(7)用ACCESS_KEY 明文與編碼后的摘要進(jìn)行拼接登刺,得到access_token值
λ ACCESS_KEY和SECRET_KEY 的值
ACCESS_KEY = "D39690AAB8AF914630E99150C2891F55B3BFBDA3"
SECRET_KEY = "99197B09707944D9E8C458CF707E19A1BB05FDB8"
λ 原始URL
http://111.4.115.170:9011/api?method=study-list
λ 加入時(shí)間戳參數(shù)后
http://111.4.115.170:9011/api?method=study-list&e=1421317725
λ 參數(shù)排序后
http://localhost:9000/api?cardNo=2013110000000001&e=1411117759&method=query-card
λ HMAC_SHA1簽名(摘要 → base64編碼 → URL安全處理)
D39690AAB8AF914630E99150C2891F55B3BFBDA3:kNHMOygciCLd_6ZaQxjOHf-dhj4=
λ 最終拼接完成的URL
http://111.4.115.170:9011/api?method=study-list&e=1421317725&token=D39690AAB8AF914630E99150C2891F55B3BFBDA3:kNHMOygciCLd_6ZaQxjOHf-dhj4=
3籽腕、多線程
? 多線程的概念:
是同步完成多項(xiàng)任務(wù),提高了資源的使用效率纸俭,多核的CPU運(yùn)算多線程更為出色;在iOS應(yīng)用中节仿,對(duì)多線程最初的理解,就是并發(fā)掉蔬。通過Cocoa的封裝廊宪,可以讓我們更為方便的使用線程矾瘾,做過C++的同學(xué)可能會(huì)對(duì)線程有更多的理解,比如線程的創(chuàng)立箭启,信號(hào)量壕翩、共享變量有認(rèn)識(shí),Cocoa框架下會(huì)方便很多傅寡,它對(duì)線程做了封裝放妈,有些封裝,可以讓我們創(chuàng)建的對(duì)象荐操,本身便擁有線程芜抒,也就是線程的對(duì)象化抽象,從而減少我們的工程托启,提供程序的健壯性宅倒。
1>多線程的作用:1.實(shí)現(xiàn)負(fù)載均衡問題,提高cpu利用率屯耸。
2>使用場(chǎng)景: 數(shù)據(jù)請(qǐng)求框架中AFN拐迁、多張圖片上傳前要多需要對(duì)圖片壓縮、文件下載疗绣、文件讀寫线召、視屏圖像的采集、處理多矮、顯示缓淹、保存等耗時(shí)操作的地方。通知塔逃、Timer和異步函數(shù)等都有使用多線程割卖。
3> NSOperationQueue和GCD的區(qū)別是什么
GCD(Grand Central Dispatch)是底層的C語言構(gòu)成的API,而NSOperationQueue及相關(guān)對(duì)象是Objc的對(duì)象患雏。在GCD中,在隊(duì)列中執(zhí)行的是由block構(gòu)成的任務(wù)鹏溯,這是一個(gè)輕量級(jí)的數(shù)據(jù)結(jié)構(gòu);NSOperation是一個(gè)抽象類淹仑,它封裝了線程的細(xì)節(jié)實(shí)現(xiàn)丙挽,我們可以通過子類化該對(duì)象,加上NSQueue來同面向?qū)ο蟮乃季S匀借,管理多線程程序颜阐。而Operation為我們提供了更多的選擇;
2.在NSOperationQueue中吓肋,我們可以隨時(shí)取消已經(jīng)設(shè)定要準(zhǔn)備執(zhí)行的任務(wù)(當(dāng)然凳怨,已經(jīng)開始的任務(wù)就無法阻止了),而GCD沒法停止已經(jīng)加入queue的block(其實(shí)是有的,但需要許多復(fù)雜的代碼)肤舞;
3.NSOperation能夠方便地設(shè)置依賴關(guān)系紫新,我們可以讓一個(gè)Operation依賴于另一個(gè)Operation,這樣的話盡管兩個(gè)Operation處于同一個(gè)并行隊(duì)列中李剖,但前者會(huì)直到后者執(zhí)行完畢后再執(zhí)行芒率;
4.我們能將KVO應(yīng)用在NSOperation中,可以監(jiān)聽一個(gè)Operation是否完成或取消篙顺,這樣子能比GCD更加有效地掌控我們執(zhí)行的后臺(tái)任務(wù)偶芍;
5.在NSOperation中,我們能夠設(shè)置NSOperation的priority優(yōu)先級(jí)德玫,能夠使同一個(gè)并行隊(duì)列中的任務(wù)區(qū)分先后地執(zhí)行匪蟀,而在GCD中,我們只能區(qū)分不同任務(wù)隊(duì)列的優(yōu)先級(jí)宰僧,如果要區(qū)分block任務(wù)的優(yōu)先級(jí)材彪,也需要大量的復(fù)雜代碼;
6.我們能夠?qū)SOperation進(jìn)行繼承撒桨,在這之上添加成員變量與成員方法查刻,提高整個(gè)代碼的復(fù)用度键兜,這比簡(jiǎn)單地將block任務(wù)排入執(zhí)行隊(duì)列更有自由度凤类,能夠在其之上添加更多自定制的功能。
7.GCD 是嚴(yán)格的隊(duì)列普气,先進(jìn)先出FIFO谜疤;NSOperation可以改動(dòng) 優(yōu)先級(jí)(或者說服務(wù)質(zhì)量)改變執(zhí)行順序
8.NSOperation的高級(jí):最大并發(fā)數(shù),控制線程個(gè)數(shù)现诀,優(yōu)化了線程的暫停夷磕、繼續(xù)、取消功能(GCD實(shí)現(xiàn)起來太難仔沿,可以用 KVO )坐桩,依賴關(guān)系,可以讓異步任務(wù)同步執(zhí)行.
2封锉、GCD與NSThread的區(qū)別:
1). NSThread 通過 @selector 指定要執(zhí)行的方法绵跷,代碼分散, 依靠的是NSObject的分類實(shí)現(xiàn)的線程之間的通訊,如果要開線程必須創(chuàng)建多個(gè)線程對(duì)象成福。經(jīng)常只用的是[NSTread current] 查看當(dāng)前的線程碾局。
NSThread是一個(gè)控制線程執(zhí)行的對(duì)象,它不如NSOperation抽象奴艾,通過它我們可以方便的得到一個(gè)線程净当,并控制它。但NSThread的線程之間的并發(fā)控制,是需要我們自己來控制的像啼,可以通過NSCondition實(shí)現(xiàn)俘闯。
2).GCD 通過 block 指定要執(zhí)行的代碼,代碼集中, 所有的代碼寫在一起的埋合,讓代碼更加簡(jiǎn)單备徐,易于閱讀和維護(hù),不需要管理線程的創(chuàng)建/銷毀/復(fù)用的過程!程序員不用關(guān)心線程的生命周期
3甚颂、進(jìn)程和線程的區(qū)別與聯(lián)系是什么?
進(jìn)程和線程都是由操作系統(tǒng)所體會(huì)的程序運(yùn)行的基本單元蜜猾,系統(tǒng)利用該基本單元實(shí)現(xiàn)系統(tǒng)對(duì)應(yīng)用的并發(fā)性
一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程:
進(jìn)程:擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享一塊內(nèi)存
線程:線程是指進(jìn)程內(nèi)的一個(gè)執(zhí)行單元振诬。
聯(lián)系:線程是進(jìn)程的基本組成單位
區(qū)別:(1)調(diào)度:線程作為調(diào)度和分配的基本單位蹭睡,進(jìn)程作為擁有資源的基本單位
(2)并發(fā)性:不僅進(jìn)程之間可以并發(fā)執(zhí)行,同一個(gè)進(jìn)程的多個(gè)線程之間也可并發(fā)執(zhí)行
(3)擁有資源:進(jìn)程是擁有系統(tǒng)資源(單獨(dú)的地址空間)赶么,線程不擁有系統(tǒng)資源肩豁,但可以訪問隸屬于進(jìn)程的資源.
(4)系統(tǒng)開銷:在創(chuàng)建或撤消進(jìn)程時(shí),系統(tǒng)都要為之分配和回收資源辫呻,導(dǎo)致系統(tǒng)的開銷明顯大于創(chuàng)建或撤消線程時(shí)的開銷清钥。一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉。所以多進(jìn)程的程序要比多線程的程序健壯放闺,但在進(jìn)程切換時(shí)祟昭,耗費(fèi)資源較大,效率要差一些怖侦。
(5)但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作篡悟,只能用線程,不能用進(jìn)程
4.分別異步執(zhí)行兩個(gè)耗時(shí)操作匾寝,等兩次耗時(shí)操作都執(zhí)行完畢后,再回到主線程執(zhí)行操作. 使用隊(duì)列組(dispatch_group_t)快速,高效的實(shí)現(xiàn)上述需求.
dispatch_group_t group = dispatch_group_create(); // 隊(duì)列組
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 全局并發(fā)隊(duì)列
dispatch_group_async(group, queue, ^{ // 異步執(zhí)行操作1
// longTime1
});
dispatch_group_async(group, queue, ^{ // 異步執(zhí)行操作2
// longTime2
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 在主線程刷新數(shù)據(jù)
// reload Data
});
}
實(shí)現(xiàn)方式
線程創(chuàng)建有三種方法:使用NSThread創(chuàng)建搬葬、使用GCD的dispatch、使用子類化的NSOperation,然后將其加入NSOperationQueue;
在主線程執(zhí)行代碼艳悔,方法是performSelectorOnMainThread急凰,
如果想延時(shí)執(zhí)行代碼可以用performSelector:onThread:withObject:waitUntilDone:
NSOperation queue是存放NSOperation的集合類。操作和操作隊(duì)列猜年,基本可以看成java中的線程和線程池的概念抡锈。
- 在項(xiàng)目什么時(shí)候選擇使用GCD,什么時(shí)候選擇NSOperation?
答: 項(xiàng)目中使用NSOperation的優(yōu)點(diǎn)是NSOperation是對(duì)線程的高度抽象码倦,在項(xiàng)目中使用它企孩,會(huì)使項(xiàng)目的程序結(jié)構(gòu)更好匣距,子類化NSOperation的設(shè)計(jì)思路衷恭,是具有面向?qū)ο蟮膬?yōu)點(diǎn)(復(fù)用、封裝)狮斗,使得實(shí)現(xiàn)是多線程支持,而接口簡(jiǎn)單补疑,建議在復(fù)雜項(xiàng)目中使用歧沪。
項(xiàng)目中使用GCD的優(yōu)點(diǎn)是GCD本身非常簡(jiǎn)單、易用莲组,對(duì)于不復(fù)雜的多線程操作诊胞,會(huì)節(jié)省代碼量,而Block參數(shù)的使用锹杈,會(huì)是代碼更為易讀撵孤,建議在簡(jiǎn)單項(xiàng)目中使用。
3> 對(duì)比iOS中的多線程技術(shù)
3.1> pthread
pthread跨平臺(tái),使用難度大,需要手動(dòng)管理線程生命周期
pthread_create創(chuàng)建線程,傳參線程標(biāo)記,線程屬性,初始函數(shù),函數(shù)參數(shù)
3.2> NSThread
NSThread需要手動(dòng)管理線程生命周期和
3.2> GCD僅僅支持FIFO隊(duì)列竭望,只可以設(shè)置隊(duì)列的優(yōu)先級(jí),而NSOperationQueue中的每一個(gè)任務(wù)都可以被重新設(shè)置優(yōu)先級(jí)(setQueuePriority:)邪码,從而實(shí)現(xiàn)不同操作的執(zhí)行順序調(diào)整
3.3> GCD不支持異步操作之間的依賴關(guān)系設(shè)置。如果某個(gè)操作的依賴另一個(gè)操作的數(shù)據(jù)咬清,使用NSOperationQueue能夠設(shè)置依賴按照正確的順序執(zhí)行操作(addDependency:)闭专。GCD則沒有內(nèi)建的依賴關(guān)系支持(只能通過Barrior和同步任務(wù)手動(dòng)實(shí)現(xiàn))。
3.4> NSOperationQueue方便停止隊(duì)列中的任務(wù)(cancelAllOperations, suspended),GCD不方便停止隊(duì)列中的任務(wù).
3.5> NSOperationQueue支持KVO旧烧,可以監(jiān)測(cè)operation是否正在執(zhí)行(isExecuted)影钉、是否結(jié)束(isFinished),是否取消(isCanceld)
3.6> GCD的執(zhí)行速度比NSOperationQueue快
3.7> NSOperationQueue可設(shè)置最大并發(fā)數(shù)量(節(jié)電),GCD具有dispatch_once(只執(zhí)行一次,單例)和dispatch_after(延遲執(zhí)行)功能
3.8> NSObject分類(perform)和NSThread遇到對(duì)象分配需要手動(dòng)內(nèi)存管理,手動(dòng)管理線程生命周期
3.10> NSObject分類線程通信
1> 多線程優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
使應(yīng)用程序的響應(yīng)速度更快,用戶界面在進(jìn)行其他工作的同時(shí)仍始終保持活動(dòng)狀態(tài);
優(yōu)化任務(wù)執(zhí)行,適當(dāng)提高資源利用率(cpu, 內(nèi)存);
缺點(diǎn):
線程占用內(nèi)存空間,管理線程需要額外的CPU開銷,開啟大量線程,降低程序性能;
增加程序復(fù)雜度,如線程間通信,多線程的資源共享等;
2> 在多線程中使用通知需要注意什么問題?
3> iOS中的延遲操作
1>[self performSelector:@selector(clearCache) withObject:nil afterDelay:duration];
1>2> dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{..});
2.利用NSOperation與NSOperationqueue處理多線程時(shí)掘剪,有3個(gè)NSOperation分別為A,B,C平委,要求A,B執(zhí)行完畢后,在執(zhí)行C杖小,如何做肆汹?
有三種實(shí)現(xiàn)方案
方案一:串行隊(duì)列同步執(zhí)行(GCD實(shí)現(xiàn))
A,B放在串行隊(duì)列中執(zhí)行愚墓,執(zhí)行完畢予权,主隊(duì)列執(zhí)行任務(wù)C
方案二:隊(duì)列依賴實(shí)現(xiàn)
方案三:并發(fā)隊(duì)列和主隊(duì)列實(shí)現(xiàn)
http://www.reibang.com/p/0b0d9b1f1f19
(1)串行隊(duì)列同步執(zhí)行和異步主隊(duì)列
dispatch_sync+串行隊(duì)列 ,同步執(zhí)行,能夠保證任務(wù)A,B順序執(zhí)行
dispatch_async A,B任務(wù)執(zhí)行完畢后浪册,主線程再執(zhí)行任務(wù)C
(2)NSOperation 有一個(gè)非常實(shí)用的功能扫腺,那就是添加依賴。比如有 3 個(gè)任務(wù):A: 從服務(wù)器上下載一張圖片村象,B:給這張圖片加個(gè)水印笆环,C:把圖片返回給服務(wù)器。這時(shí)就可以用到依賴了:
利用NSBlockOperation創(chuàng)建三個(gè)任務(wù)
設(shè)置依賴關(guān)系
創(chuàng)建隊(duì)列并加入任務(wù)
(3)同步執(zhí)行 :我們可以使用多線程的知識(shí)厚者,把多個(gè)線程都要執(zhí)行此段代碼添加到同一個(gè)串行隊(duì)列躁劣,這樣就實(shí)現(xiàn)了線程同步的概念。當(dāng)然這里可以使用 GCD 和 NSOperation 兩種方案库菲。
NSOperationQueue 有一個(gè)參數(shù) maxConcurrentOperationCount 最大并發(fā)數(shù)账忘,用來設(shè)置最多可以讓多少個(gè)任務(wù)同時(shí)執(zhí)行。當(dāng)你把它設(shè)置為 1 的時(shí)候,他不就是串行了嘛鳖擒!
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
這里面執(zhí)行任務(wù)C
}];
多線程
一.資源搶奪
2> 資源搶奪解決方案
@sychronized{ }
dispatch_barrier_async
NSLock NSCondition
dispatch_semaphore_wait
- dispatch_barrier_async的作用是什么溉浙?
在并行隊(duì)列中,為了保持某些任務(wù)的順序蒋荚,需要等待一些任務(wù)完成后才能繼續(xù)進(jìn)行戳稽,使用 barrier 來等待之前任務(wù)完成,避免數(shù)據(jù)競(jìng)爭(zhēng)等問題期升。 dispatch_barrier_async 函數(shù)會(huì)等待追加到Concurrent Dispatch Queue并行隊(duì)列中的操作全部執(zhí)行完之后惊奇,然后再執(zhí)行 dispatch_barrier_async 函數(shù)追加的處理,等 dispatch_barrier_async 追加的處理執(zhí)行結(jié)束之后播赁,Concurrent Dispatch Queue才恢復(fù)之前的動(dòng)作繼續(xù)執(zhí)行赊时。
打個(gè)比方:比如你們公司周末跟團(tuán)旅游,高速休息站上行拢,司機(jī)說:大家都去上廁所祖秒,速戰(zhàn)速?zèng)Q,上完廁所就上高速舟奠。超大的公共廁所竭缝,大家同時(shí)去,程序猿很快就結(jié)束了沼瘫,但程序媛就可能會(huì)慢一些抬纸,即使你第一個(gè)回來,司機(jī)也不會(huì)出發(fā)耿戚,司機(jī)要等待所有人都回來后湿故,才能出發(fā)。 dispatch_barrier_async 函數(shù)追加的內(nèi)容就如同 “上完廁所就上高速”這個(gè)動(dòng)作膜蛔。
(注意:使用 dispatch_barrier_async 坛猪,該函數(shù)只能搭配自定義并行隊(duì)列 dispatch_queue_t 使用。不能使用: dispatch_get_global_queue 皂股,否則 dispatch_barrier_async 的作用會(huì)和 dispatch_async 的作用一模一樣墅茉。 )
一般情況下,選擇使用GCD的dispatch_after呜呐。
1.performSelector和scheduledTimerWithTimeInterval方法都是基于runloop的就斤。
當(dāng)一個(gè)應(yīng)用啟動(dòng)時(shí),系統(tǒng)會(huì)開啟一個(gè)主線程蘑辑,并且把主線程的runloop激活洋机,也就是run起來,并且主線程的runloop是不會(huì)停止的洋魂。所以绷旗,當(dāng)這兩個(gè)方法在主線程可以被正常調(diào)用啄踊。
們更多的邏輯是放在子線程中執(zhí)行的。而子線程的runloop是默認(rèn)關(guān)閉的刁标。這時(shí)如果不手動(dòng)激活runloop颠通,performSelector和scheduledTimerWithTimeInterval的調(diào)用將是無效的。
2.NSTimer的創(chuàng)建與撤銷必須在同一個(gè)線程操作膀懈、performSelector的創(chuàng)建與撤銷必須在同一個(gè)線程操作顿锰。
scheduledTimerWithTimeInterval方法將target設(shè)為A對(duì)象時(shí),A對(duì)象會(huì)被這個(gè)timer所持有启搂,也就是會(huì)被retain一次硼控,timer會(huì)被當(dāng)前的runloop所持有。performSelector:withObject:afterDelay:方法實(shí)際上是在當(dāng)前線程的runloop里幫你創(chuàng)建的一個(gè)timer去執(zhí)行任務(wù)胳赌,所以和scheduledTimerWithTimeInterval方法一樣會(huì)retain其調(diào)用對(duì)象牢撼。但是,我們往往不希望因?yàn)檫@些延遲操作而影響對(duì)象的生命周期疑苫,更甚至是熏版,導(dǎo)致對(duì)象無法釋放.
3.內(nèi)存管理有潛在泄露的風(fēng)險(xiǎn)
3.dispatch_after有個(gè)致命的弱點(diǎn):dispatch_after一旦執(zhí)行后,就不能撤銷了捍掺。而performSelector可以使用cancelPreviousPerformRequestsWithTarget方法撤銷撼短,NSTimer也可以調(diào)用invalidate進(jìn)行撤銷。
解決辦法:
5.在多線程Core Data中挺勿,NSC,MOC,NSObjectModel哪些需要在線程中創(chuàng)建或者傳遞曲横?你是用什么策越來實(shí)現(xiàn)的?
Core Data是iOS5之后才出現(xiàn)的一個(gè)框架不瓶,它提供了對(duì)象-關(guān)系映射(ORM)的功能禾嫉,即能夠?qū)C對(duì)象轉(zhuǎn)化成數(shù)據(jù),保存在SQLite數(shù)據(jù)庫文件中蚊丐,也能夠?qū)⒈4嬖跀?shù)據(jù)庫中的數(shù)據(jù)還原成OC對(duì)象熙参。在此數(shù)據(jù)操作期間,我們不需要編寫任何SQL語句吠撮,這個(gè)有點(diǎn)類似于著名的Hibernate持久化框架尊惰,不過功能肯定是沒有Hibernate強(qiáng)大的讲竿。簡(jiǎn)單地用下圖描述下它的作用:
利用Core Data框架泥兰,我們就可以輕松地將數(shù)據(jù)庫里面的2條記錄轉(zhuǎn)換成2個(gè)OC對(duì)象,也可以輕松地將2個(gè)OC對(duì)象保存到數(shù)據(jù)庫中题禀,變成2條表記錄鞋诗,而且不用寫一條SQL語句, 另外支持自動(dòng)撤銷機(jī)制,一對(duì)多關(guān)聯(lián)等
Core data 是 Cocoa 中處理數(shù)據(jù)迈嘹,綁定數(shù)據(jù)的關(guān)鍵特性削彬,其重要性不言而喻全庸,但也比較復(fù)雜。Core Data 相關(guān)的類比較多融痛,初學(xué)者往往不太容易弄懂壶笼。1> CoreData是對(duì)SQLite數(shù)據(jù)庫的封裝
2> CoreData中的NSManagedObjectContext在多線程中不安全
3> 如果想要多線程訪問CoreData的話,最好的方法是一個(gè)線程一個(gè)NSManagedObjectContext
4> 每個(gè)NSManagedObjectContext對(duì)象實(shí)例都可以使用同一個(gè)
NSPersistentStoreCoordinator實(shí)例雁刷,這是因?yàn)镹SManagedObjectContext會(huì)在便用NSPersistentStoreCoordinator前上鎖
NSC持久化存儲(chǔ)調(diào)度器
PSC使用NSPersistentStore對(duì)象與數(shù)據(jù)庫進(jìn)行交互覆劈,NSPersistentStore對(duì)象會(huì)將MOC提交的改變同步到數(shù)據(jù)庫中
MOC管理對(duì)象上下文
NSObjectMode對(duì)象模型
于MOC不是線程安全的,如果多線程共用MOC的話會(huì)出現(xiàn)數(shù)據(jù)混亂沛励,甚至更嚴(yán)重的會(huì)導(dǎo)致程序崩潰责语。此外MO也不是線程安全的,但是PSC是線程安全的目派,因?yàn)镃ontext將改變提交給PSC時(shí)坤候,系統(tǒng)會(huì)為其上鎖,確保一次只執(zhí)行一個(gè)MOC提交的改變企蹭。
一個(gè)線程使用一個(gè)MOC對(duì)象白筹,并且在該線程中只能操作它所監(jiān)聽的MO。
使用兩個(gè)MOC谅摄,一個(gè)負(fù)責(zé)在后臺(tái)處理各種耗時(shí)的操作遍蟋,一個(gè)負(fù)責(zé)與UI進(jìn)行協(xié)作。
我們知道MOC和MO不是線程安全的螟凭,為了解決這個(gè)問題我們?cè)谝粋€(gè)線程中僅使用一個(gè)MOC虚青,因此不能跨線程訪問同一個(gè)MOC和MO周崭。但是這會(huì)存在問題项钮。
比如:我在后臺(tái)線程中執(zhí)行update操作,主線程中的上下文是不知道的如迟,所以當(dāng)我在主線程中去進(jìn)行查詢時(shí)下隧,查詢出來的結(jié)果并不是已更新后的結(jié)果奢人。
為了解決這個(gè)問題,我們需要監(jiān)聽通知:NSManagedObjectContextDidSaveNotification淆院,在耗時(shí)操作處理完之后去告訴主上下文發(fā)生了哪些改變何乎。我們可以通過主線程執(zhí)行合并操作來實(shí)現(xiàn)。
我們將探討從舊模型中提取數(shù)據(jù)并使用這些數(shù)據(jù)來填充具有新的實(shí)體和關(guān)系的目標(biāo)模型土辩。
當(dāng)你要升級(jí)你的數(shù)據(jù)模型到新版支救,你將先選擇一個(gè)基準(zhǔn)模型。對(duì)于輕量級(jí)遷移拷淘,持久化存儲(chǔ)會(huì)為你自動(dòng)推斷一個(gè)映射模型各墨。然而,如果你對(duì)新模型所做的修改并不被輕量級(jí)遷移所支持启涯,那么你就需要?jiǎng)?chuàng)建一個(gè)映射模型贬堵。一個(gè)映射模型需要一個(gè)源數(shù)據(jù)模型和一個(gè)目標(biāo)數(shù)據(jù)模型恃轩。
4.+(void)load與 +(void)initialize區(qū)別
load方法:
1.當(dāng)類加載到OC運(yùn)行時(shí)環(huán)境(內(nèi)存)中的時(shí)候,就會(huì)調(diào)用一次(一個(gè)類只會(huì)加載一次).
- 程序一啟動(dòng)就會(huì)調(diào)用.
3.程序運(yùn)行過程中,只會(huì)調(diào)用1次.
initialize方法:
1.當(dāng)?shù)谝淮问褂眠@個(gè)類的時(shí)候(比如調(diào)用了類的某個(gè)方法)才會(huì)調(diào)用. - 并非程序一啟動(dòng)就會(huì)調(diào)用.
load和initialize的共同特點(diǎn)
在不考慮開發(fā)者主動(dòng)使用的情況下,系統(tǒng)最多會(huì)調(diào)用一次
如果父類和子類都被調(diào)用黎做,父類的調(diào)用一定在子類之前
都是為了應(yīng)用運(yùn)行提前創(chuàng)建合適的運(yùn)行環(huán)境
在使用時(shí)都不要過重地依賴于這兩個(gè)方法叉跛,除非真正必要
它們的相同點(diǎn)在于:方法只會(huì)被調(diào)用一次。(其實(shí)這是相對(duì)runtime來說的蒸殿,后邊會(huì)做進(jìn)一步解釋)昧互。
load是只要類所在文件被引用就會(huì)被調(diào)用,而initialize是在類或者其子類的第一個(gè)方法被調(diào)用前調(diào)用伟桅。所以如果類沒有被引用進(jìn)項(xiàng)目敞掘,就不會(huì)有l(wèi)oad調(diào)用;但即使類文件被引用進(jìn)來楣铁,但是沒有使用玖雁,那么initialize也不會(huì)被調(diào)用。
文檔也明確闡述了方法調(diào)用的順序:父類(Superclass)的方法優(yōu)先于子類(Subclass)的方法盖腕,類中的方法優(yōu)先于類別(Category)中的方法赫冬。
? load 和 initialize方法的區(qū)別
5.http的post與區(qū)別與聯(lián)系,實(shí)踐中如何選擇它們溃列?
(1)get是從服務(wù)器上獲取數(shù)據(jù)劲厌,post是向服務(wù)器傳送數(shù)據(jù)。
(2)在客戶端听隐,Get方式在通過URL提交數(shù)據(jù),數(shù)據(jù)在URL中可以看到雅任;POST方式风范,數(shù)據(jù)放置body內(nèi)提交。
(3)對(duì)于get方式沪么,服務(wù)器端用Request.QueryString獲取變量的值硼婿,對(duì)于post方式,服務(wù)器端用Request.Form獲取提交的數(shù)據(jù)禽车。
(4)GET方式提交的數(shù)據(jù)最多只能有1024字節(jié)寇漫,而POST則沒有此限制。
(5)安全性問題殉摔。正如在(1)中提到州胳,使用 Get 的時(shí)候,參數(shù)會(huì)顯示在地址欄上钦勘,而 Post 不會(huì)陋葡。所以,如果這些數(shù)據(jù)是中文數(shù)據(jù)而且是非敏感數(shù)據(jù)彻采,那么使用 get腐缤;如果用戶輸入的數(shù)據(jù)不是中文字符而且包含敏感數(shù)據(jù),那么還是使用 post為好肛响。
(6)post 可以設(shè)置書簽
(7)在做數(shù)據(jù)查詢時(shí)岭粤,建議用Get方式
6.說說關(guān)于UDP/TCP的區(qū)別?
UDP(User Data Protocol特笋,用戶數(shù)據(jù)報(bào)協(xié)議)是與TCP相對(duì)應(yīng)的協(xié)議剃浇。它是面向非連接的協(xié)議,它不與對(duì)方建立連接猎物,而是直接就把數(shù)據(jù)包發(fā)送過去虎囚! UDP適用于一次只傳送少量數(shù)據(jù)、對(duì)可靠性要求不高的應(yīng)用環(huán)境蔫磨。
1.只管發(fā)送淘讥,不確認(rèn)對(duì)方是否接收到
2.將數(shù)據(jù)及源和目的封裝成數(shù)據(jù)包中,不需要建立連接
3.每個(gè)數(shù)據(jù)報(bào)的大小限制在64K之內(nèi)
4.因?yàn)闊o需連接堤如,因此是不可靠協(xié)議
5.不需要建立連接蒲列,速度快
應(yīng)用場(chǎng)景:多媒體教室/網(wǎng)絡(luò)流媒體
TCP(Transmission Control Protocol,傳輸控制協(xié)議)是基于連接的協(xié)議搀罢,也就是說蝗岖,在正式收發(fā)數(shù)據(jù)前,必須和對(duì)方建立可靠的連接榔至。一個(gè)TCP連接必須要經(jīng)過三次“對(duì)話”才能 建立起來抵赢,其中的過程非常復(fù)雜,我們這里只做簡(jiǎn)單唧取、形象的介紹瓣俯,你只要做到能夠理解這個(gè)過程即可。
1.建立連接兵怯,形成傳輸數(shù)據(jù)的通道
2.在連接中進(jìn)行大數(shù)據(jù)傳輸(數(shù)據(jù)大小不收限制)
3.通過三次握手完成連接彩匕,是可靠協(xié)議,安全送達(dá)
4.必須建立連接媒区,效率會(huì)稍低
TCP傳輸控制協(xié)議主要包含下列任務(wù)和功能:
- 確保IP數(shù)據(jù)報(bào)的成功傳遞驼仪。
- 對(duì)程序發(fā)送的大塊數(shù)據(jù)進(jìn)行分段和重組。
- 確保正確排序及按順序傳遞分段的數(shù)據(jù)袜漩。
- 通過計(jì)算校驗(yàn)和绪爸,進(jìn)行傳輸數(shù)據(jù)的完整性檢查。
簡(jiǎn)單的說宙攻,TCP注重?cái)?shù)據(jù)安全奠货,而UDP數(shù)據(jù)傳輸快點(diǎn),但安全性一般
3> TCP與UDP的區(qū)別:
3.1>基于連接與無連接座掘;
3.2>對(duì)系統(tǒng)資源的要求(TCP較多递惋,UDP少)柔滔;
3.3>UDP程序結(jié)構(gòu)較簡(jiǎn)單;
3.4>流模式與數(shù)據(jù)報(bào)模式 萍虽;
3.5>TCP保證數(shù)據(jù)正確性睛廊,UDP可能丟包,TCP保證數(shù)據(jù)順序杉编,UDP不保證超全。
十八:長(zhǎng)鏈接&短鏈接
TCP短連接
我們模擬一下TCP短連接的情況,client向server發(fā)起連接請(qǐng)求邓馒,server接到請(qǐng)求嘶朱,然后雙方建立連接。client向server 發(fā)送消息光酣,server回應(yīng)client疏遏,然后一次讀寫就完成了,這時(shí)候雙方任何一個(gè)都可以發(fā)起close操作挂疆,不過一般都是client先發(fā)起 close操作改览。為什么呢,一般的server不會(huì)回復(fù)完client后立即關(guān)閉連接的缤言,當(dāng)然不排除有特殊的情況宝当。從上面的描述看,短連接一般只會(huì)在 client/server間傳遞一次讀寫操作
TCP長(zhǎng)連接
接下來我們?cè)倌M一下長(zhǎng)連接的情況胆萧,client向server發(fā)起連接庆揩,server接受client連接,雙方建立連接跌穗。Client與server完成一次讀寫之后订晌,它們之間的連接并不會(huì)主動(dòng)關(guān)閉,后續(xù)的讀寫操作會(huì)繼續(xù)使用這個(gè)連接蚌吸。
長(zhǎng)連接短連接操作過程
短連接的操作步驟是:
建立連接——數(shù)據(jù)傳輸——關(guān)閉連接…建立連接——數(shù)據(jù)傳輸——關(guān)閉連接
長(zhǎng)連接的操作步驟是:
建立連接——數(shù)據(jù)傳輸…(保持連接)…數(shù)據(jù)傳輸——關(guān)閉連接
什么時(shí)候用長(zhǎng)連接锈拨,短連接?
長(zhǎng)連接多用于操作頻繁羹唠,點(diǎn)對(duì)點(diǎn)的通訊奕枢,而且連接數(shù)不能太多情況,佩微。每個(gè)TCP連接都需要三步握手缝彬,這需要時(shí)間,如果每個(gè)操作都是先連接哺眯,再操作的話 那么處理速度會(huì)降低很多谷浅,所以每個(gè)操作完后都不斷開,次處理時(shí)直接發(fā)送數(shù)據(jù)包就OK了,不用建立TCP連接一疯。例如:數(shù)據(jù)庫的連接用長(zhǎng)連接撼玄, 如果用短連接頻繁的通信會(huì)造成socket錯(cuò)誤,而且頻繁的socket 創(chuàng)建也是對(duì)資源的浪費(fèi)违施。
而像WEB網(wǎng)站的http服務(wù)一般都用短鏈接互纯,因?yàn)殚L(zhǎng)連接對(duì)于服務(wù)端來說會(huì)耗費(fèi)一定的資源瑟幕,而像WEB網(wǎng)站這么頻繁的成千上萬甚至上億客戶端的連接 用短連接會(huì)更省一些資源磕蒲,如果用長(zhǎng)連接,而且同時(shí)有成千上萬的用戶只盹,如果每個(gè)用戶都占用一個(gè)連接的話辣往,那可想而知吧苏遥。所以并發(fā)量大压语,但每個(gè)用戶無需頻繁操 作情況下需用短連好放仗。
長(zhǎng)連接和短連接的優(yōu)點(diǎn)和缺點(diǎn)
由上可以看出奕删,長(zhǎng)連接可以省去較多的TCP建立和關(guān)閉的操作冠胯,減少浪費(fèi)嗡善,節(jié)約時(shí)間岗宣。對(duì)于頻繁請(qǐng)求資源的客戶來說热某,較適用長(zhǎng)連接菩鲜。不過這里存在一個(gè)問 題园细,存活功能的探測(cè)周期太長(zhǎng),還有就是它只是探測(cè)TCP連接的存活接校,屬于比較斯文的做法猛频,遇到惡意的連接時(shí),敝朊悖活功能就不夠使了鹿寻。在長(zhǎng)連接的應(yīng)用場(chǎng)景 下,client端一般不會(huì)主動(dòng)關(guān)閉它們之間的連接诽凌,Client與server之間的連接如果一直不關(guān)閉的話毡熏,會(huì)存在一個(gè)問題,隨著客戶端連接越來越 多侣诵,server早晚有扛不住的時(shí)候痢法,這時(shí)候server端需要采取一些策略,如關(guān)閉一些長(zhǎng)時(shí)間沒有讀寫事件發(fā)生的連接窝趣,這樣可 以避免一些惡意連接導(dǎo)致server端服務(wù)受損疯暑;如果條件再允許就可以以客戶端機(jī)器為顆粒度,限制每個(gè)客戶端的最大長(zhǎng)連接數(shù)哑舒,這樣可以完全避免某個(gè)蛋疼的 客戶端連累后端服務(wù)妇拯。
短連接對(duì)于服務(wù)器來說管理較為簡(jiǎn)單,存在的連接都是有用的連接,不需要額外的控制手段越锈。但如果客戶請(qǐng)求頻繁仗嗦,將在TCP的建立和關(guān)閉操作上浪費(fèi)時(shí)間和帶寬。
長(zhǎng)連接和短連接的產(chǎn)生在于client和server采取的關(guān)閉策略甘凭,具體的應(yīng)用場(chǎng)景采用具體的策略稀拐,沒有十全十美的選擇,只有合適的選擇丹弱。
TCP 傳輸原理
1>TCP如何防止亂序和丟包
TCP數(shù)據(jù)包的頭格式中有兩個(gè)概念,Sequence Number是數(shù)據(jù)包的序號(hào)德撬,用來解決網(wǎng)絡(luò)包亂序(reordering)問題。Acknowledgement Number就是ACK——用于確認(rèn)收到躲胳,用來解決不丟包的問題蜓洪。
位碼即tcp標(biāo)志位,有6種標(biāo)示:SYN(synchronous建立聯(lián)機(jī)) ACK(acknowledgement 確認(rèn)) PSH(push傳送) FIN(finish結(jié)束) RST(reset重置) URG(urgent緊急)Sequence number(順序號(hào)碼) Acknowledge number(確認(rèn)號(hào)碼).
SeqNum的增加是和傳輸?shù)淖止?jié)數(shù)相關(guān)的,TCP傳輸數(shù)據(jù)時(shí),A主機(jī)第一次傳輸1440個(gè)字節(jié),seq=1,那么第二次時(shí)seq = 1441,B拼接數(shù)據(jù)就是根據(jù)seq進(jìn)行拼接的,seq數(shù)字不斷累加避免了亂序.B主機(jī)收到第一次數(shù)據(jù)包以后會(huì)返回ack = 1441.
A主機(jī)收到B的ack = 1441時(shí),就知道第一個(gè)數(shù)據(jù)包B已收到. 如果B沒有收到第一次的數(shù)據(jù)包,那么B再收到A的數(shù)據(jù)包時(shí),他就會(huì)發(fā)ack = 1回去,A收到B的回復(fù),發(fā)現(xiàn)B沒有收到第一次數(shù)據(jù)包,就會(huì)重發(fā)第一次數(shù)據(jù)包,這樣就可以防止丟包.
2>描述一下三次握手
第一次握手:建立連接時(shí)坯苹,客戶端發(fā)送syn包(syn=j)到服務(wù)器隆檀,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn)粹湃;
第二次握手:服務(wù)器收到syn包恐仑,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k)为鳄,即SYN+ACK包裳仆,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
第三次握手:客戶端收到服務(wù)器的SYN+ACK包济赎,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1)鉴逞,此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài)司训,完成三次握手构捡。完成三次握手,客戶端與服務(wù)器開始傳送數(shù)據(jù).
3> 三次握手實(shí)現(xiàn)的過程:
第一次握手:建立連接時(shí)壳猜,客戶端發(fā)送同步序列編號(hào)到服務(wù)器勾徽,并進(jìn)入發(fā)送狀態(tài),等待服務(wù)器確認(rèn)
第二次:服務(wù)器收到同步序列編號(hào)统扳,并確認(rèn)同時(shí)自己也發(fā)送一個(gè)同步序列編號(hào)+確認(rèn)標(biāo)志,此時(shí)服務(wù)器進(jìn)入接收狀態(tài)
第三次:客戶端收到服務(wù)器發(fā)送的包咒钟,并向服務(wù)器發(fā)送確認(rèn)標(biāo)志吹由,隨后鏈接成功。
注意:是在鏈接成功后在進(jìn)行數(shù)據(jù)傳輸朱嘴。
8.http和scoket通信的區(qū)別?socket連接相關(guān)庫,TCP,UDP的連接方法,HTTP的幾種常用方式?
http和scoket通信的區(qū)別:
http是客戶端用http協(xié)議進(jìn)行請(qǐng)求,發(fā)送請(qǐng)求時(shí)候需要封裝http請(qǐng)求頭,并綁定請(qǐng)求的數(shù)據(jù),服務(wù)器一般有web服務(wù)器配合(當(dāng)然也非絕對(duì))倾鲫。 http請(qǐng)求方式為客戶端主動(dòng)發(fā)起請(qǐng)求,服務(wù)器才能給響應(yīng),一次請(qǐng)求完畢后則斷開連接,以節(jié)省資源粗合。服務(wù)器不能主動(dòng)給客戶端響應(yīng)(除非采取http長(zhǎng)連接技術(shù))。iphone主要使用類是NSUrlConnection乌昔。
scoket是客戶端跟服務(wù)器直接使用socket“套接字”進(jìn)行連接,并沒有規(guī)定連接后斷開,所以客戶端和服務(wù)器可以保持連接通道,雙方都可以主動(dòng)發(fā)送數(shù)據(jù)。一般在游戲開發(fā)或股票開發(fā)這種要求即時(shí)性很強(qiáng)并且保持發(fā)送數(shù)據(jù)量比較大的場(chǎng)合使用牙寞。主要使用類是CFSocketRef。
5> HTTP請(qǐng)求常用的幾種方式
GET :獲取指定資源
POST :2M 向指定資源提交數(shù)據(jù)進(jìn)行處理請(qǐng)求伟端,在RESTful 風(fēng)格用于新增資源
HEAD :獲取指定資源頭部信息
PUT :替換指定資源(不支持瀏覽器操作)
DELETE: 刪除指定資源
BLOCK
1.. 使用block時(shí)什么情況會(huì)發(fā)生引用循環(huán)杯道,如何解決?
一個(gè)對(duì)象中強(qiáng)引用了block责蝠,在block中又使用了該對(duì)象党巾,就會(huì)發(fā)射循環(huán)引用。 解決方法是將該對(duì)象使用__weak或者_(dá)_block修飾符修飾之后再在block中使用霜医。
id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self該方法可以設(shè)置宏
id __block weakSelf = self;
2.. 在block內(nèi)如何修改block外部變量齿拂?
在block中訪問的外部變量是復(fù)制過去的,即:寫操作不對(duì)原變量生效肴敛。但是你可以加上__block來讓其寫操作生效署海,示例代碼如下:
__block int a = 0;
void (^foo)(void) = ^{
a = 1;
}
f00();
//這里,a的值被修改為1
3.Block&MRC-Block
block雖然好用医男,但是里面也有不少坑砸狞,最大的坑莫過于循環(huán)引用問題。稍不注意镀梭,可能就會(huì)造成內(nèi)存泄漏刀森。這節(jié),我將從源碼的角度來分析造成循環(huán)引用問題的根本原因报账。并解釋變量前加block研底,和weak的區(qū)別。
明確兩點(diǎn)
1,Block可以訪問Block函數(shù)以及語法作用域以內(nèi)的外部變量透罢。也就是說:一個(gè)函數(shù)里定義了個(gè)block榜晦,這個(gè)block可以訪問該函數(shù)的內(nèi)部變量(當(dāng)然還包括靜態(tài),全局變量)-即block可以使用和本身定義范圍相同的變量琐凭。 2,Block其實(shí)是特殊的Objective-C對(duì)象芽隆,可以使用copy,release等來管理內(nèi)存,但和一般的NSObject的管理方式有些不 同,稍后會(huì)說明统屈。
MRC:防止 block 對(duì)self的引用 解決辦法
__block typeof(self) weakSelf = self;
ARC:防止 block 對(duì)self的引用 解決辦法
__weak typeof(self) weakSelf = self;
對(duì)于非ARC下, 為了防止循環(huán)引用, 我們使用__block來修飾在Block中使用的對(duì)象:
對(duì)于ARC下, 為了防止循環(huán)引用, 我們使用weak來修飾在Block中使用的對(duì)象胚吁。原理就是:ARC中,Block中如果引用了strong修飾符的自動(dòng)變量愁憔,則相當(dāng)于Block對(duì)該變量的引用計(jì)數(shù)+1腕扶。
1.block
1> block屬性為什么用copy?
棧->堆
2> block使用注意什么?
循環(huán)引用
__block 修飾局部變量,這個(gè)變量在 block 內(nèi)外屬于同一個(gè)地址 上的變量,可以被 block 內(nèi)部的代碼修改
3> block的主要使用場(chǎng)景 ?
動(dòng)畫
數(shù)組字典排序遍歷
回調(diào)狀態(tài)
錯(cuò)誤控制
多線程GCD
4>block原理
block屬性是指向結(jié)構(gòu)體的指針,
- 什么是block
答: 對(duì)于閉包(block),有很多定義吨掌,其中閉包就是能夠讀取其它函數(shù)內(nèi)部變量的函數(shù)半抱,這個(gè)定義即接近本質(zhì)又較好理解脓恕。對(duì)于剛接觸Block的同學(xué),會(huì)覺得有些繞窿侈,因?yàn)槲覀兞?xí)慣寫這樣的程序main(){ funA();} funA(){funB();} funB(){…..}; 就是函數(shù)main調(diào)用函數(shù)A炼幔,函數(shù)A調(diào)用函數(shù)B… 函數(shù)們依次順序執(zhí)行,但現(xiàn)實(shí)中不全是這樣的史简,例如項(xiàng)目經(jīng)理M,手下有3個(gè)程序員A圆兵、B跺讯、C,當(dāng)他給程序員A安排實(shí)現(xiàn)功能F1時(shí)殉农,他并不等著A完成之后刀脏,再去安排B去實(shí)現(xiàn)F2,而是安排給A功能F1超凳,B功能F2愈污,C功能F3,然后可能去寫技術(shù)文檔聪建,而當(dāng)A遇到問題時(shí)钙畔,他會(huì)來找項(xiàng)目經(jīng)理M,當(dāng)B做完時(shí)金麸,會(huì)通知M,這就是一個(gè)異步執(zhí)行的例子簿盅。在這種情形下挥下,Block便可大顯身手,因?yàn)樵陧?xiàng)目經(jīng)理M桨醋,給A安排工作時(shí)棚瘟,同時(shí)會(huì)告訴A若果遇到困難,如何能找到他報(bào)告問題(例如打他手機(jī)號(hào))喜最,這就是項(xiàng)目經(jīng)理M給A的一個(gè)回調(diào)接口偎蘸,要回掉的操作,比如接到電話瞬内,百度查詢后迷雪,返回網(wǎng)頁內(nèi)容給A,這就是一個(gè)Block虫蝶,在M交待工作時(shí)章咧,已經(jīng)定義好,并且取得了F1的任務(wù)號(hào)(局部變量)能真,卻是在當(dāng)A遇到問題時(shí),才調(diào)用執(zhí)行氢伟,跨函數(shù)在項(xiàng)目經(jīng)理M查詢百度次坡,獲得結(jié)果后回調(diào)該block。 - block 實(shí)現(xiàn)原理
答: Objective-C是對(duì)C語言的擴(kuò)展卤档,block的實(shí)現(xiàn)是基于指針和函數(shù)指針。
從計(jì)算語言的發(fā)展程剥,最早的goto裆装,高級(jí)語言的指針,到面向?qū)ο笳Z言的block倡缠,從機(jī)器的思維哨免,一步步接近人的思維,以方便開發(fā)人員更為高效昙沦、直接的描述出現(xiàn)實(shí)的邏輯(需求)琢唾。
使用實(shí)例
cocoaTouch框架下動(dòng)畫效果的Block的調(diào)用
使用typed聲明block
// 這就聲明了一個(gè)didFinishBlock類型的block,
typedef void(^didFinishBlock) (NSObject *obj);
// 這就聲明了一個(gè)didFinishBlock類型的block盾饮,
typedef void(^didFinishBlock) (NSObject *obj);
然后便可用
@property (nonatomic,copy) didFinishBlock finishBlock;
@property (nonatomic,copy) didFinishBlock finishBlock;
聲明一個(gè)blokc對(duì)象采桃,注意對(duì)象屬性設(shè)置為copy,接到block 參數(shù)時(shí)丘损,便會(huì)自動(dòng)復(fù)制一份普办。
__block是一種特殊類型,
使用該關(guān)鍵字聲明的局部變量徘钥,可以被block所改變衔蹲,并且其在原函數(shù)中的值會(huì)被改變。
60.關(guān)于block
答: 面試時(shí)呈础,面試官會(huì)先問一些舆驶,是否了解block,是否使用過block而钞,這些問題相當(dāng)于開場(chǎng)白沙廉,往往是下面一系列問題的開始,所以一定要如實(shí)根據(jù)自己的情況回答臼节。
1). 使用block和使用delegate完成委托模式有什么優(yōu)點(diǎn)?
首先要了解什么是委托模式撬陵,委托模式在iOS中大量應(yīng)用,其在設(shè)計(jì)模式中是適配器模式中的對(duì)象適配器网缝,Objective-C中使用id類型指向一切對(duì)象巨税,使委托模式更為簡(jiǎn)潔。了解委托模式的細(xì)節(jié):
iOS設(shè)計(jì)模式—-委托模式
使用block實(shí)現(xiàn)委托模式途凫,其優(yōu)點(diǎn)是回調(diào)的block代碼塊定義在委托對(duì)象函數(shù)內(nèi)部垢夹,使代碼更為緊湊;
適配對(duì)象不再需要實(shí)現(xiàn)具體某個(gè)protocol,代碼更為簡(jiǎn)潔维费。
2). 多線程與block
GCD與Block
使用 dispatch_async 系列方法果元,可以以指定的方式執(zhí)行block
GCD編程實(shí)例
dispatch_async的完整定義
void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
1
void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
功能:在指定的隊(duì)列里提交一個(gè)異步執(zhí)行的block促王,不阻塞當(dāng)前線程
通過queue來控制block執(zhí)行的線程而晒。主線程執(zhí)行前文定義的 finishBlock對(duì)象
dispatch_async(dispatch_get_main_queue(),^(void){finishBlock();});
dispatch_async(dispatch_get_main_queue(),^(void){finishBlock();});
- 談?wù)剬?duì)Block 的理解?并寫出一個(gè)使用Block執(zhí)行UIVew動(dòng)畫?
答:Block是可以獲取其他函數(shù)局部變量的匿名函數(shù),其不但方便開發(fā)倡怎,并且可以大幅提高應(yīng)用的執(zhí)行效率(多核心CPU可直接處理Block指令)
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; }
completion:NULL];
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; }
completion:NULL]; - 寫出上面代碼的Block的定義迅耘。
答:
typedef void(^animations) (void);
typedef void(^completion) (BOOL finished);
typedef void(^animations) (void);
typedef void(^completion) (BOOL finished);
Weak、strong监署、copy颤专、assign 使用
什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同钠乏?
什么情況使用 weak 關(guān)鍵字栖秕?
在 ARC 中,在有可能出現(xiàn)循環(huán)引用的時(shí)候,往往要通過讓其中一端使用 weak 來解決,比如: delegate 代理屬性
自身已經(jīng)對(duì)它進(jìn)行一次強(qiáng)引用,沒有必要再強(qiáng)引用一次,此時(shí)也會(huì)使用 weak,自定義 IBOutlet 控件屬性一般也使用 weak;當(dāng)然晓避,也可以使用strong簇捍。在下文也有論述:《IBOutlet連出來的視圖屬性為什么可以被設(shè)置成weak?》
不同點(diǎn):
weak 此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系” (nonowning relationship)。為這種屬性設(shè)置新值時(shí)俏拱,設(shè)置方法既不保留新值暑塑,也不釋放舊值。此特質(zhì)同assign類似锅必, 然而在屬性所指的對(duì)象遭到摧毀時(shí)事格,屬性值也會(huì)清空(nil out)。 而 assign 的“設(shè)置方法”只會(huì)執(zhí)行針對(duì)“純量類型” (scalar type况毅,例如 CGFloat 或 NSlnteger 等)的簡(jiǎn)單賦值操作分蓖。
assigin 可以用非 OC 對(duì)象,而 weak 必須用于 OC 對(duì)象怎么用 copy 關(guān)鍵字?
用途:
NSString尔许、NSArray、NSDictionary 等等經(jīng)常使用copy關(guān)鍵字终娃,是因?yàn)樗麄冇袑?duì)應(yīng)的可變類型:NSMutableString味廊、NSMutableArray、NSMutableDictionary棠耕;
block 也經(jīng)常使用 copy 關(guān)鍵字余佛,具體原因見官方文檔:Objects Use Properties to Keep Track of Blocks:
block 使用 copy 是從 MRC 遺留下來的“傳統(tǒng)”,在 MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).在 ARC 中寫不寫都行:對(duì)于 block 使用 copy 還是 strong 效果是一樣的,但寫上 copy 也無傷大雅窍荧,還能時(shí)刻提醒我們:編譯器自動(dòng)對(duì) block 進(jìn)行了 copy 操作辉巡。如果不寫 copy ,該類的調(diào)用者有可能會(huì)忘記或者根本不知道“編譯器會(huì)自動(dòng)對(duì) block 進(jìn)行了 copy 操作”蕊退,他們有可能會(huì)在調(diào)用之前自行拷貝屬性值郊楣。這種操作多余而低效憔恳。
copy 此特質(zhì)所表達(dá)的所屬關(guān)系與 strong 類似。然而設(shè)置方法并不保留新值净蚤,而是將其“拷貝” (copy)钥组。 當(dāng)屬性類型為 NSString 時(shí),經(jīng)常用此特質(zhì)來保護(hù)其封裝性今瀑,因?yàn)閭鬟f給設(shè)置方法的新值有可能指向一個(gè) NSMutableString 類的實(shí)例程梦。這個(gè)類是 NSString 的子類,表示一種可修改其值的字符串橘荠,此時(shí)若是不拷貝字符串屿附,那么設(shè)置完屬性之后,字符串的值就可能會(huì)在對(duì)象不知情的情況下遭人更改哥童。所以挺份,這時(shí)就要拷貝一份“不可變” (immutable)的字符串,確保對(duì)象中的字符串值不會(huì)無意間變動(dòng)如蚜。只要實(shí)現(xiàn)屬性所用的對(duì)象是“可變的” (mutable)压恒,就應(yīng)該在設(shè)置新屬性值時(shí)拷貝一份。
一: weak&strong
strong表示保留它指向的堆上的內(nèi)存區(qū)域不再指向這塊區(qū)域了错邦。 也就是說我強(qiáng)力指向了一個(gè)區(qū)域探赫,我們不再指向它的條件只有我們指向nil或者我自己也不在內(nèi)存上,沒有人strong指向我了撬呢。
weak表示如果還沒有人指向它了伦吠,它就會(huì)被清除內(nèi)存,同時(shí)被指向nil魂拦,因?yàn)槲也荒茏x取不存在的東西毛仪。
weak只在iOS5.0使用
這并不是垃圾回收,我們用reference count 表示堆上還有多少strong指針芯勘,當(dāng)它變?yōu)?就馬上釋放箱靴。
本地變量都是strong,編輯器幫你計(jì)算.
補(bǔ)充
管理機(jī)制:使用了一種叫做引用計(jì)數(shù)的機(jī)制來管理內(nèi)存中的對(duì)象荷愕。OC中每個(gè)對(duì)象都對(duì)應(yīng)著他們自己的引用計(jì)數(shù)衡怀,引用計(jì)數(shù)可以理解為一個(gè)整數(shù)計(jì)數(shù)器,當(dāng)使 用alloc方法創(chuàng)建對(duì)象的時(shí)候安疗,持有計(jì)數(shù)會(huì)自動(dòng)設(shè)置為1抛杨。當(dāng)你向一個(gè)對(duì)象發(fā)送retain消息 時(shí),持有計(jì)數(shù)數(shù)值會(huì)增加1荐类。相反怖现,當(dāng)你像一個(gè)對(duì)象發(fā)送release消息時(shí),持有計(jì)數(shù)數(shù)值會(huì)減小1玉罐。當(dāng)對(duì)象的持有計(jì)數(shù)變?yōu)?的時(shí)候屈嗤,對(duì)象會(huì)釋放自己所占用 的內(nèi)存潘拨。 retain(引用計(jì)數(shù)加1)->release(引用計(jì)數(shù)減1) alloc(申請(qǐng)內(nèi)存空間)->dealloc(釋放內(nèi)存空間) readwrite: 表示既有g(shù)etter,也有setter (默認(rèn)) readonly: 表示只有g(shù)etter恢共,沒有setter nonatomic:不考慮線程安全 atomic:線程操作安全 (默認(rèn)) 線程安全情況下的setter和getter:
(NSString*) value { @synchronized(self) { return [[_value retain] autorelease];
} }
(void) setValue:(NSString)aValue { @synchronized(self) { [aValue retain]; [value release]; value = aValue;
} } retain: release舊的對(duì)象战秋,將舊對(duì)象的值賦予輸入對(duì)象,再提高輸入對(duì)象的索引計(jì)數(shù)為1 assign: 簡(jiǎn)單賦值讨韭,不更改索引計(jì)數(shù) (默認(rèn)) copy: 其實(shí)是建立了一個(gè)相同的對(duì)象,地址不同(retain:指針拷貝 copy:內(nèi)容拷貝) strong:(ARC下的)和(MRC)retain一樣 (默認(rèn)) weak:(ARC下的)和(MRC)assign一樣脂信, weak當(dāng)指向的內(nèi)存釋放掉后自動(dòng)nil化,防止野指針 unsafe_unretained 聲明一個(gè)弱應(yīng)用透硝,但是不會(huì)自動(dòng)nil化狰闪,也就是說,如果所指向的內(nèi)存區(qū)域被釋放了濒生,這個(gè)指針就是一個(gè)野指針了,聲明的屬性dealloc 里面設(shè)置為nil埋泵。 autoreleasing 用來修飾一個(gè)函數(shù)的參數(shù),這個(gè)參數(shù)會(huì)在函數(shù)返回的時(shí)候被自動(dòng)釋放觉义。1、 類變量的@protected ,@private,@public,@package窘疮,聲明各有什么含義闸衫? @private:作用范圍只能在自身類 @protected:作用范圍在自身類和繼承自己的子類 (默認(rèn)) @public:作用范圍最大,可以在任何地方被訪問轧苫。 @package:這個(gè)類型最常用于框架類的實(shí)例變量,同一包內(nèi)能用楚堤,跨包就不能訪問這個(gè)寫法會(huì)出什么問題: @property (copy) NSMutableArray *array
兩個(gè)問題:1、添加,刪除,修改數(shù)組內(nèi)的元素的時(shí)候,程序會(huì)因?yàn)檎也坏綄?duì)應(yīng)的方法而崩潰.因?yàn)?copy 就是復(fù)制一個(gè)不可變 NSArray 的對(duì)象含懊;2身冬、使用了 atomic 屬性會(huì)嚴(yán)重影響性能
第1條的相關(guān)原因在下文中有論述《用@property聲明的NSString(或NSArray,NSDictionary)經(jīng)常使用 copy 關(guān)鍵字岔乔,為什么酥筝?如果改用strong關(guān)鍵字,可能造成什么問題雏门?》 以及上文《怎么用 copy 關(guān)鍵字坏挠?》也有論述。
比如下面的代碼就會(huì)發(fā)生崩潰
// .h文件
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// 下面的代碼就會(huì)發(fā)生崩潰
@property (nonatomic, copy) NSMutableArray *mutableArray;
// .m文件
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// 下面的代碼就會(huì)發(fā)生崩潰
NSMutableArray *array = [NSMutableArray arrayWithObjects:@1,@2,nil];
self.mutableArray = array;
[self.mutableArray removeObjectAtIndex:0];
接下來就會(huì)奔潰:
-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460
第2條原因更振,如下:
該屬性使用了同步鎖确沸,會(huì)在創(chuàng)建時(shí)生成一些額外的代碼用于幫助編寫多線程程序,這會(huì)帶來性能問題募闲,通過聲明 nonatomic 可以節(jié)省這些雖然很小但是不必要額外開銷步脓。
在默認(rèn)情況下,由編譯器所合成的方法會(huì)通過鎖定機(jī)制確保其原子性(atomicity)。如果屬性具備 nonatomic 特質(zhì)靴患,則不使用同步鎖仍侥。請(qǐng)注意,盡管沒有名為“atomic”的特質(zhì)(如果某屬性不具備 nonatomic 特質(zhì)鸳君,那它就是“原子的”(atomic))农渊。
在iOS開發(fā)中,你會(huì)發(fā)現(xiàn)或颊,幾乎所有屬性都聲明為 nonatomic砸紊。
一般情況下并不要求屬性必須是“原子的”,因?yàn)檫@并不能保證“線程安全” ( thread safety)饭宾,若要實(shí)現(xiàn)“線程安全”的操作批糟,還需采用更為深層的鎖定機(jī)制才行看铆。例如徽鼎,一個(gè)線程在連續(xù)多次讀取某屬性值的過程中有別的線程在同時(shí)改寫該值,那么即便將屬性聲明為 atomic弹惦,也還是會(huì)讀到不同的屬性值否淤。
因此,開發(fā)iOS程序時(shí)一般都會(huì)使用 nonatomic 屬性棠隐。但是在開發(fā) Mac OS X 程序時(shí)石抡,使用 atomic 屬性通常都不會(huì)有性能瓶頸
- 如何讓自己的類用 copy 修飾符?如何重寫帶 copy 關(guān)鍵字的 setter助泽?
若想令自己所寫的對(duì)象具有拷貝功能啰扛,則需實(shí)現(xiàn) NSCopying 協(xié)議。如果自定義的對(duì)象分為可變版本與不可變版本嗡贺,那么就要同時(shí)實(shí)現(xiàn) NSCopying 與 NSMutableCopying 協(xié)議
具體步驟:
需聲明該類遵從 NSCopying 協(xié)議
實(shí)現(xiàn) NSCopying 協(xié)議隐解。該協(xié)議只有一個(gè)方法:
- (id)copyWithZone:(NSZone *)zone;
注意:一提到讓自己的類用 copy 修飾符,我們總是想覆寫copy方法诫睬,其實(shí)真正需要實(shí)現(xiàn)的卻是 “copyWithZone” 方法
但在實(shí)際的項(xiàng)目中煞茫,不可能這么簡(jiǎn)單,遇到更復(fù)雜一點(diǎn)摄凡,比如類對(duì)象中的數(shù)據(jù)結(jié)構(gòu)可能并未在初始化方法中設(shè)置好续徽,需要另行設(shè)置。舉個(gè)例子亲澡,假如 CYLUser 中含有一個(gè)數(shù)組钦扭,與其他 CYLUser 對(duì)象建立或解除朋友關(guān)系的那些方法都需要操作這個(gè)數(shù)組。那么在這種情況下床绪,你得把這個(gè)包含朋友對(duì)象的數(shù)組也一并拷貝過來土全。下面列出了實(shí)現(xiàn)此功能所需的全部代碼:
【注:深淺拷貝的概念捎琐,在下文中有介紹,詳見下文的:用@property聲明的 NSString(或NSArray裹匙,NSDictionary)經(jīng)常使用 copy 關(guān)鍵字,為什么末秃?如果改用 strong 關(guān)鍵字概页,可能造成什么問題?】
在例子中练慕,存放朋友對(duì)象的 set 是用 “copyWithZone:” 方法來拷貝的惰匙,這種淺拷貝方式不會(huì)逐個(gè)復(fù)制 set 中的元素。若需要深拷貝的話铃将,則可像下面這樣项鬼,編寫一個(gè)專供深拷貝所用的方法:
- @property 的本質(zhì)是什么?ivar劲阎、getter绘盟、setter 是如何生成并添加到這個(gè)類中的
@property = ivar + getter + setter;
屬性” (property)作為 Objective-C 的一項(xiàng)特性,主要的作用就在于封裝對(duì)象中的數(shù)據(jù)悯仙。 Objective-C 對(duì)象通常會(huì)把其所需要的數(shù)據(jù)保存為各種實(shí)例變量龄毡。實(shí)例變量一般通過“存取方法”(access method)來訪問。其中锡垄,“獲取方法” (getter)用于讀取變量值沦零,而“設(shè)置方法” (setter)用于寫入變量值。這個(gè)概念已經(jīng)定型货岭,并且經(jīng)由“屬性”這一特性而成為 Objective-C 2.0 的一部分路操。 而在正規(guī)的 Objective-C 編碼風(fēng)格中,存取方法有著嚴(yán)格的命名規(guī)范千贯。 正因?yàn)橛辛诉@種嚴(yán)格的命名規(guī)范屯仗,所以 Objective-C 這門語言才能根據(jù)名稱自動(dòng)創(chuàng)建出存取方法。其實(shí)也可以把屬性當(dāng)做一種關(guān)鍵字丈牢,其表示:
編譯器會(huì)自動(dòng)寫出一套存取方法祭钉,用以訪問給定類型中具有給定名稱的變量。 所以你也可以這么說:
@property = getter + setter;
ivar己沛、getter慌核、setter 是如何生成并添加到這個(gè)類中的?
“自動(dòng)合成”( autosynthesis)
完成屬性定義后,編譯器會(huì)自動(dòng)編寫訪問這些屬性所需的方法申尼,此過程叫做“自動(dòng)合成”(autosynthesis)垮卓。需要強(qiáng)調(diào)的是,這個(gè)過程由編譯 器在編譯期執(zhí)行师幕,所以編輯器里看不到這些“合成方法”(synthesized method)的源代碼粟按。除了生成方法代碼 getter诬滩、setter 之外,編譯器還要自動(dòng)向類中添加適當(dāng)類型的實(shí)例變量灭将,并且在屬性名前面加下劃線疼鸟,以此作為實(shí)例變量的名字。在前例中庙曙,會(huì)生成兩個(gè)實(shí)例變量空镜,其名稱分別為 _firstName 與 _lastName。也可以在類的實(shí)現(xiàn)代碼里通過 @synthesize 語法來指定實(shí)例變量的名字.
@implementation Person
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
6.用@property聲明的NSString(或NSArray捌朴,NSDictionary)經(jīng)常使用copy關(guān)鍵字吴攒,為什么?如果改用strong關(guān)鍵字砂蔽,可能造成什么問題洼怔?
因?yàn)楦割愔羔樋梢灾赶蜃宇悓?duì)象,使用copy的目的是為了讓本對(duì)象的屬性不受外界影響,使用copy無論給我傳入是一個(gè)可變對(duì)象還是不可對(duì)象,我本身持有的就是一個(gè)不可變的副本.
如果我們使用是strong,那么這個(gè)屬性就有可能指向一個(gè)可變對(duì)象,如果這個(gè)可變對(duì)象在外部被修改了,那么會(huì)影響該屬性.
7.@protocol 和 category 中如何使用 @property
在 protocol 中使用 property 只會(huì)生成 setter 和 getter 方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對(duì)象能實(shí)現(xiàn)該屬性
category 使用 @property 也是只會(huì)生成 setter 和 getter 方法的聲明,如果我們真的需要給 category 增加屬性的實(shí)現(xiàn),需要借助于運(yùn)行時(shí)的兩個(gè)函數(shù):
objc_setAssociatedObject
objc_getAssociatedObject
8.runtime如何通過selector找到對(duì)應(yīng)的IMP地址?
每一個(gè)類對(duì)象中都一個(gè)方法列表(isa),方法列表中記錄著方法的名稱,方法實(shí)現(xiàn),以及參數(shù)類型,其實(shí)selector本質(zhì)就是方法名稱,通過這個(gè)方法名稱就可以在方法列表中找到對(duì)應(yīng)的方法實(shí)現(xiàn).
9.retain和copy區(qū)別
copy其實(shí)是建立了一個(gè)相同的對(duì)象,而retain不是:
比如一個(gè)NSString對(duì)象绪妹,地址為0×1111律歼,內(nèi)容為@”STR”
Copy到另外一個(gè)NSString之 后民镜,地址為0×2222,內(nèi)容相同苗膝,新的對(duì)象retain為1殃恒, 舊有對(duì)象沒有變化
retain到另外一個(gè)NSString之 后,地址相同(建立一個(gè)指針辱揭,指針拷貝),內(nèi)容當(dāng)然相同病附,這個(gè)對(duì)象的retain值+1
也就是說问窃,retain是指針拷貝,copy是內(nèi)容拷貝
copy是創(chuàng)建一個(gè)新對(duì)象完沪,retain是創(chuàng)建一個(gè)指針域庇。 copy:建立一個(gè)索引計(jì)數(shù)為1的新對(duì)象,然后釋放舊對(duì)象覆积。新的對(duì)象retain為1听皿,與舊有對(duì)象引用技術(shù)無關(guān),減少了對(duì)象對(duì)上下文的依賴宽档。retain:釋放舊的對(duì)象尉姨,將舊對(duì)象的值賦予輸入新對(duì)象,再提高輸入對(duì)象的索引計(jì)數(shù)為1吗冤,新對(duì)象和舊對(duì)象指針相同又厉。
10.copy和strong的使用?
我們?cè)诼暶饕粋€(gè)NSString屬性時(shí)椎瘟,對(duì)于其內(nèi)存相關(guān)特性覆致,通常有兩種選擇(基于ARC環(huán)境):strong與copy。那這兩者有什么區(qū)別呢肺蔚?什么時(shí)候該用strong煌妈,什么時(shí)候該用copy呢?
由于NSMutableString是NSString的子類宣羊,所以一個(gè)NSString指針可以指向NSMutableString對(duì)象璧诵,讓我們的strongString指針指向一個(gè)可變字符串是OK的。
而上面的例子可以看出段只,當(dāng)源字符串是NSString時(shí)腮猖,由于字符串是不可變的,所以赞枕,不管是strong還是copy屬性的對(duì)象澈缺,都是指向源對(duì)象坪创,copy操作只是做了次淺拷貝。
當(dāng)源字符串是NSMutableString時(shí)姐赡,strong屬性只是增加了源字符串的引用計(jì)數(shù)莱预,而copy屬性則是對(duì)源字符串做了次深拷貝,產(chǎn)生一個(gè)新的對(duì)象项滑,且copy屬性對(duì)象指向這個(gè)新的對(duì)象依沮。另外需要注意的是,這個(gè)copy屬性對(duì)象的類型始終是NSString枪狂,而不是NSMutableString危喉,因此其是不可變的。
這里還有一個(gè)性能問題,即在源字符串是NSMutableString,strong是單純的增加對(duì)象的引用計(jì)數(shù)伞鲫,而copy操作是執(zhí)行了一次深拷貝泞当,所以性能上會(huì)有所差異。而如果源字符串是NSString時(shí),則沒有這個(gè)問題。
所以,在聲明NSString屬性時(shí)毫深,到底是選擇strong還是copy,可以根據(jù)實(shí)際情況來定毒姨。不過哑蔫,一般我們將對(duì)象聲明為NSString時(shí),都不希望它改變手素,所以大多數(shù)情況下鸳址,我們建議用copy,以免因可變字符串的修改導(dǎo)致的一些非預(yù)期問題泉懦。
2.NSString和NSMutableString稿黍,前者線程安全,后者線程不安全崩哩。
NSString和NSMutableString巡球,前者接收到copy時(shí),是淺拷貝邓嘹,后者是深拷貝酣栈,但返回的都是不可變對(duì)象,即NSString對(duì)象
NSString和NSMutableString汹押,接收到mutableCopy時(shí)矿筝,都是深拷貝,并且返回的都是可變對(duì)象棚贾,即NSMutableString對(duì)象
NSString和NSMutableString窖维,strong修飾時(shí)屬性時(shí)一樣榆综,都是強(qiáng)引用的概念,賦值時(shí)不會(huì)接收到copy或mutableCopy消息
很簡(jiǎn)單,假如有一個(gè)NSMutableString,現(xiàn)在用他給一個(gè)retain修飾 NSString賦值,那么只是將NSString指向了NSMutableString所指向的位置,并對(duì)NSMUtbaleString計(jì)數(shù)器加一,此時(shí),如果對(duì)NSMutableString進(jìn)行修改,也會(huì)導(dǎo)致NSString的值修改,原則上這是不允許的. 如果是copy修飾的NSString對(duì)象,在用NSMutableString給他賦值時(shí),會(huì)進(jìn)行深拷貝,及把內(nèi)容也給拷貝了一份,兩者指向不同的位置,即使改變了NSMutableString的值,NSString的值也不會(huì)改變.
所以用copy是為了安全,防止NSMutableString賦值給NSString時(shí),前者修改引起后者值變化而用的.
- readwrite铸史,readonly鼻疮,assign,retain琳轿,copy判沟,weak ,strong,nonatomic 屬性的作用
答:@property是一個(gè)屬性訪問聲明,擴(kuò)號(hào)內(nèi)支持以下幾個(gè)屬性:
1).getter=getterName崭篡,setter=setterName挪哄,設(shè)置setter與 getter的方法名
2).readwrite,readonly,設(shè)置可供訪問級(jí)別
2).assign琉闪,setter方法直接賦值中燥,不進(jìn)行任何retain操作,為了解決原類型與環(huán)循引用問題塘偎。用于非指針變量。用于基礎(chǔ)數(shù)據(jù)類型 (例如NSInteger)和C數(shù)據(jù)類型(int, float, double, char, 等),另外還有id,其setter方法直接賦值拿霉,不進(jìn)行任何retain操作
3).retain吟秩,setter方法對(duì)參數(shù)進(jìn)行release舊值再retain新值,所有實(shí)現(xiàn)都是這個(gè)順序(CC上有相關(guān)資料)
4).copy绽淘,setter方法進(jìn)行Copy操作涵防,與retain處理流程一樣,先舊值release沪铭,再 Copy出新的對(duì)象壮池,retainCount為1。這是為了減少對(duì)上下文的依賴而引入的機(jī)制杀怠。
5).nonatomic椰憋,決定編譯器生成的setter getter是非原子操作,非原子性訪問,不加同步赔退,多線程并發(fā)訪問會(huì)提高性能橙依。注意,如果不加此屬性硕旗,則默認(rèn)是兩個(gè)訪問方法都為原子型事務(wù)訪問窗骑。鎖被加到所屬對(duì)象實(shí)例級(jí)。
6).weak 用于指針變量,比assign多了一個(gè)功能,當(dāng)對(duì)象消失后自動(dòng)把指針變成nil,由于消息發(fā)送給空對(duì)象表示無操作,這樣有效的避免了崩潰(野指針),為了解決原類型與循環(huán)引用問題
7).strong 用于指針變量,setter方法對(duì)參數(shù)進(jìn)行release舊值再retain新值
OC與JS的交互(iOS與H5混編)
在開發(fā)過程中漆枚,經(jīng)常會(huì)出現(xiàn)需要iOS移動(dòng)端與H5混編的使用場(chǎng)景创译。 iOS中加載html網(wǎng)頁, 可以使用UIWebView或WKWebView. 本篇博客將介紹兩種控件使用過程中如何實(shí)現(xiàn)OC與JS的交互墙基。
UIWebView delegate 協(xié)議方法
//網(wǎng)頁即將開始加載
-(BOOL)webView:(UIWebView)webView shouldStartLoadWithRequest:(NSURLRequest)request navigationType:(UIWebViewNavigationType)navigationType;
//網(wǎng)頁開始加載
- (void)webViewDidStartLoad:(UIWebView *)webView;
//網(wǎng)頁加載完成
- (void)webViewDidFinishLoad:(UIWebView *)webView;
//網(wǎng)頁加載失敗
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
//UIWebView自帶了一個(gè)方法, 可以直接調(diào)用JS代碼(轉(zhuǎn)化為string類型的js代碼)
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
//例如修改id為‘html’標(biāo)簽內(nèi)部的text屬性
[web stringByEvaluatingJavaScriptFromString:@"document.getElementById('html').innerText='修改內(nèi)容'"];
//也可以執(zhí)行多行js代碼
[web stringByEvaluatingJavaScriptFromString:@"vardiv= document.getElementById('html'); div.innerText = '修改內(nèi)容'"];
利用JavaScriptCore實(shí)現(xiàn)交互
JavaScriptCore中類及協(xié)議:
JSContext:給JavaScript提供運(yùn)行的上下文環(huán)境
JSValue:JavaScript和Objective-C數(shù)據(jù)和方法的橋梁
JSManagedValue:管理數(shù)據(jù)和方法的類
JSVirtualMachine:處理線程相關(guān)软族,使用較少
JSExport:這是一個(gè)協(xié)議刷喜,如果采用協(xié)議的方法交互,自己定義的協(xié)議必須遵守此協(xié)議
OC中提供了JavaScriptCore 這個(gè)庫互订,使得OC與js的交互變得更加方便吱肌。
使用方法:
1 加入JavaScriptCore 這個(gè)framework
2 引入頭文件<JavaScriptCore/JavaScriptCore.h>
3 在VC里面加入一個(gè)JSContext屬性
@property (strong, nonatomic) JSContext *context;
JSContext是什么那? 我們看一下api里面的解釋
@interface
@discussion A JSContext is a JavaScript execution environment. All
JavaScript execution takes place within a context, and all JavaScript values
are tied to a context.
大概意思是說:JSContext是一個(gè)JS的執(zhí)行環(huán)境仰禽,所有的JS執(zhí)行都發(fā)生在一個(gè)context里面氮墨, 所有的JS value都綁定到context里面
具體使用
//初始化context
self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//OC調(diào)用JS
//(1)例如html的script中一個(gè)方法
function dolike(a,b,c){
}
//通過OC調(diào)用此方法
NSString * method = @"dolike";
JSValue * function = [self.context objectForKeyedSubscript:method];
//這里面的a,b,c就是OC調(diào)用JS的時(shí)候給JS傳的參數(shù)
[function callWithArguments:@[a,b,c]];
//JS調(diào)用OC
//例如網(wǎng)頁中有個(gè)標(biāo)簽,點(diǎn)擊button的時(shí)候調(diào)用Jump方法, 此處3為傳入的參數(shù)
<button onclick="jump('3')">點(diǎn)我</button>
//當(dāng)點(diǎn)擊網(wǎng)頁中的button的時(shí)候吐葵,觸發(fā)jump方法规揪, 在OC中用如下代碼可以捕捉到j(luò)ump方法, 并拿到JS給我傳的參數(shù)‘3’
self.context[@"jump"] = ^(NSString * str){
//此處 str 值為'3'(js調(diào)用OC時(shí)傳給OC的參數(shù))
};
? 說到WKWebView温峭, 首先要說下WKWebView的優(yōu)勢(shì)
1 更多的支持HTML5的特性
2 官方宣稱的高達(dá)60fps的滾動(dòng)刷新率以及內(nèi)置手勢(shì)
3 將UIWebViewDelegate與UIWebView拆分成了14類與3個(gè)協(xié)議,以前很多不方便實(shí)現(xiàn) 的功能得以實(shí)現(xiàn)
4 Safari相同的JavaScript引擎
5 占用更少的內(nèi)存
類:
WKBackForwardList: 之前訪問過的 web 頁面的列表猛铅,可以通過后退和前進(jìn)動(dòng)作來訪問到。
WKBackForwardListItem: webview 中后退列表里的某一個(gè)網(wǎng)頁凤藏。
WKFrameInfo: 包含一個(gè)網(wǎng)頁的布局信息奸忽。
WKNavigation: 包含一個(gè)網(wǎng)頁的加載進(jìn)度信息。
WKNavigationAction: 包含可能讓網(wǎng)頁導(dǎo)航變化的信息揖庄,用于判斷是否做出導(dǎo)航變化栗菜。
WKNavigationResponse: 包含可能讓網(wǎng)頁導(dǎo)航變化的返回內(nèi)容信息,用于判斷是否做出導(dǎo)航變化蹄梢。
WKPreferences: 概括一個(gè) webview 的偏好設(shè)置疙筹。
WKProcessPool: 表示一個(gè) web 內(nèi)容加載池。
WKUserContentController: 提供使用 JavaScript post 信息和注射 script 的方法禁炒。
WKScriptMessage: 包含網(wǎng)頁發(fā)出的信息而咆。
WKUserScript: 表示可以被網(wǎng)頁接受的用戶腳本。
WKWebViewConfiguration: 初始化 webview 的設(shè)置幕袱。
WKWindowFeatures: 指定加載新網(wǎng)頁時(shí)的窗口屬性暴备。
協(xié)議:
WKNavigationDelegate: 提供了追蹤主窗口網(wǎng)頁加載過程和判斷主窗口和子窗口是否進(jìn)行頁面加載新頁面的相關(guān)方法。
WKScriptMessageHandler: 提供從網(wǎng)頁中收消息的回調(diào)方法凹蜂。
WKUIDelegate: 提供用原生控件顯示網(wǎng)頁的方法回調(diào)馍驯。
?
加載方式:
//方式一
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[self.view addSubview:webView];
//方式二
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc] init];
webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[self.view addSubview:webView];
協(xié)議方法介紹:
pragma mark - WKNavigationDelegate
// 頁面開始加載時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
}
// 當(dāng)內(nèi)容開始返回時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
}
// 頁面加載完成之后調(diào)用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
}
// 頁面加載失敗時(shí)調(diào)用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{
}
// 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求之后調(diào)用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
}
// 在收到響應(yīng)后,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"%@",navigationResponse.response.URL.absoluteString);
//允許跳轉(zhuǎn)
decisionHandler(WKNavigationResponsePolicyAllow);
//不允許跳轉(zhuǎn)
//decisionHandler(WKNavigationResponsePolicyCancel);
}
// 在發(fā)送請(qǐng)求之前玛痊,決定是否跳轉(zhuǎn)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
NSLog(@"%@",navigationAction.request.URL.absoluteString);
//允許跳轉(zhuǎn)
decisionHandler(WKNavigationActionPolicyAllow);
//不允許跳轉(zhuǎn)
decisionHandler(WKNavigationActionPolicyCancel);
}
pragma mark - WKUIDelegate
// 創(chuàng)建一個(gè)新的WebView
(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
return [[WKWebView alloc]init];
}
// 輸入框(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler{
completionHandler(@"http");
}
// 確認(rèn)框(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{
completionHandler(YES);
}
// 警告框(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
NSLog(@"%@",message);
completionHandler();
}
OC與JS的交互
WKWebView
WKWebView的 UIDelegate 提供了三個(gè)協(xié)議方法汰瘫, 可以讓前端很方便的攔截JS的alert, confirm, prompt方法。除此之外擂煞,OC混弥,JS互調(diào)可以按照如下方法。
1 OC 調(diào)用JS
可以使用webkit這個(gè)庫(void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
//例如OC調(diào)用JS的方法 setName
[webView evaluateJavaScript:@"setname('張三')" completionHandler:nil];
//此處 setname為JS定義的方法名, 內(nèi)部 ‘張三’為傳給JS的參數(shù)蝗拿。 如果setname方法需要傳入一個(gè)json或者array等非字符參數(shù)晾捏, 需要用format方法將其轉(zhuǎn)為string類型,在調(diào)用evaluate方法。例如
NSString * para = [NSString stringWithFormat:@"setname('%@')",json];
?
JS調(diào)用OC
此時(shí)就要用到WKScriptMessageHandler了
//首先.m中加入屬性
@property (nonatomic ,strong)WKUserContentController * userCC;
//1 遵循WKScriptMessageHandler協(xié)議
//2 初始化
WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init];
self.wkWebViw = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
[self.wkWebViw loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.webPageUrl]]];
[self.view addSubview:self.wkWebViw];
self.userCC = config.userContentController;
[self.userCC addScriptMessageHandler:self name:@"callOSX"];
//此處相當(dāng)于監(jiān)聽了JS中callFunction這個(gè)方法
[self.userCC addScriptMessageHandler:self name:@"callFunction"];
//當(dāng)JS發(fā)出callFunction這個(gè)方法指令的時(shí)候哀托, WKScriptMessageHandler的協(xié)議方法中我們就會(huì)收到這個(gè)消息
pragma mark WKScriptMessageHandler delegate
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
//這個(gè)回調(diào)里面惦辛, message.name代表方法名(‘本例為 callFunction’), message.body代表JS給我們傳過來的參數(shù)
}
//最后仓手, VC銷毀的時(shí)候一定要把handler移除
-(void)dealloc
{
[_userContentController removeScriptMessageHandlerForName:@"callFunction"];
}
//對(duì)應(yīng)的JS代碼
<button onclick="buttonClick('溫馨提示')">點(diǎn)我</button>
<script>
function buttonClick(string){
//JS調(diào)用OC, 格式如下
//(window.webkit.messageHandlers.Method_Name.postMessage(parameterToOC))
window.webkit.messageHandlers.callFunction.postMessage(string)
}
</script>
2.TableView性能優(yōu)化
1.行高一定要緩存胖齐!
2.不要?jiǎng)討B(tài)創(chuàng)建子視圖
所有的子視圖都預(yù)先創(chuàng)建,如果不需要顯示可以設(shè)置 hidden
3.所有的子視圖都應(yīng)該添加到 contentView 上
4.所有的子視圖都必須指定背景顏色嗽冒,且所有的顏色都不要使用 alpha
5.cell 柵格化
6.異步繪制
UITableView最核心的思想就是UITableViewCell的重用機(jī)制呀伙。簡(jiǎn)單的理解就是:UITableView只會(huì)創(chuàng)建一屏幕(或一屏幕多一點(diǎn))的UITableViewCell,其他都是從中取出來重用的添坊。每當(dāng)Cell滑出屏幕時(shí)剿另,就會(huì)放入到一個(gè)集合(或數(shù)組)中(這里就相當(dāng)于一個(gè)重用池),當(dāng)要顯示某一位置的Cell時(shí)贬蛙,會(huì)先去集合(或數(shù)組)中取雨女,如果有,就直接拿來顯示阳准;如果沒有戚篙,才會(huì)創(chuàng)建。這樣做的好處可想而知溺职,極大的減少了內(nèi)存的開銷。
tableView:cellForRowAtIndexPath:
和tableView:heightForRowAtIndexPath:
UITableView是繼承自UIScrollView的位喂,需要先確定它的contentSize及每個(gè)Cell的位置浪耘,然后才會(huì)把重用的Cell放置到對(duì)應(yīng)的位置。所以事實(shí)上塑崖,UITableView的回調(diào)順序是先多次調(diào)用tableView:heightForRowAtIndexPath:以確定contentSize及Cell的位置七冲,然后才會(huì)調(diào)用tableView:cellForRowAtIndexPath:,從而來顯示在當(dāng)前屏幕的Cell规婆。
思路是把賦值和計(jì)算布局分離澜躺。這樣讓tableView:cellForRowAtIndexPath:方法只負(fù)責(zé)賦值,tableView:heightForRowAtIndexPath:方法只負(fù)責(zé)計(jì)算高度抒蚜。
可以在獲得數(shù)據(jù)后掘鄙,直接先根據(jù)數(shù)據(jù)源計(jì)算出對(duì)應(yīng)的布局,并緩存到數(shù)據(jù)源中嗡髓,這樣在tableView:heightForRowAtIndexPath:方法中就直接返回高度操漠,而不需要每次都計(jì)算了。
UITableView的優(yōu)化主要從三個(gè)方面入手:
1.提前計(jì)算并緩存好高度(布局)饿这,因?yàn)閔eightForRowAtIndexPath:是調(diào)用最頻繁的方法浊伙;
2.異步繪制撞秋,遇到復(fù)雜界面,遇到性能瓶頸時(shí)嚣鄙,可能就是突破口吻贿;
3.滑動(dòng)時(shí)按需加載,這個(gè)在大量圖片展示哑子,網(wǎng)絡(luò)加載的時(shí)候很管用>肆小(SDWebImage已經(jīng)實(shí)現(xiàn)異步加載,配合這條性能杠杠的)赵抢。
正確使用reuseIdentifier來重用Cells
盡量使所有的view opaque剧蹂,包括Cell自身
盡量少用或不用透明圖層
如果Cell內(nèi)現(xiàn)實(shí)的內(nèi)容來自web,使用異步加載烦却,緩存請(qǐng)求結(jié)果
減少subviews的數(shù)量
在heightForRowAtIndexPath:中盡量不使用cellForRowAtIndexPath:阅仔,如果你需要用到它,只用一次然后緩存結(jié)果
盡量少用addView給Cell動(dòng)態(tài)添加View椎工,可以初始化時(shí)就添加伴逸,然后通過hide來控制是否顯示
在使用UITableView的時(shí)候,有的時(shí)候你會(huì)碰到Cell卡頓摩渺,圖片加載慢简烤,使得滑動(dòng)cell時(shí)變得不那么流暢,這些都會(huì)影響用戶體驗(yàn)摇幻,拉低整體app的效果横侦。
? 使用cell重用機(jī)制,盡可能快地返回重用cell實(shí)例 這點(diǎn)大家都應(yīng)該比較清楚绰姻,使用reuse機(jī)制能大幅降低創(chuàng)建cell所帶來的損耗枉侧,這就要各位在UITableView的dataSource中實(shí)現(xiàn)的tableView:cellForRowAtIndexPath:方法。只是有一點(diǎn)狂芋,盡量不要在此時(shí)綁定數(shù)據(jù)榨馁,因?yàn)槟壳霸谄聊簧线€沒有cell,可以在UITableView的delegate方法tableView:willDisplayCell:forRowAtIndexPath:中進(jìn)行數(shù)據(jù)的填充帜矾。 需要說明的是翼虫,你可能會(huì)動(dòng)態(tài)計(jì)算cell高度,但最好是不要選擇Autolayout屡萤。使用Autolayout后珍剑,會(huì)根據(jù)cell的子視圖使得求解的約束也越多,從而降低計(jì)算速度死陆,影響滑動(dòng)時(shí)FPS次慢。所以,為了使tableview平滑滾動(dòng),請(qǐng)使用動(dòng)態(tài)計(jì)算高度迫像,不要選擇Autolayout劈愚。
- cell的subViews的各級(jí)opaque值要設(shè)成YES
opaque用于輔助繪圖系統(tǒng),表示UIView是否透明闻妓。在不透明的情況下菌羽,渲染視圖時(shí)需要快速地渲染,以提高性能由缆。渲染最慢的操作之一是混合(blending)注祖。提高性能的方法是減少混合操作的次數(shù),其實(shí)就是GPU的不合理使用均唉,這是硬件來完成的(混合操作由GPU來執(zhí)行是晨,因?yàn)檫@個(gè)硬件就是用來做混合操作的,當(dāng)然不只是混合)舔箭。 優(yōu)化混合操作的關(guān)鍵點(diǎn)是在平衡CPU和GPU的負(fù)載罩缴。
還有就是cell的layer的shouldRasterize要設(shè)成YES。 - 在繪制字符串時(shí)层扶,盡可能使用drawAtPoint:withFont: , 在繪制圖片箫章,盡量使用drawAtPoint
不要使用更復(fù)雜的drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withFont:(UIFont*)font lineBreakMode:(UILineBreakMode)lineBreakMode;如果要繪制過長(zhǎng)的字符串,建議先截?cái)嗑祷幔缓笫褂胐rawAtPoint:withFont:方法繪制檬寂。
不要使用drawInRect, 因?yàn)樗诶L制過程中對(duì)圖片放縮大小戳表,消耗CPU桶至。
其實(shí),最快的繪制就是你不要做任何繪制匾旭。有時(shí)塞茅,通過 UIGraphicsBeginImageContextWithOptions() 或者 CGBitmapContextCeate() 創(chuàng)建位圖會(huì)顯得更有意義,從位圖上面抓取圖像季率,并設(shè)置為 CALayer 的內(nèi)容。
如果你必須實(shí)現(xiàn) -drawRect:描沟,并且你必須繪制大量的東西飒泻,這將占用時(shí)間。
圖片的話吏廉,你可能會(huì)用位圖來替代: - cell異步加載圖片以及緩存
對(duì)于cell里的圖片采用異步的方式泞遗,加載好后緩存。當(dāng)圖片還沒有請(qǐng)求加載時(shí)席覆,你可以使用默認(rèn)圖片史辙。
一旦你緩存好圖片,使用cell的重用機(jī)制時(shí)就可以從關(guān)聯(lián)好的視圖源里以相應(yīng)的url來找到對(duì)應(yīng)的緩存圖片,緩存大大節(jié)省重復(fù)請(qǐng)求圖片的耗損聊倔。只是你要考慮內(nèi)存級(jí)別的緩存還是磁盤級(jí)別的緩存晦毙,記得使用完畢清緩存哦!(記得減少內(nèi)存級(jí)別的拷貝)
為了防止圖片多次下載耙蔑,我們需要對(duì)圖片做緩存见妒,緩存分為內(nèi)存緩存于沙盒緩存,我們當(dāng)然兩種都要實(shí)現(xiàn)甸陌。
般情況下在我們會(huì)在cellForRow方法里面設(shè)置cell的圖片數(shù)據(jù)源须揣,也就是說如果一個(gè)cell的imageview對(duì)象開啟了一個(gè)下載任務(wù),這個(gè)時(shí)候該cell對(duì)象發(fā)生了重用钱豁,新的image數(shù)據(jù)源會(huì)開啟另外的一個(gè)下載任務(wù)耻卡,由于他們關(guān)聯(lián)的imageview對(duì)象實(shí)際上是同一個(gè)cell實(shí)例的imageview對(duì)象,就會(huì)發(fā)生2個(gè)下載任務(wù)回調(diào)給同一個(gè)imageview對(duì)象牲尺。這個(gè)時(shí)候就有必要做一些處理卵酪,避免回調(diào)發(fā)生時(shí),錯(cuò)誤的image數(shù)據(jù)源刷新了UI秸谢。
在我們向下滑動(dòng)tableview的時(shí)候我們需要手動(dòng)去取消掉下載操作凛澎,當(dāng)用戶停止滑動(dòng),再去執(zhí)行下載操作
如果快速滑下去估蹄,然后又滑回來的話塑煎,圖片是過了一會(huì)才顯示出來,這是因?yàn)榭焖倩瑒?dòng)的時(shí)候臭蚁,舊數(shù)據(jù)源的下載任務(wù)被取消掉了最铁。
異步下載圖片我們用的是NSOperation,并且創(chuàng)建一個(gè)全局的queue來管理下載圖片的操作垮兑。
在把圖片顯示到Cell上之前
先判斷內(nèi)存中(images字典中)有沒有圖片冷尉,
如果有,則取出url對(duì)應(yīng)的圖片來顯示系枪,
如果沒有雀哨,再去沙盒緩存中查看,當(dāng)然存到沙盒中都是NSData私爷。
如果沙盒緩存中有雾棺,我們?nèi)〕鰧?duì)應(yīng)的數(shù)據(jù)給Cell去顯示
如果沙盒中也沒有圖片,我們先顯示占位圖片衬浑。再創(chuàng)建operation去執(zhí)行下載操作了捌浩。
當(dāng)然在創(chuàng)建operation之前,我們要判斷這個(gè)operation操作是否存在
如果沒有下載操作工秩,我們才需要真正的去創(chuàng)建operation執(zhí)行下載尸饺。
創(chuàng)建好下載操作之后應(yīng)該把該操作存放到全局隊(duì)列中去異步執(zhí)行迈螟,同時(shí)吧操作放入operations字典中記錄下來惫叛。
下載完成之后:
把下載好的圖片放到內(nèi)存中预皇、同時(shí)存到沙盒緩存中
執(zhí)行完上面的操作之后回到主線程刷新表格肝劲,
從operations字典中移除下載操作(防止operations越來越大舱殿,同時(shí)保證下載失敗后叹螟,能重新下載)
TableView為什么會(huì)卡抵蚊?
主要由以下原因:
cellForRowAtIndexPath:方法中處理了過多業(yè)務(wù)
tablev
iewCell的subview層級(jí)太復(fù)雜羹应,做了大量透明處理
cell的height動(dòng)態(tài)變化時(shí)計(jì)算方式不對(duì)
優(yōu)化核心思想:UITableViewCell重用機(jī)制
簡(jiǎn)單的理解就是:UITableView只會(huì)創(chuàng)建一屏幕(或一屏幕多一點(diǎn))的UITableViewCell赖捌,其他都是從中取出來重用的。每當(dāng)Cell滑出屏幕時(shí)镀脂,就會(huì)放入到一個(gè)集合(或數(shù)組)中(這里就相當(dāng)于一個(gè)重用池),當(dāng)要顯示某一位置的Cell時(shí)纱兑,會(huì)先去集合(或數(shù)組)中取呀闻,如果有,就直接拿來顯示潜慎;如果沒有捡多,才會(huì)創(chuàng)建。這樣做的好處可想而知铐炫,極大的減少了內(nèi)存的開銷垒手。
Tips:
提前計(jì)算并緩存好高度(布局),因?yàn)閔eightForRowAtIndexPath:是調(diào)用最頻繁的方法倒信;
異步繪制,遇到復(fù)雜界面,參考Facebook的AsyncDisplayKit和YYAsyncLayer異步繪制框架科贬;
緩存圖片(SDWebImage),提前處理好UIImageView圖片的尺寸按需加載而不是加載原圖鳖悠;
計(jì)算等耗時(shí)操作異步處理榜掌,處理完再回主線程更新UI;
圖文混排不定高度采用CoreText排版乘综,緩存Cell高度參考YYKit唐责;
實(shí)現(xiàn)Cell的drawRect:方法直接繪制,減少UIView瘾带,UIImageView鼠哥,UILabel等容器的使用。
Bonus:
正確使用reuseIdentifier來重用Cell看政;
盡量少用或不用透明圖層或View朴恳;
如果Cell內(nèi)現(xiàn)實(shí)的內(nèi)容來自web,使用異步加載允蚣,緩存請(qǐng)求結(jié)果于颖;
減少subviews的數(shù)量在heightForRowAtIndexPath:中盡量不使用cellForRowAtIndexPath:,如果你需要用到它嚷兔,只用一次然后緩存結(jié)果森渐;
盡量少用addView給Cell動(dòng)態(tài)添加View,可以初始化時(shí)就添加冒晰,然后通過hide來控制是否顯示同衣;
固定高度不要實(shí)現(xiàn)heightForRowAtIndexPath:方法。
1.UITableViewCell里不要添加太多subview壶运,最好只添加一個(gè)cellview耐齐。
2.UITableViewCell 上的子View的opaque屬性設(shè)為YES。其實(shí)默認(rèn)也是不透明。UITableViewCell盡量不要包含透明的子View埠况。
3.在cellview里耸携,重寫drawRect函數(shù)繪制UITableViewCell的內(nèi)容。
4.在繪制字符串時(shí)辕翰,盡可能使用drawAtPoint: withFont:夺衍,而不要使用更復(fù)雜的drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode; 如果要繪制過長(zhǎng)的字符串,建議自己先截?cái)嘞裁缓笫褂胐rawAtPoint: withFont:方法繪制刷后。
5.在繪制圖片時(shí),盡量使用drawAtPoint渊抄,而不要使用drawInRect颅崩。drawInRect如果在繪制過程中對(duì)圖片進(jìn)行放縮柳爽,會(huì)特別消耗CPU埃仪。
6.如果繪制cell過程中腾降,需要下載cell中的圖片职员,建議在繪制cell一段時(shí)間后再開啟圖片下載任務(wù)根盒。譬如先畫一個(gè)默認(rèn)圖片箭启,然后在0.5S后開始下載本cell的圖片越走。
7.即使下載cell 圖片是在子線程中進(jìn)行缓呛,在繪制cell過程中催享,也不能開啟過多的子線程。最好只有一個(gè)下載圖片的子線程在活動(dòng)哟绊。否則也會(huì)影響UITableViewCell的繪制因妙,因而影響了UITableViewCell的滑動(dòng)速度。(建議結(jié)合使用NSOpeartion和NSOperationQueue來下載圖片票髓,如果想盡可能找的下載圖片攀涵,可以把[self.queuesetMaxConcurrentOperationCount:4];)
8.最好自己寫一個(gè)cache,用來緩存UITableView中的UITableViewCell洽沟,這樣在整個(gè)UITableView的生命周期里以故,一個(gè)cell只需繪制一次,并且如果發(fā)生內(nèi)存不足裆操,也可以有效的釋放掉緩存的cell怒详。
9.不要將tableview的背景顏色設(shè)置成一個(gè)圖片。這回嚴(yán)重影響UITableView的滑動(dòng)速度踪区。在限時(shí)免費(fèi)搜索里昆烁,我曾經(jīng)翻過一個(gè)錯(cuò)誤:self.tableView_.backgroundColor = [UIColorcolorWithPatternImage:[UIImageimageNamed:@"background.png"]]; 通過這種方式設(shè)置UITableView的背景顏色會(huì)嚴(yán)重影響UTIableView的滑動(dòng)流暢性。修改成self.tableView_.backgroundColor = [UIColor clearColor];之后缎岗,fps從43上升到60左右善玫。滑動(dòng)比較流暢。
10.cell的行高不是固定值茅郎,需要計(jì)算蜗元,則要盡可能緩存行高值,避免重復(fù)計(jì)算行高系冗。這里指的是UITableViewDelegate里的行高函數(shù)奕扣。
如果做到以上10點(diǎn),則UITableView 滑動(dòng)的fps可以達(dá)到60 fps掌敬」叨梗滑動(dòng)非常順暢
UITableView最核心的思想就是UITableViewCell的重用機(jī)制。簡(jiǎn)單的理解就是:UITableView只會(huì)創(chuàng)建一屏幕(或一屏幕多一點(diǎn))的UITableViewCell奔害,其他都是從中取出來重用的楷兽。每當(dāng)Cell滑出屏幕時(shí),就會(huì)放入到一個(gè)集合(或數(shù)組)中(這里就相當(dāng)于一個(gè)重用池)华临,當(dāng)要顯示某一位置的Cell時(shí)芯杀,會(huì)先去集合(或數(shù)組)中取,如果有雅潭,就直接拿來顯示揭厚;如果沒有,才會(huì)創(chuàng)建扶供。這樣做的好處可想而知筛圆,極大的減少了內(nèi)存的開銷。
知道UITableViewCell的重用原理后椿浓,我們來看看UITableView的回調(diào)方法太援。UITableView最主要的兩個(gè)回調(diào)方法是tableView:cellForRowAtIndexPath:和tableView:heightForRowAtIndexPath:。理想上我們是會(huì)認(rèn)為UITableView會(huì)先調(diào)用前者扳碍,再調(diào)用后者粉寞,因?yàn)檫@和我們創(chuàng)建控件的思路是一樣的,先創(chuàng)建它左腔,再設(shè)置它的布局唧垦。但實(shí)際上卻并非如此,我們都知道液样,UITableView是繼承自UIScrollView的振亮,需要先確定它的contentSize及每個(gè)Cell的位置,然后才會(huì)把重用的Cell放置到對(duì)應(yīng)的位置鞭莽。所以事實(shí)上坊秸,UITableView的回調(diào)順序是先多次調(diào)用tableView:heightForRowAtIndexPath:以確定contentSize及Cell的位置,然后才會(huì)調(diào)用tableView:cellForRowAtIndexPath:澎怒,從而來顯示在當(dāng)前屏幕的Cell褒搔。
舉個(gè)例子來說:如果現(xiàn)在要顯示100個(gè)Cell,當(dāng)前屏幕顯示5個(gè)。那么刷新(reload)UITableView時(shí)星瘾,UITableView會(huì)先調(diào)用100次tableView:heightForRowAtIndexPath:方法走孽,然后調(diào)用5次tableView:cellForRowAtIndexPath:方法;滾動(dòng)屏幕時(shí)琳状,每當(dāng)Cell滾入屏幕磕瓷,都會(huì)調(diào)用一次tableView:heightForRowAtIndexPath:、tableView:cellForRowAtIndexPath:方法念逞。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ContacterTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ContacterTableCell"];
if (!cell) {
cell = (ContacterTableCell *)[[[NSBundle mainBundle] loadNibNamed:@"ContacterTableCell" owner:self options:nil] lastObject];
}
NSDictionary *dict = self.dataList[indexPath.row];
[cell setContentInfo:dict];
return cell;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
return cell.frame.size.height;
}
這樣寫困食,在Cell賦值內(nèi)容的時(shí)候,會(huì)根據(jù)內(nèi)容設(shè)置布局翎承,當(dāng)然也就可以知道Cell的高度硕盹,想想如果1000行,那就會(huì)調(diào)用1000+頁面Cell個(gè)數(shù)次tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法叨咖,而我們對(duì)Cell的處理操作瘩例,都是在這個(gè)方法里的!什么賦值芒澜、布局等等。開銷自然很大创淡,這種方案Pass痴晦。。琳彩。改進(jìn)代碼誊酌。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *dict = self.dataList[indexPath.row];
return [ContacterTableCell cellHeightOfInfo:dict];
}
思路是把賦值和計(jì)算布局分離。這樣讓tableView:cellForRowAtIndexPath:方法只負(fù)責(zé)賦值露乏,tableView:heightForRowAtIndexPath:方法只負(fù)責(zé)計(jì)算高度碧浊。注意:兩個(gè)方法盡可能的各司其職,不要重疊代碼瘟仿!兩者都需要盡可能的簡(jiǎn)單易算箱锐。Run一下,會(huì)發(fā)現(xiàn)UITableView滾動(dòng)流暢了很多劳较。驹止。。
基于上面的實(shí)現(xiàn)思路观蜗,我們可以在獲得數(shù)據(jù)后臊恋,直接先根據(jù)數(shù)據(jù)源計(jì)算出對(duì)應(yīng)的布局,并緩存到數(shù)據(jù)源中墓捻,這樣在tableView:heightForRowAtIndexPath:方法中就直接返回高度抖仅,而不需要每次都計(jì)算了。
其實(shí)上面的改進(jìn)方法并不是最佳方案,但基本能滿足簡(jiǎn)單的界面撤卢!記得開頭我的任務(wù)嗎环凿?像朋友圈那樣的圖文混排,這種方案還是扛不住的凸丸!我們需要進(jìn)入更深層次的探究:自定義Cell的繪制拷邢。
我們?cè)贑ell上添加系統(tǒng)控件的時(shí)候,實(shí)質(zhì)上系統(tǒng)都需要調(diào)用底層的接口進(jìn)行繪制屎慢,當(dāng)我們大量添加控件時(shí)瞭稼,對(duì)資源的開銷也會(huì)很大,所以我們可以索性直接繪制腻惠,提高效率环肘。是不是說的很抽象?廢話不多說集灌,直接上代碼:
首先需要給自定義的Cell添加draw方法悔雹,(當(dāng)然也可以重寫drawRect)然后在方法體中實(shí)現(xiàn):
滾動(dòng)很快時(shí),只加載目標(biāo)范圍內(nèi)的Cell欣喧,這樣按需加載腌零,極大的提高流暢度。
寫了這么多唆阿,也差不多該來個(gè)總結(jié)了益涧!UITableView的優(yōu)化主要從三個(gè)方面入手:
提前計(jì)算并緩存好高度(布局),因?yàn)閔eightForRowAtIndexPath:是調(diào)用最頻繁的方法驯鳖;
異步繪制闲询,遇到復(fù)雜界面,遇到性能瓶頸時(shí)浅辙,可能就是突破口扭弧;
滑動(dòng)時(shí)按需加載,這個(gè)在大量圖片展示记舆,網(wǎng)絡(luò)加載的時(shí)候很管用8肽怼(SDWebImage已經(jīng)實(shí)現(xiàn)異步加載,配合這條性能杠杠的)泽腮。
除了上面最主要的三個(gè)方面外泊愧,還有很多幾乎大伙都很熟知的優(yōu)化點(diǎn):
正確使用reuseIdentifier來重用Cells
盡量使所有的view opaque,包括Cell自身
盡量少用或不用透明圖層
如果Cell內(nèi)現(xiàn)實(shí)的內(nèi)容來自web盛正,使用異步加載删咱,緩存請(qǐng)求結(jié)果
減少subviews的數(shù)量
在heightForRowAtIndexPath:中盡量不使用cellForRowAtIndexPath:,如果你需要用到它豪筝,只用一次然后緩存結(jié)果
盡量少用addView給Cell動(dòng)態(tài)添加View痰滋,可以初始化時(shí)就添加摘能,然后通過hide來控制是否顯示
3.UITableview
1> 自定義高度
1.1>新建一個(gè)繼承自UITableViewCell的類
1.2>重寫initWithStyle:reuseIdentifier:方法
1.3>添加所有需要顯示的子控件(不需要設(shè)置子控件的數(shù)據(jù)和frame, 子控件要添加到contentView中)
1.4>進(jìn)行子控件一次性的屬性設(shè)置(有些屬性只需要設(shè)置一次, 比如字體\固定的圖片)
1.5>提供2個(gè)模型
數(shù)據(jù)模型: 存放文字?jǐn)?shù)據(jù)\圖片數(shù)據(jù)
frame模型: 存放數(shù)據(jù)模型\所有子控件的frame\cell的高度
1.6>cell擁有一個(gè)frame模型(不要直接擁有數(shù)據(jù)模型)
1.7>重寫frame模型屬性的setter方法: 在這個(gè)方法中設(shè)置子控件的顯示數(shù)據(jù)和frame
2> 自定義高度原理
A 手動(dòng)計(jì)算
1> 由于heightForRow比cellForRow方法先調(diào)用,創(chuàng)建frame模型包含微博模型敲街,重寫微博模型賦值set方法团搞,提前計(jì)算cell子控件的frame并保存,heightForRow方法中取出frame模型中保存的高度多艇,實(shí)現(xiàn)自定義高度cell
2> 設(shè)置最大尺寸逻恐、文本屬性,根據(jù)文本內(nèi)容計(jì)算正文內(nèi)容展示尺寸
3> cellForRow中創(chuàng)建自定義cell包含frame屬性峻黍,重寫frame屬性set方法創(chuàng)建cell子控件并賦值frame模型保存的子控件尺寸
B. 自動(dòng)計(jì)算
1> 首先設(shè)置行高使用autolayout自動(dòng)計(jì)算并預(yù)估高度
2> 在stroboard中對(duì)cell內(nèi)容進(jìn)行自動(dòng)布局复隆,注意設(shè)置圖片距離底部約束,cellForRow中創(chuàng)建storyboard中對(duì)應(yīng)標(biāo)記的自定義cell
3> 由于正文內(nèi)容的不確定性姆涩,設(shè)置label多行挽拂,拖線圖片高度約束,根據(jù)圖片有無骨饿,設(shè)置代碼設(shè)置高度約束
老生常談之UITableView的性能優(yōu)化
1亏栈、cell復(fù)用 復(fù)用很簡(jiǎn)單,這或許是所有iOS開發(fā)者最為熟知的一個(gè)優(yōu)化內(nèi)容宏赘,如下代碼:
1
2
3
4
5
6
7
8
9
10
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *Identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
return cell;
}
但是赵誓,這樣重用就完美了嗎蕊苗?
我們經(jīng)常在注意cellForRowAtIndexPath:中為每一個(gè)cell綁定數(shù)據(jù)痹仙,實(shí)際上在調(diào)用cellForRowAtIndexPath:的時(shí)候cell還沒有被顯示出來取逾,為了提高效率我們應(yīng)該把數(shù)據(jù)綁定的操作放在cell顯示出來后再執(zhí)行,可以在tableView:willDisplayCell:forRowAtIndexPath:(以后簡(jiǎn)稱willDisplayCell)方法中綁定數(shù)據(jù)箕母。
注意willDisplayCell在cell 在tableview展示之前就會(huì)調(diào)用储藐,此時(shí)cell實(shí)例已經(jīng)生成俱济,所以不能更改cell的結(jié)構(gòu)嘶是,只能是改動(dòng)cell上的UI的一些屬性(例如label的內(nèi)容等)。
2蛛碌、cell高度的計(jì)算
這邊我們分為兩種cell聂喇,一種是定高的cell,另外一種是動(dòng)態(tài)高度的cell蔚携。
(1)定高的cell希太,應(yīng)該采用如下方式:
self.tableView.rowHeight = 88;
這個(gè)方法指定了所有cell高度都是88的tableview,rowHeight默認(rèn)的值是44酝蜒,所以一個(gè)空的TableView會(huì)顯示成這個(gè)樣子誊辉。對(duì)于定高cell,直接采用上面方式給定高度亡脑,不需要實(shí)現(xiàn)tableView:heightForRowAtIndexPath:以節(jié)省不必要的計(jì)算和開銷堕澄。
(2)動(dòng)態(tài)高度的cell
我們需要實(shí)現(xiàn)它的代理邀跃,來給出高度:
-(CGFloat)tableView:(UITableView *)tableViewheightForRowAtIndexPath:(NSIndexPath *)indexPath{
// return xxx
}
這個(gè)代理方法實(shí)現(xiàn)后,上面的rowHeight的設(shè)置將會(huì)變成無效蛙紫。在這個(gè)方法中拍屑,我們需要提高cell高度的計(jì)算效率,來節(jié)省時(shí)間坑傅。
自從iOS8之后有了self-sizing cell的概念僵驰,cell可以自己算出高度,使用self-sizing cell需要滿足以下三個(gè)條件:
(1)使用Autolayout進(jìn)行UI布局約束(要求cell.contentView的四條邊都與內(nèi)部元素有約束關(guān)系)唁毒。
(2)指定TableView的estimatedRowHeight屬性的默認(rèn)值。
(3)指定TableView的rowHeight屬性為UITableViewAutomaticDimension。
1
2
3
4
- (void)viewDidload {
self.myTableView.estimatedRowHeight = 44.0;
self.myTableView.rowHeight = UITableViewAutomaticDimension;
}
除了提高cell高度的計(jì)算效率之外,對(duì)于已經(jīng)計(jì)算出的高度涩拙,我們需要進(jìn)行緩存台谍,對(duì)于已經(jīng)計(jì)算過的高度风纠,沒有必要進(jìn)行計(jì)算第二次觅丰。
3鼠锈、渲染
為了保證TableView的流暢,當(dāng)快速滑動(dòng)的時(shí)候访惜,cell必須被快速的渲染出來嘹履。所以cell渲染的速度必須快。如何提高cell的渲染速度呢债热?
(1)當(dāng)有圖像時(shí)砾嫉,預(yù)渲染圖像,在bitmap context先將其畫一遍窒篱,導(dǎo)出成UIImage對(duì)象焕刮,然后再繪制到屏幕,這會(huì)大大提高渲染速度墙杯。具體內(nèi)容可以自行查找“利用預(yù)渲染加速顯示iOS圖像”相關(guān)資料济锄。
(2)渲染最好時(shí)的操作之一就是混合(blending)了,所以我們不要使用透明背景,將cell的opaque值設(shè)為Yes霍转,背景色不要使用clearColor荐绝,盡量不要使用陰影漸變等
(3)由于混合操作是使用GPU來執(zhí)行,我們可以用CPU來渲染避消,這樣混合操作就不再執(zhí)行低滩。可以在UIView的drawRect方法中自定義繪制岩喷。
4恕沫、減少視圖的數(shù)目
我們?cè)赾ell上添加系統(tǒng)控件的時(shí)候,實(shí)際上系統(tǒng)都會(huì)調(diào)用底層的接口進(jìn)行繪制纱意,大量添加控件時(shí)婶溯,會(huì)消耗很大的資源并且也會(huì)影響渲染的性能。當(dāng)使用默認(rèn)的UITableViewCell并且在它的ContentView上面添加控件時(shí)會(huì)相當(dāng)消耗性能。所以目前最佳的方法還是繼承UITableViewCell迄委,并重寫drawRect方法褐筛。
5、減少多余的繪制操作
在實(shí)現(xiàn)drawRect方法的時(shí)候叙身,它的參數(shù)rect就是我們需要繪制的區(qū)域渔扎,在rect范圍之外的區(qū)域我們不需要進(jìn)行繪制,否則會(huì)消耗相當(dāng)大的資源信轿。
6晃痴、不要給cell動(dòng)態(tài)添加subView
在初始化cell的時(shí)候就將所有需要展示的添加完畢,然后根據(jù)需要來設(shè)置hide屬性顯示和隱藏财忽。
7倘核、異步化UI,不要阻塞主線程
我們時(shí)常會(huì)看到這樣一個(gè)現(xiàn)象即彪,就是加載時(shí)整個(gè)頁面卡住不動(dòng)笤虫,怎么點(diǎn)都沒用,仿佛死機(jī)了一般祖凫。原因是主線程被阻塞了琼蚯。所以對(duì)于網(wǎng)路數(shù)據(jù)的請(qǐng)求或者圖片的加載,我們可以開啟多線程惠况,將耗時(shí)操作放到子線程中進(jìn)行遭庶,異步化操作。這個(gè)或許每個(gè)iOS開發(fā)者都知道的知識(shí)稠屠,不必多講峦睡。
8、滑動(dòng)時(shí)按需加載對(duì)應(yīng)的內(nèi)容
如果目標(biāo)行與當(dāng)前行相差超過指定行數(shù)权埠,只在目標(biāo)滾動(dòng)范圍的前后指定3行加載榨了。
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollViewwithVelocity:(CGPoint)velocitytargetContentOffset:(inoutCGPoint *)targetContentOffset{
NSIndexPath *ip=[selfindexPathForRowAtPoint:CGPointMake(0,targetContentOffset->y)];
NSIndexPath *cip=[[selfindexPathsForVisibleRows]firstObject];
NSIntegerskipCount=8;
if(labs(cip.row-ip.row)>skipCount){
NSArray *temp=[selfindexPathsForRowsInRect:CGRectMake(0,targetContentOffset->y,self.width,self.height)];
NSMutableArray *arr=[NSMutableArrayarrayWithArray:temp];
if(velocity.y<0){
NSIndexPath *indexPath=[templastObject];
if(indexPath.row+33){
[arraddObject:[NSIndexPathindexPathForRow:indexPath.row-3inSection:0]];
[arraddObject:[NSIndexPathindexPathForRow:indexPath.row-2inSection:0]];
[arraddObject:[NSIndexPathindexPathForRow:indexPath.row-1inSection:0]];
}
}
[needLoadArraddObjectsFromArray:arr];
}
}
記得在tableView:cellForRowAtIndexPath:方法中加入判斷:
1
2
3
4
if(needLoadArr.count>0&&[needLoadArrindexOfObject:indexPath]==NSNotFound){
[cellclear];
return;
}
滑動(dòng)很快時(shí),只加載目標(biāo)范圍內(nèi)的cell攘蔽,這樣按需加載(配合SDWebImage)龙屉,極大提高流暢度。
9满俗、最后想談下離屏渲染的問題:
9.1转捕、下面的情況或操作會(huì)引發(fā)離屏渲染:
? 為圖層設(shè)置遮罩(layer.mask)
? 將圖層的layer.masksToBounds / view.clipsToBounds屬性設(shè)置為true
? 將圖層layer.allowsGroupOpacity屬性設(shè)置為YES和layer.opacity小于1.0
? 為圖層設(shè)置陰影(layer.shadow *)。
? 為圖層設(shè)置layer.shouldRasterize=true
? 具有l(wèi)ayer.cornerRadius唆垃,layer.edgeAntialiasingMask五芝,layer.allowsEdgeAntialiasing的圖層
? 文本(任何種類,包括UILabel辕万,CATextLayer枢步,Core Text等)沉删。
? 使用CGContext在drawRect :方法中繪制大部分情況下會(huì)導(dǎo)致離屏渲染,甚至僅僅是一個(gè)空的實(shí)現(xiàn)
9.2醉途、優(yōu)化方案
官方對(duì)離屏渲染產(chǎn)生性能問題也進(jìn)行了優(yōu)化:
iOS 9.0 之前UIimageView跟UIButton設(shè)置圓角都會(huì)觸發(fā)離屏渲染矾瑰。
iOS 9.0 之后UIButton設(shè)置圓角會(huì)觸發(fā)離屏渲染,而UIImageView里png圖片設(shè)置圓角不會(huì)觸發(fā)離屏渲染了结蟋,如果設(shè)置其他陰影效果之類的還是會(huì)觸發(fā)離屏渲染的脯倚。
(1)圓角優(yōu)化
在APP開發(fā)中渔彰,圓角圖片還是經(jīng)常出現(xiàn)的嵌屎。如果一個(gè)界面中只有少量圓角圖片或許對(duì)性能沒有非常大的影響,但是當(dāng)圓角圖片比較多的時(shí)候就會(huì)APP性能產(chǎn)生明顯的影響恍涂。
我們?cè)O(shè)置圓角一般通過如下方式:
imageView.layer.cornerRadius=CGFloat(10);
imageView.layer.masksToBounds=YES;
這樣處理的渲染機(jī)制是GPU在當(dāng)前屏幕緩沖區(qū)外新開辟一個(gè)渲染緩沖區(qū)進(jìn)行工作宝惰,也就是離屏渲染,這會(huì)給我們帶來額外的性能損耗再沧,如果這樣的圓角操作達(dá)到一定數(shù)量尼夺,會(huì)觸發(fā)緩沖區(qū)的頻繁合并和上下文的的頻繁切換,性能的代價(jià)會(huì)宏觀地表現(xiàn)在用戶體驗(yàn)上——掉幀炒瘸。
優(yōu)化方案1:使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個(gè)圓角
1
2
3
4
5
6
7
8
9
10
11
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
imageView.image = [UIImage imageNamed:@"myImg"];
//開始對(duì)imageView進(jìn)行畫圖
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
//使用貝塞爾曲線畫出一個(gè)圓形圖
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:imageView.frame.size.width] addClip];
[imageView drawRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
//結(jié)束畫圖
UIGraphicsEndImageContext();
[self.view addSubview:imageView];
優(yōu)化方案2:使用CAShapeLayer和UIBezierPath設(shè)置圓角
1
2
3
4
5
6
7
8
9
10
UIImageView *imageView=[[UIImageViewalloc]initWithFrame:CGRectMake(100,100,100,100)];
imageView.image=[UIImageimageNamed:@"myImg"];
UIBezierPath *maskPath=[UIBezierPathbezierPathWithRoundedRect:imageView.boundsbyRoundingCorners:UIRectCornerAllCornerscornerRadii:imageView.bounds.size];
CAShapeLayer *maskLayer=[[CAShapeLayeralloc]init];
//設(shè)置大小
maskLayer.frame=imageView.bounds;
//設(shè)置圖形樣子
maskLayer.path=maskPath.CGPath;
imageView.layer.mask=maskLayer;
[self.viewaddSubview:imageView];
對(duì)于方案2需要解釋的是:
? CAShapeLayer繼承于CALayer,可以使用CALayer的所有屬性值淤堵;
? CAShapeLayer需要貝塞爾曲線配合使用才有意義(也就是說才有效果)
? 使用CAShapeLayer(屬于CoreAnimation)與貝塞爾曲線可以實(shí)現(xiàn)不在view的drawRect(繼承于CoreGraphics走的是CPU,消耗的性能較大)方法中畫出一些想要的圖形
? CAShapeLayer動(dòng)畫渲染直接提交到手機(jī)的GPU當(dāng)中,相較于view的drawRect方法使用CPU渲染而言顷扩,其效率極高拐邪,能大大優(yōu)化內(nèi)存使用情況。
總的來說就是用CAShapeLayer的內(nèi)存消耗少隘截,渲染速度快扎阶,建議使用優(yōu)化方案2。
(2)shadow優(yōu)化
對(duì)于shadow婶芭,如果圖層是個(gè)簡(jiǎn)單的幾何圖形或者圓角圖形东臀,我們可以通過設(shè)置shadowPath來優(yōu)化性能,能大幅提高性能犀农。示例如下:
imageView.layer.shadowColor=[UIColorgrayColor].CGColor;
imageView.layer.shadowOpacity=1.0;
imageView.layer.shadowRadius=2.0;
UIBezierPath *path=[UIBezierPathbezierPathWithRect:imageView.frame];
imageView.layer.shadowPath=path.CGPath;
我們還可以通過設(shè)置shouldRasterize屬性值為YES來強(qiáng)制開啟離屏渲染惰赋。其實(shí)就是光柵化(Rasterization)。既然離屏渲染這么不好呵哨,為什么我們還要強(qiáng)制開啟呢谤逼?當(dāng)一個(gè)圖像混合了多個(gè)圖層,每次移動(dòng)時(shí)仇穗,每一幀都要重新合成這些圖層流部,十分消耗性能。當(dāng)我們開啟光柵化后纹坐,會(huì)在首次產(chǎn)生一個(gè)位圖緩存枝冀,當(dāng)再次使用時(shí)候就會(huì)復(fù)用這個(gè)緩存舞丛。但是如果圖層發(fā)生改變的時(shí)候就會(huì)重新產(chǎn)生位圖緩存。所以這個(gè)功能一般不能用于UITableViewCell中果漾,cell的復(fù)用反而降低了性能球切。最好用于圖層較多的靜態(tài)內(nèi)容的圖形。而且產(chǎn)生的位圖緩存的大小是有限制的绒障,一般是2.5個(gè)屏幕尺寸吨凑。在100ms之內(nèi)不使用這個(gè)緩存,緩存也會(huì)被刪除户辱。所以我們要根據(jù)使用場(chǎng)景而定鸵钝。
(3)其他的一些優(yōu)化建議
? 當(dāng)我們需要圓角效果時(shí),可以使用一張中間透明圖片蒙上去
? 使用ShadowPath指定layer陰影效果路徑
? 使用異步進(jìn)行l(wèi)ayer渲染(Facebook開源的異步繪制框架AsyncDisplayKit)
? 設(shè)置layer的opaque值為YES庐镐,減少復(fù)雜圖層合成
? 盡量使用不包含透明(alpha)通道的圖片資源
? 盡量設(shè)置layer的大小值為整形值
? 直接讓美工把圖片切成圓角進(jìn)行顯示恩商,這是效率最高的一種方案
? 很多情況下用戶上傳圖片進(jìn)行顯示,可以讓服務(wù)端處理圓角
? 使用代碼手動(dòng)生成圓角Image設(shè)置到要顯示的View上必逆,利用UIBezierPath(CoreGraphics框架)畫出來圓角圖片
(4)Core Animation工具檢測(cè)離屏渲染
對(duì)于離屏渲染的檢測(cè)怠堪,蘋果為我們提供了一個(gè)測(cè)試工具Core Animation∶迹可以在Xcode->Open Develeper Tools->Instruments中找到粟矿,如下圖:
Core Animation工具用來監(jiān)測(cè)Core Animation性能,提供可見的FPS值损拢,并且提供幾個(gè)選項(xiàng)來測(cè)量渲染性能陌粹。如下圖:
下面我們來說明每個(gè)選項(xiàng)的功能:
Color Blended Layers:這個(gè)選項(xiàng)如果勾選,你能看到哪個(gè)layer是透明的探橱,GPU正在做混合計(jì)算申屹。顯示紅色的就是透明的衡查,綠色就是不透明的签餐。
Color Hits Green and Misses Red:如果勾選這個(gè)選項(xiàng),且當(dāng)我們代碼中有設(shè)置shouldRasterize為YES瞻想,那么紅色代表沒有復(fù)用離屏渲染的緩存胞枕,綠色則表示復(fù)用了緩存杆煞。我們當(dāng)然希望能夠復(fù)用。
Color Copied Images:按照官方的說法腐泻,當(dāng)圖片的顏色格式GPU不支持的時(shí)候决乎,Core Animation會(huì)
拷貝一份數(shù)據(jù)讓CPU進(jìn)行轉(zhuǎn)化。例如從網(wǎng)絡(luò)上下載了TIFF格式的圖片派桩,則需要CPU進(jìn)行轉(zhuǎn)化构诚,這個(gè)區(qū)域會(huì)顯示成藍(lán)色。還有一種情況會(huì)觸發(fā)Core Animation的copy方法铆惑,就是字節(jié)不對(duì)齊的時(shí)候范嘱。如下圖:
Color Immediately:默認(rèn)情況下Core Animation工具以每毫秒10次的頻率更新圖層調(diào)試顏色送膳,如果勾選這個(gè)選項(xiàng)則移除10ms的延遲。對(duì)某些情況需要這樣丑蛤,但是有可能影響正常幀數(shù)的測(cè)試叠聋。
Color Misaligned Images:勾選此項(xiàng),如果圖片需要縮放則標(biāo)記為黃色受裹,如果沒有像素對(duì)齊則標(biāo)記為紫色碌补。像素對(duì)齊我們已經(jīng)在上面有所介紹。
Color Offscreen-Rendered Yellow:用來檢測(cè)離屏渲染的棉饶,如果顯示黃色厦章,表示有離屏渲染。當(dāng)然還要結(jié)合Color Hits Green and Misses Red來看砰盐,是否復(fù)用了緩存闷袒。
Color OpenGL Fast Path Blue:這個(gè)選項(xiàng)對(duì)那些使用OpenGL的圖層才有用坑律,像是GLKView或者 CAEAGLLayer岩梳,如果不顯示藍(lán)色則表示使用了CPU渲染,繪制在了屏幕外晃择,顯示藍(lán)色表示正常冀值。
Flash Updated Regions:當(dāng)對(duì)圖層重繪的時(shí)候回顯示黃色,如果頻繁發(fā)生則會(huì)影響性能宫屠×辛疲可以用增加緩存來增強(qiáng)性能。
以上就是本人的一些總結(jié)浪蹂,當(dāng)然對(duì)于UITableView的性能優(yōu)化抵栈,網(wǎng)上有很多相關(guān)的資料。如果有什么不同的觀點(diǎn)坤次,歡迎大家補(bǔ)充古劲。
1.注冊(cè)成為環(huán)信開發(fā)者
2.在開發(fā)者后臺(tái)創(chuàng)建APP,獲取key
3.下載SDK,獲取DEMO
4.集成SDK
如果項(xiàng)目中使用-ObjC有沖突,可以添加-force_load來解決
SDK不支持bitcode,向Build Settings → Linking → Enable Bitcode中設(shè)置NO缰猴。
5.SDK同步/異步方法區(qū)分:
SDK中产艾,大部分與網(wǎng)絡(luò)有關(guān)的操作,提供的是同步方法(注:同步方法會(huì)阻塞主線程,需要用戶自己創(chuàng)建異步線程執(zhí)行;帶有async的方法為異步方法)
6.初始化SDK
AppKey: 區(qū)別app的標(biāo)識(shí)滑绒,開發(fā)者注冊(cè)及管理后臺(tái)
apnsCertName: iOS中推送證書名稱闷堡。制作與上傳推送證書
環(huán)信為im部分提供了apns推送功能,如果您要使用疑故,請(qǐng)?zhí)D(zhuǎn)到apns離線推送
7.注冊(cè)
開發(fā)注冊(cè)和授權(quán)注冊(cè)
只有開放注冊(cè)時(shí)杠览,才可以客戶端注冊(cè),開放注冊(cè)主要是測(cè)試使用纵势。
授權(quán)注冊(cè)的流程應(yīng)該是您服務(wù)器通過環(huán)信提供的rest api注冊(cè)踱阿,之后保存到您的服務(wù)器或返回給客戶端误续。
8.登錄
9.自動(dòng)登錄
自動(dòng)登錄在以下幾種情況下會(huì)被取消
1)用戶調(diào)用了SDK的登出動(dòng)作;
2)用戶在別的設(shè)備上更改了密碼, 導(dǎo)致此設(shè)備上自動(dòng)登陸失敗;
3)用戶的賬號(hào)被從服務(wù)器端刪除;
4)用戶從另一個(gè)設(shè)備登錄,把當(dāng)前設(shè)備上登陸的用戶踢出.
在您調(diào)用登錄方法前扫茅,應(yīng)該先判斷是否設(shè)置了自動(dòng)登錄蹋嵌,如果設(shè)置了,則不需要您再調(diào)用
10.重連
當(dāng)?shù)艟€時(shí)葫隙,IOS SDK會(huì)自動(dòng)重連栽烂,只需要監(jiān)聽重連相關(guān)的回調(diào),無需進(jìn)行任何操作恋脚。
11.退出登錄
(1)主動(dòng)退出登錄:調(diào)用SDK的退出接口腺办;
(2)被動(dòng)退出登錄:正在登陸的賬號(hào)在另一臺(tái)設(shè)備上登陸; 2糟描、 正在登陸的賬號(hào)被從服務(wù)器端刪除怀喉。
12.好友管理
環(huán)信不是好友也可以聊天,不推薦使用環(huán)信的好友機(jī)制船响。如果你有自己的服務(wù)器或好友關(guān)系躬拢,請(qǐng)自己維護(hù)好友關(guān)系。
(1) 從服務(wù)器獲取所有的好友
(2)從數(shù)據(jù)庫獲取所有的好友
13.添加好友
如果您已經(jīng)發(fā)過见间,并且對(duì)方?jīng)]有處理聊闯,您將不能再次發(fā)送
14.實(shí)時(shí)通話管理
發(fā)起實(shí)時(shí)通話
被叫方同意實(shí)時(shí)通話
結(jié)束實(shí)時(shí)通話
藍(lán)牙
在iOS中,藍(lán)牙是基于4.0標(biāo)準(zhǔn)的米诉,設(shè)備間低功耗通信菱蔬。
其中Peripheral外設(shè)相當(dāng)于Socket編程中的Server服務(wù)端,Central中心相當(dāng)于Client客戶端(ps吐槽下史侣,Central中心拴泌,作為服務(wù)端,不更適合嗎惊橱!)
本地中心 -> 遠(yuǎn)程外設(shè)
本地外設(shè) -> 遠(yuǎn)程中心
建立中心角色 —> 掃描外設(shè)(discover)—> 發(fā)現(xiàn)外設(shè)后連接外設(shè)(connect) —> 掃描外設(shè)中的服務(wù)和特征(discover) —> 與外設(shè)做數(shù)據(jù)交互(explore and interact) —> 斷開連接(disconnect)蚪腐。
1.建立中心角色
上面的delegate為CBCentralManagerDelegate,后續(xù)藍(lán)牙相關(guān)的回調(diào)都會(huì)在此李皇。queue代表藍(lán)牙在哪個(gè)隊(duì)列里面操作削茁,如果傳入nil默認(rèn)為主隊(duì)列,值得注意的是后續(xù)的回調(diào)也是在傳入的隊(duì)列中調(diào)用的掉房,所以如果傳入的是非主線程的隊(duì)列茧跋,在delegate中需要操作UI時(shí)需要手動(dòng)切換到主線程
CBCentralManager對(duì)象創(chuàng)建后會(huì)回調(diào)到centralManagerDidUpdateState方法來檢測(cè)藍(lán)牙可用狀態(tài),這時(shí)我們可以提醒用戶設(shè)備是否支持藍(lán)牙卓囚,是否打開了藍(lán)牙瘾杭。
2.掃描外設(shè)
如果serviceUUIDS為nil則會(huì)掃描周圍所有的設(shè)外設(shè),反之只會(huì)掃描UUID匹配的外設(shè)哪亿。CBCentralManagerScanOptionAllowDuplicatesKey默認(rèn)為false粥烁,此次掃描中發(fā)現(xiàn)過設(shè)備則跳過不回調(diào)贤笆,我們這里傳入true,因?yàn)橄旅孀鐾庠O(shè)掉線的處理時(shí)需要用到
傳入的serviceUUIDS數(shù)組元素為CBUUID類型讨阻,千萬不要傳入String芥永,后面的操作也是如此,不然會(huì)碰到很多奇葩問題
發(fā)現(xiàn)外設(shè)后會(huì)回調(diào)到 centralManager(central:,didDiscoverPeripheral:,advertisementData:, RSSI:)
其中钝吮,perpheral則代表著外設(shè)埋涧,我們需要保存起來,后續(xù)的對(duì)外設(shè)的操作都是基于perpheral對(duì)象的
3.連接外設(shè)
傳入上面保存的外設(shè)對(duì)象奇瘦,如果連接失敗后會(huì)回調(diào)到 centralManager(central:, didFailToConnectPeripheral:, error:)棘催,
連接成功后會(huì)回調(diào)到 centralManager(central:didConnectPeripheral:),這個(gè)時(shí)候我們只是連接上外設(shè)而已耳标,還需要發(fā)現(xiàn)外設(shè)中的服務(wù)與特征
4.發(fā)現(xiàn)服務(wù)與特征
5.發(fā)送數(shù)據(jù)
6.讀取數(shù)據(jù)
7.斷開連接
在藍(lán)牙交互的二種角色中醇坝,通常APP端扮演中央Central的角色,設(shè)備扮演外設(shè)Peripheral的角色
創(chuàng)建CBCentralManager對(duì)象時(shí)傳入的queue決定了后續(xù)CBCentralManagerDelegate次坡、CBPeripheralDelegate等回調(diào)的所在線程
一個(gè)外設(shè)設(shè)備可包含一個(gè)或多個(gè)服務(wù)呼猪,一個(gè)服務(wù)可包含一個(gè)或多個(gè)特征,讀寫操作最終是針對(duì)特征贸毕。
藍(lán)牙的緩沖大小只有20bytes郑叠,在發(fā)送數(shù)據(jù)時(shí)最多只能發(fā)送20bytes夜赵,所以得分多次發(fā)送明棍,數(shù)據(jù)的一體性可以用 EOM 標(biāo)識(shí)符表標(biāo)識(shí)
- 在iPhone應(yīng)用中如何保存數(shù)據(jù)?
答:有以下幾種保存機(jī)制:
1)存入到NSUserDefaults(系統(tǒng)plist文件中)
1).通過web服務(wù),保存在服務(wù)器上
2).通過NSCoder固化機(jī)制寇僧,將對(duì)象保存在文件中
3).通過SQlite或CoreData保存在文件數(shù)據(jù)庫中 - 什么是coredata?
答:coredata是蘋果提供一套數(shù)據(jù)保存框架摊腋,其基于SQlite - 什么是NSManagedObject模型?
答:NSManagedObject是NSObject的子類 ,也是coredata的重要組成部分嘁傀,它是一個(gè)通用的類,實(shí)現(xiàn)了core data 模型層所需的基本功能兴蒸,用戶可通過子類化NSManagedObject,建立自己的數(shù)據(jù)模型细办。 - 什么是NSManagedobjectContext?
答:NSManagedobjectContext對(duì)象負(fù)責(zé)應(yīng)用和數(shù)據(jù)庫之間的交互橙凳。 - ios 平臺(tái)怎么做數(shù)據(jù)的持久化?coredata 和sqlite有無必然聯(lián)系?coredata是一個(gè)關(guān)系型數(shù)據(jù)庫嗎笑撞?
答:iOS 中可以有四種持久化數(shù)據(jù)的方式:屬性列表(plist)岛啸、對(duì)象歸檔、 SQLite3 和 Core Data茴肥; core data 可以使你以圖形界面的方式快速的定義 app 的數(shù)據(jù)模型坚踩,同時(shí)在你的代碼中容易獲取到它。 coredata 提供了基礎(chǔ)結(jié)構(gòu)去處理常用的功能瓤狐,例如保存瞬铸,恢復(fù)批幌,撤銷和重做,允許你在 app 中繼續(xù)創(chuàng)建新的任務(wù)嗓节。在使用 core data 的時(shí)候荧缘,你不用安裝額外的數(shù)據(jù)庫系統(tǒng),因?yàn)?core data 使用內(nèi)置的 sqlite 數(shù)據(jù)庫拦宣。 core data 將你 app 的模型層放入到一組定義在內(nèi)存中的數(shù)據(jù)對(duì)象胜宇。 coredata 會(huì)追蹤這些對(duì)象的改變,同時(shí)可以根據(jù)需要做相反的改變恢着,例如用戶執(zhí)行撤銷命令桐愉。當(dāng) core data 在對(duì)你 app 數(shù)據(jù)的改變進(jìn)行保存的時(shí)候, core data 會(huì)把這些數(shù)據(jù)歸檔掰派,并永久性保存从诲。 mac os x 中sqlite 庫,它是一個(gè)輕量級(jí)功能強(qiáng)大的關(guān)系數(shù)據(jù)引擎靡羡,也很容易嵌入到應(yīng)用程序系洛。可以在多個(gè)平臺(tái)使用略步, sqlite 是一個(gè)輕量級(jí)的嵌入式 sql 數(shù)據(jù)庫編程描扯。與 core data 框架不同的是, sqlite 是使用程序式的趟薄, sql 的主要的 API 來直接操作數(shù)據(jù)表绽诚。 Core Data 不是一個(gè)關(guān)系型數(shù)據(jù)庫,也不是關(guān)系型數(shù)據(jù)庫管理系統(tǒng) (RDBMS) 杭煎。雖然 Core Dta 支持SQLite 作為一種存儲(chǔ)類型恩够,但它不能使用任意的 SQLite 數(shù)據(jù)庫。 Core Data 在使用的過程種自己創(chuàng)建這個(gè)數(shù)據(jù)庫羡铲。 Core Data 支持對(duì)一蜂桶、對(duì)多的關(guān)系。
二十:CoreData&SQLite3
首先也切,coredata和sqlite的概念不同扑媚,core為對(duì)象周期管理,而sqlite為dbms雷恃。
使用方便性疆股。實(shí)際上,一個(gè)成熟的工程中一定是對(duì)數(shù)據(jù)持久化進(jìn)行了封裝的褂萧,因此底層使用的到底是core data還是sqlite押桃,不應(yīng)該被業(yè)務(wù)邏輯開發(fā)者關(guān)心。因此,即使習(xí)慣寫SQL查詢的人唱凯,也應(yīng)該避免在業(yè)務(wù)邏輯中直接編寫SQL語句蟋软。
存儲(chǔ)性能匾二,在寫入性能上,因?yàn)槎际鞘褂玫膕qlite格式作為磁盤存儲(chǔ)格式,因此其性能是一樣的注簿,如果你覺得用core data寫的慢棍辕,很可能是你用sqlite的時(shí)候?qū)懙拿織l數(shù)據(jù)的內(nèi)容沒有core data時(shí)多余佛,或者是你批量寫入的時(shí)候每寫入一條就調(diào)用了一次save罩抗。
查詢性能,core data因?yàn)橐嫒荻喾N后端格式峰鄙,因此查詢時(shí)浸间,其可用的語句比直接使用sqlite少,因此有些fetch實(shí)際上不是在sqlite中執(zhí)行的吟榴。但這樣未必 會(huì)降低查詢效率魁蒜。因?yàn)閕Phone的flash memory速度還是很快的。我的經(jīng)驗(yàn)是大部分時(shí)候吩翻,在內(nèi)存不是很緊張時(shí)兜看,直接fetch一個(gè)entity的所有數(shù)據(jù)然后在內(nèi)存中做filter往往比使 用predicate在fetch時(shí)過濾更快。如果你覺的查詢慢狭瞎,很可能是查詢方式有問題细移,可以把core data的debug模式打開,看一下到底執(zhí)行了多少SQL語句熊锭,相信其中大部分是可以通過改寫core data的調(diào)用方式避免的弧轧。
core data的一個(gè)比較大的痛點(diǎn)是多人合作開發(fā)的時(shí)候,管理coredata的模型需要很小心球涛,尤其是合并的時(shí)候劣针,他的data model是XML格式的,手動(dòng)resolve比較煩心亿扁。
core data還有其他sql所不具備的優(yōu)點(diǎn),比如對(duì)undo的支持鸟廓,多個(gè)context實(shí)現(xiàn)sketchbook類似的功能从祝。為ManagedObject優(yōu)化的row cash等。
另外core data是支持多線程的引谜,但需要thread confinement的方式實(shí)現(xiàn),使用了多線程之后可以最大化的防止阻塞主線程
三.數(shù)據(jù)存儲(chǔ)
1.數(shù)據(jù)存儲(chǔ)技術(shù)
1> 數(shù)據(jù)存儲(chǔ)的幾種方式
XML屬性列表(plist)歸檔
Preference(偏好設(shè)置)
NSKeyedArchiver歸檔(NSCoding)
SQLite3
Core Data
2> 各自特點(diǎn)
Plist:
屬性列表是一種XML格式的文件牍陌,拓展名為plist
如果對(duì)象是NSString、NSDictionary员咽、NSArray毒涧、NSData、NSNumber等類型贝室,就可以使用writeToFile:atomically:方法直接將對(duì)象寫到屬性列表文件中
將一個(gè)NSDictionary對(duì)象歸檔到一個(gè)plist屬性列表中
// 將數(shù)據(jù)封裝成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"母雞" forKey:@"name"];
// 將字典持久化到Documents/stu.plist文件中
[dict writeToFile:path atomically:YES];
面試考點(diǎn):
- plist的根節(jié)點(diǎn) 只能是NSDictionary和NSArray契讲,所以存儲(chǔ)內(nèi)容必須轉(zhuǎn)為對(duì)象類型
- 使用場(chǎng)景 功能動(dòng)態(tài)更新 應(yīng)用級(jí)別數(shù)據(jù)更新 XML的替代品
偏好設(shè)置:
每個(gè)應(yīng)用都有個(gè)NSUserDefaults實(shí)例仿吞,通過它來存取偏好設(shè)置
比如,保存用戶名捡偏、字體大小唤冈、是否自動(dòng)登錄
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"itcast" forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];
面試考點(diǎn):
- 使用場(chǎng)景 保存應(yīng)用信息
- 特點(diǎn) 不會(huì)自動(dòng)刪除,itune同步银伟,不適合存大數(shù)據(jù)
- 使用單例模式你虹、
- 直接存取結(jié)構(gòu)體,基本數(shù)據(jù)類型彤避,無需轉(zhuǎn)換
- 即時(shí)操作注意同步
歸檔:
如果對(duì)象是NSString傅物、NSDictionary、NSArray琉预、NSData挟伙、NSNumber等類型,可以直接用NSKeyedArchiver進(jìn)行歸檔和恢復(fù)
不是所有的對(duì)象都可以直接用這種方法進(jìn)行歸檔模孩,只有遵守了NSCoding協(xié)議的對(duì)象才可以
NSCoding協(xié)議有2個(gè)方法:
encodeWithCoder:
每次歸檔對(duì)象時(shí)尖阔,都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何歸檔對(duì)象中的每個(gè)實(shí)例變量榨咐,可以使用encodeObject:forKey:方法歸檔實(shí)例變量
initWithCoder:
每次從文件中恢復(fù)(解碼)對(duì)象時(shí)介却,都會(huì)調(diào)用這個(gè)方法。一般在這個(gè)方法里面指定如何解碼文件中的數(shù)據(jù)為對(duì)象的實(shí)例變量块茁,可以使用decodeObject:forKey方法解碼實(shí)例變量
歸檔一個(gè)NSArray對(duì)象到Documents/array.archive
NSArray *array = [NSArray arrayWithObjects:@”a”,@”b”,nil];
[NSKeyedArchiver archiveRootObject:array toFile:path];
使用archiveRootObject:toFile:方法可以將一個(gè)對(duì)象直接寫入到一個(gè)文件中齿坷,但有時(shí)候可能想將多個(gè)對(duì)象寫入到同一個(gè)文件中,那么就要使用NSData來進(jìn)行歸檔對(duì)象
歸檔(編碼)
// 新建一塊可變數(shù)據(jù)區(qū)
NSMutableData *data = [NSMutableData data];
// 將數(shù)據(jù)區(qū)連接到一個(gè)NSKeyedArchiver對(duì)象
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
// 開始存檔對(duì)象数焊,存檔的數(shù)據(jù)都會(huì)存儲(chǔ)到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存檔完畢(一定要調(diào)用這個(gè)方法)
[archiver finishEncoding];
// 將存檔的數(shù)據(jù)寫入文件
[data writeToFile:path atomically:YES];
? 恢復(fù)(解碼)
// 從文件中讀取數(shù)據(jù)
NSData *data = [NSData dataWithContentsOfFile:path];
// 根據(jù)數(shù)據(jù)永淌,解析成一個(gè)NSKeyedUnarchiver對(duì)象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person1 = [unarchiver decodeObjectForKey:@"person1"];
Person *person2 = [unarchiver decodeObjectForKey:@"person2"];
// 恢復(fù)完畢
[unarchiver finishDecoding];
利用歸檔實(shí)現(xiàn)深復(fù)制
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];
// 解析data,生成一個(gè)新的Person對(duì)象
Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
面試考點(diǎn):
- 特點(diǎn): 存入Document佩耳,itune同步遂蛀,不會(huì)自動(dòng)刪除,可存放大型用戶數(shù)據(jù)
- 使用場(chǎng)景: 用戶產(chǎn)生的數(shù)據(jù)干厚,如游戲李滴,操作記錄等等
- 可保存自定義對(duì)象,需要遵守NSCoding協(xié)議蛮瞄,實(shí)現(xiàn)對(duì)應(yīng)的encodeWithCoder initWithCoder 方法
- 和NSData的配合
4.1> 多對(duì)象單目錄存儲(chǔ)
4.2> 字典/數(shù)組內(nèi)容的深拷貝 - 不能直接存基本類型和結(jié)構(gòu)體所坯,需要轉(zhuǎn)成對(duì)象 NSValue NSNumber
2> 沙盒目錄結(jié)構(gòu)
2.1> Library Caches Preferences
2.2> Documents
2.3> tmp
3> 如何讀取沙盒中plist的內(nèi)容
1> 3.1> 讀取沙盒并拼接plist的文件路徑
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
3.2> 根據(jù)plist根節(jié)點(diǎn)類型讀取plist文件
NSArray *apps = [NSArray arrayWithContentsOfFile:path];
2.數(shù)據(jù)庫技術(shù)(SQLite&CoreData)
1> SQLite和CoreData的區(qū)別
1.1> CoreData可以在一個(gè)對(duì)象更新時(shí),其關(guān)聯(lián)的對(duì)象也會(huì)隨著更新,相當(dāng)于你更新一張表時(shí),其關(guān)聯(lián)的其他表的也回隨著更新
1.2> CoreData提供更簡(jiǎn)單的性能管理機(jī)制,可以限制查詢記錄的總數(shù),這個(gè)類會(huì)自動(dòng)更新其緩存
1.3> 多表查詢方面,CoreData沒有SQL直觀,沒有類似外連接,左連接等操作.
iOS App升級(jí)安裝 - CoreData數(shù)據(jù)庫升級(jí)
1.選中你的mydata.xcdatamodeld文件,選擇菜單editor->Add Model Version 比如取名:mydata2.xcdatamodel
2.設(shè)置當(dāng)前版本
3..修改新數(shù)據(jù)模型mydata2挂捅,在新的文件上添加字段及表
4.刪除原來的類文件芹助,重新生成下類。在appdelegate中添加 *optionsDictionary,原來options:nil 改成options:optionsDictionary
5.重新編譯下程序状土。
增加模型版本——->選擇最新的版本——->選擇表无蜂,添加字段——>刪除之前的類,重新生成声诸。
- Objective-C堆和棧的區(qū)別酱讶?
答: 管理方式:對(duì)于棧來講,是由編譯器自動(dòng)管理彼乌,無需我們手工控制泻肯;對(duì)于堆來說,釋放工作由程序員控制慰照,容易產(chǎn)生memory leak灶挟。
申請(qǐng)大小:
棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)毒租,是一塊連續(xù)的內(nèi)存的區(qū)域稚铣。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在 WINDOWS下墅垮,棧的大小是2M(也有的說是1M惕医,總之是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請(qǐng)的空間超過棧的剩余空間時(shí)算色,將提示overflow抬伺。因 此,能從棧獲得的空間較小灾梦。
堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)峡钓,是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲(chǔ)的空閑內(nèi)存地址的若河,自然是不連續(xù)的能岩,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存萧福。由此可見拉鹃,堆獲得的空間比較靈活,也比較大统锤。
碎片問題:對(duì)于堆來講毛俏,頻繁的new/delete勢(shì)必會(huì)造成內(nèi)存空間的不連續(xù),從而造成大量的碎片饲窿,使程序效率降低。對(duì)于棧來講焕蹄,則不會(huì)存在這個(gè)問題逾雄,因?yàn)闂J窍冗M(jìn)后出的隊(duì)列,他們是如此的一一對(duì)應(yīng),以至于永遠(yuǎn)都不可能有一個(gè)內(nèi)存塊從棧中間彈出
分配方式:堆都是動(dòng)態(tài)分配的鸦泳,沒有靜態(tài)分配的堆银锻。棧有2種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是編譯器完成的做鹰,比如局部變量的分配击纬。動(dòng)態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動(dòng)態(tài)分配和堆是不同的钾麸,他的動(dòng)態(tài)分配是由編譯器進(jìn)行釋放更振,無需我們手工實(shí)現(xiàn)。
分配效率:棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu)饭尝,計(jì)算機(jī)會(huì)在底層對(duì)棧提供支持:分配專門的寄存器存放棧的地址肯腕,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高钥平。堆則是C/C++函數(shù)庫提供的实撒,它的機(jī)制是很復(fù)雜的。
十九:內(nèi)存泄露&內(nèi)存溢出
內(nèi)存溢出 out of memory涉瘾,是指程序在申請(qǐng)內(nèi)存時(shí)知态,沒有足夠的內(nèi)存空間供其使用,出現(xiàn)out of memory立叛;比如申請(qǐng)了一個(gè)integer,但給它存了long才能存下的數(shù)负敏,那就是內(nèi)存溢出。
內(nèi)存泄露 memory leak囚巴,是指程序在申請(qǐng)內(nèi)存后原在,無法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄露危害可以忽略彤叉,但內(nèi)存泄露堆積后果很嚴(yán)重庶柿,無論多少內(nèi)存,遲早會(huì)被占光。
memory leak會(huì)最終會(huì)導(dǎo)致out of memory秽浇!
內(nèi)存溢出就是你要求分配的內(nèi)存超出了系統(tǒng)能給你的浮庐,系統(tǒng)不能滿足需求,于是產(chǎn)生溢出
二十五:堆&棧
一柬焕、堆椛蟛校空間分配區(qū)別:
- 1、棧(操作系統(tǒng)):由操作系統(tǒng)自動(dòng)分配釋放 斑举,存放函數(shù)的參數(shù)值搅轿,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧富玷;
- 2璧坟、堆(操作系統(tǒng)): 一般由程序員分配釋放既穆, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收雀鹃,分配方式倒是類似于鏈表幻工。
二、堆棧緩存方式區(qū)別:
- 1黎茎、棧使用的是一級(jí)緩存囊颅, 他們通常都是被調(diào)用時(shí)處于存儲(chǔ)空間中,調(diào)用完畢立即釋放
- 2傅瞻、堆是存放在二級(jí)緩存中踢代,生命周期由虛擬機(jī)的垃圾回收算法來決定(并不是一旦成為孤兒對(duì)象就能被回收)。所以調(diào)用這些對(duì)象的速度要相對(duì)來得低一些俭正。
三奸鬓、堆棧數(shù)據(jù)結(jié)構(gòu)區(qū)別: - 堆(數(shù)據(jù)結(jié)構(gòu)):堆可以被看成是一棵樹,如:堆排序掸读;
- 棧(數(shù)據(jù)結(jié)構(gòu)):一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu)串远。
內(nèi)存其他補(bǔ)充:
全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的儿惫,初始化的全局變量和靜態(tài)變量在一塊區(qū)域澡罚, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 - 程序結(jié)束后有系統(tǒng)釋放
文字常量區(qū)—常量字符串就是放在這里的肾请。 程序結(jié)束后由系統(tǒng)釋放
程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼留搔。
六.內(nèi)存管理
1.內(nèi)存區(qū)域
1>堆和棧的區(qū)別
管理方式:對(duì)于棧來講,是由編譯器自動(dòng)管理铛铁,無需我們手工控制隔显;對(duì)于堆來說闸准,釋放工作由程序員控制邑遏,容易產(chǎn)生memory leak。
申請(qǐng)大懈哦:
棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)倍权,是一塊連續(xù)的內(nèi)存的區(qū)域,棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的掷豺,能從棧獲得的空間較小。
堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)薄声,是不連續(xù)的內(nèi)存區(qū)域,因?yàn)橄到y(tǒng)是用鏈表來存儲(chǔ)的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址当船。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存,因此堆獲得的空間比較靈活,也比較大。
碎片問題:
對(duì)于堆來講默辨,頻繁的new/delete勢(shì)必會(huì)造成內(nèi)存空間的不連續(xù)德频,從而造成大量的碎片,使程序效率降低缩幸。對(duì)于棧來講抱婉,則不會(huì)存在這個(gè)問題档叔,因?yàn)闂J窍冗M(jìn)后出的隊(duì)列桌粉,他們是如此的一一對(duì)應(yīng)蒸绩,以至于永遠(yuǎn)都不可能有一個(gè)內(nèi)存塊從棧中間彈出
分配方式:
堆都是動(dòng)態(tài)分配的,沒有靜態(tài)分配的堆铃肯。棧有2種分配方式:靜態(tài)分配和動(dòng)態(tài)分配患亿。靜態(tài)分配是編譯器完成的,比如局部變量的分配押逼。動(dòng)態(tài)分配由alloca函數(shù)進(jìn)行分配步藕,但是棧的動(dòng)態(tài)分配和堆是不同的,他的動(dòng)態(tài)分配是由編譯器進(jìn)行釋放挑格,無需我們手工實(shí)現(xiàn)咙冗。
分配效率:
棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會(huì)在底層對(duì)棧提供支持:分配專門的寄存器存放棧的地址漂彤,壓棧出棧都有專門的指令執(zhí)行雾消,這就決定了棧的效率比較高。堆則是C/C++函數(shù)庫提供的挫望,它的機(jī)制是很復(fù)雜的立润。
2> iOS內(nèi)存區(qū)域
2.1> 棧區(qū)
由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等.其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧.
2.2> 堆區(qū)
一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)由系統(tǒng)回收
2.3> 全局區(qū)(靜態(tài)區(qū))
全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域,未初始化的全局變量和未初始化的靜態(tài)變量相鄰的另一塊區(qū)域.
全局區(qū)分為未初始化全局區(qū): .bss段 和初始化全局區(qū): data段.
2.4> 常量區(qū)
常量字符串就是放在常量區(qū)
2.5> 代碼區(qū)
存放函數(shù)體的二進(jìn)制代碼
字符串的內(nèi)存管理
創(chuàng)建字符串的內(nèi)存空間 堆 常量區(qū)你是如何優(yōu)化內(nèi)存管理
1> 使用ARC
2> 延遲加載 懶加載
3> 重用 在正確的地方使用reuseIndentifier
4> 緩存 NSCache 保存計(jì)算數(shù)據(jù)
5> 處理內(nèi)存警告 移除對(duì)緩存,圖片 object 和其他一些可以重創(chuàng)建的 objects 的強(qiáng)引用
5.1> app delegate 中使用applicationDidReceiveMemoryWarning:
的方法
5.2> 自定義 UIViewController 的子類 (subclass) 中覆蓋didReceiveMemoryWarning
5.3> 在自定義類中注冊(cè)并接收 UIApplicationDidReceiveMemoryWarningNotification 的通知
6> 重用大開銷對(duì)象 NSDateFormatter 和 NSCalendar 懶加載/單例 _formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy”; 設(shè)置和創(chuàng)建速度一樣慢
7> 自動(dòng)釋放池 手動(dòng)添加自動(dòng)釋放池
8> 是否緩存圖片 imageNamed imageWithContentOfFile
9> 混編
10> 循環(huán)引用 delegate block nstimer
11> 移除 kvo nsnotificationcenter 并未強(qiáng)引用,只記錄內(nèi)存地址,野指針報(bào)錯(cuò) UIViewController自動(dòng)移除 一般在dealloc中
13> performselector 延遲操作 [NSObject cancelPreviousPerformRequestsWithTarget:self]循環(huán)引用
delegate屬性的內(nèi)存策略
block循環(huán)引用 實(shí)際場(chǎng)景autorelease的使用
1> 工廠方法為什么不釋放對(duì)象
很多類方法為了在代碼塊結(jié)束時(shí)引用的對(duì)象不會(huì)因無強(qiáng)引用而被釋放內(nèi)存采用自動(dòng)釋放的方式,當(dāng)其最近的自動(dòng)釋放池釋放時(shí)該對(duì)象才會(huì)釋放.
2> ARC下autorelease的使用場(chǎng)景
ARC中手動(dòng)添加autoreleasepool可用于提前釋放使用自動(dòng)釋放策略的對(duì)象,防止大量自動(dòng)釋放的對(duì)象堆積造成內(nèi)存峰值過高.
3> 自動(dòng)釋放池如何工作
自動(dòng)釋放池時(shí)棧結(jié)構(gòu),每個(gè)線程的runloop運(yùn)行時(shí)都會(huì)自動(dòng)創(chuàng)建自動(dòng)釋放池,程序員可以代碼手動(dòng)創(chuàng)建自動(dòng)釋放池,自動(dòng)釋放的對(duì)象會(huì)被添加到最近的(棧頂)自動(dòng)釋放池中,系統(tǒng)自動(dòng)創(chuàng)建的自動(dòng)釋放池在每個(gè)運(yùn)行循環(huán)結(jié)束時(shí)銷毀釋放池并給池中所有對(duì)象發(fā)release消息,手動(dòng)創(chuàng)建釋放池在所在代碼塊結(jié)束時(shí)銷毀釋放池并發(fā)消息統(tǒng)一release
避免內(nèi)存峰值
SDWebimage中加載gif圖片 大循環(huán)
棧結(jié)構(gòu) 棧頂
統(tǒng)一發(fā)release消息
5> ARC和MRC的混用
5.1> MRC>ARC
把MRC的代碼轉(zhuǎn)換成ARC的代碼媳板,刪除內(nèi)存管理操作(手動(dòng))
xcode提供了自動(dòng)將MRC轉(zhuǎn)換成ARC的功能桑腮,操作菜單欄edit -> Refacotor(重構(gòu)) -> Convert to Objective-C ARC
5.2> ARC>MRC
在ARC項(xiàng)目中繼續(xù)使用MRC編譯的類,在編譯選項(xiàng)中標(biāo)識(shí)MRC文件即可"-fno-objc-arc"
在MRC項(xiàng)目中繼續(xù)使用ARC編譯的類在編譯選項(xiàng)中標(biāo)識(shí)MRC文件即可"-fobjc-arc”
6> NSTimer的內(nèi)存管理
以下代碼有什么問題蛉幸?
@interface SvCheatYourself () {
NSTimer *_timer;
}
@end
@implementation SvCheatYourself
(id)init {
self = [super init];
if (self) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(testTimer:) userInfo:nil repeats:YES];
}
return self;
}(void)dealloc {
[_timer invalidate];
}(void)testTimer:(NSTimer*)timer{
NSLog(@"haha!");
}
@end
1)timer都會(huì)對(duì)它的target進(jìn)行retain破讨,對(duì)于重復(fù)性的timer,除非手動(dòng)關(guān)閉奕纫,否則對(duì)象不會(huì)釋放提陶,場(chǎng)景:導(dǎo)航控制器關(guān)聯(lián)的控制器無法銷毀
2)NSTimer要加到異步線程中,防止線程繁忙導(dǎo)致定時(shí)器失準(zhǔn)
3)timer必須加入到runloop中才會(huì)有效若锁,主線程runloop默認(rèn)開啟搁骑,異步線程手動(dòng)啟動(dòng)
4)注意runloop模式
7> ARC的實(shí)現(xiàn)原理
在程序預(yù)編譯階段,將 ARC 的代碼轉(zhuǎn)換為非 ARC 的 代碼,自動(dòng)加入 release、autorelease又固、retain
3.跨平臺(tái)
4.Runloop
1> 每個(gè)線程上都有一個(gè)runloop,主線程默認(rèn)開啟,輔助線程需要手動(dòng)開啟,主要用于
? 使用端口或自定義輸入源來和其他線程通信
? 使用線程的定時(shí)器
? Cocoa中使用任何performSelector…的方法
? 使線程周期性工作
2> runloop的工作流程
3> OC和C框架對(duì)象引用
oc和c 橋接 三個(gè)橋接關(guān)鍵字都是干么的 __bridge 不更改歸屬權(quán) __bridge_transfer 所有權(quán)給OC __bridge_retain 解除OC的所有權(quán)
ios5/6/7/8 內(nèi)存方面的區(qū)別
ios5.自動(dòng)引用計(jì)數(shù) (ARC)
ios6.UICollectionView ( 內(nèi)存重用機(jī)制仲器,圖片展示瀑布流實(shí)現(xiàn) ) 在didReceiveMemoryWarning中處理內(nèi)存(6之前在ViewDidUnload中) http://blog.csdn.net/likendsl/article/details/8199350
ios7.iOS7以后強(qiáng)制使用ARC
ios8
- fmmpeg框架
答: 音視頻編解碼框架,內(nèi)部使用UDP協(xié)議針對(duì)流媒體開發(fā)仰冠,內(nèi)部開辟了六個(gè)端口來接受流媒體數(shù)據(jù)乏冀,完成快速接受之目的。 - fmdb框架
答:數(shù)據(jù)庫框架洋只,對(duì)sqllite的數(shù)據(jù)操作進(jìn)行了封裝辆沦,使用著可把精力都放在sql語句上面昼捍。 - 320框架
答: ui框架,導(dǎo)入320工程作為框架包如同添加一個(gè)普通框架一樣肢扯。cover(open) flower框架 (2d 仿射技術(shù))妒茬,內(nèi)部核心類是CATransform3D.
4.UIKit和CoreAnimation和CoreGraphics的關(guān)系是什么?在開發(fā)中是否使用過CoreAnimation和CoreGraphics?
絕大多數(shù)圖形界面都由UIKit完成蔚晨,UIKit依賴于Core Graphics框架乍钻,也是基于Core Graphics框架實(shí)現(xiàn)的。某些更底層的功能铭腕,使用Core Graphics完成银择,是一組自由度更大的圖形繪制和動(dòng)畫API。
UIKit和CoreGraphics主要區(qū)別:
(1)Core Graphics其實(shí)是一套基于C的API框架累舷,使用了Quartz作為繪圖引擎浩考。這也就意味著Core Graphics不是面向?qū)ο蟮摹?br>
(2)Core Graphics需要一個(gè)圖形上下文(Context)
使用Core Graphics來繪圖,最簡(jiǎn)單的方法就是自定義一個(gè)類繼承自UIView被盈,并重寫子類的drawRect方法析孽。在這個(gè)方法中繪制圖形。
Core Graphics繪圖的步驟:
獲取上下文(畫布)
創(chuàng)建路徑(自定義或者調(diào)用系統(tǒng)的API)并添加到上下文中害捕。
進(jìn)行繪圖內(nèi)容的設(shè)置(畫筆顏色绿淋、粗細(xì)、填充區(qū)域顏色尝盼、陰影吞滞、連接點(diǎn)形狀等)
開始繪圖(CGContextDrawPath)
釋放路徑(CGPathRelease)
(1)核心圖形Core Graphics是用來實(shí)現(xiàn)用戶界面視覺設(shè)計(jì)方案的重要技術(shù)框架
(2)核心動(dòng)畫Core Animation提供了一套用于創(chuàng)建和渲染動(dòng)態(tài)交互效果的簡(jiǎn)單易行的解決方案,通過與UIKit的緊密配合,核心動(dòng)畫可以將界面交互對(duì)象與動(dòng)畫過渡效果進(jìn)行完美地整合盾沫。
(3)UIkit是用來打造iOS應(yīng)用的最重要的圖形技術(shù)框架裁赠,它提供了用于構(gòu)造觸屏設(shè)備用戶界面的全部工具和資源,并在整個(gè)交互體驗(yàn)的塑造過程中扮演著至關(guān)重要的角色
2> trasform
修改位移\形變\旋轉(zhuǎn),transform不同于board\center\frame,前者中記錄的是形變的數(shù)據(jù),不發(fā)生形變其值是空的,所以我們需要新建結(jié)構(gòu)體,用CGAffineTransform(仿射變換)函數(shù)給對(duì)象結(jié)構(gòu)體屬性賦值,而后者是控件的固有屬性,內(nèi)存數(shù)據(jù)是始終存在的,當(dāng)我們用他們做移動(dòng)等操作時(shí),是改變其值,所以是結(jié)構(gòu)體賦值三步曲,不用CG的函數(shù)
使用情景區(qū)別: transform一般用于有來有回的變化,而frame是有去無回
6點(diǎn)講動(dòng)畫和layer ,view的區(qū)別
1)觸摸
2)layer 特有
3)不觸摸的替代
4)屬性
5)為什么不合二為1
6)高級(jí)用法
1.圖層與視圖
一個(gè)視圖就是在屏幕上顯示的一個(gè)矩形塊(比如圖片赴精,文字或者視頻)佩捞,它能夠1)攔截類似于鼠標(biāo)點(diǎn)擊或者觸摸手勢(shì)等用戶輸入。視圖在層級(jí)關(guān)系中可以互相嵌套蕾哟,一個(gè)視圖可以管理它的所有子視圖的位置一忱。
所有的視圖都從一個(gè)叫做UIVIew的基類派生而來,UIView可以處理觸摸 2)(layer不行,但是layer有錨點(diǎn)和position的概念 選裝變換的時(shí)候用)谭确,可以支持基于Core Graphics繪圖帘营,可以做仿射變換(例如旋轉(zhuǎn)或者縮放),或者簡(jiǎn)單的類似于滑動(dòng)或者漸變的動(dòng)畫逐哈。
CALayer類在概念上和UIView類似芬迄,同樣也是一些被層級(jí)關(guān)系樹管理的矩形塊,同樣也可以包含一些內(nèi)容(像圖片昂秃,文本或者背景色)禀梳,管理子圖層的位置杜窄。它們有一些方法和屬性用來做動(dòng)畫和變換。和UIView最大的不同是CALayer不處理用戶的交互算途。
CALayer并不清楚具體的響應(yīng)鏈(iOS通過視圖層級(jí)關(guān)系用來傳送觸摸事件的機(jī)制)塞耕,于是它并不能夠響應(yīng)事件,即使3)它提供了一些方法來判斷是否一個(gè)觸點(diǎn)在圖層的范圍之內(nèi)郊艘。
2.平行的層級(jí)關(guān)系
4)每一個(gè)UIview都有一個(gè)CALayer實(shí)例的圖層屬性荷科,也就是所謂的backing layer,視圖的職責(zé)就是創(chuàng)建并管理這個(gè)圖層纱注,以確保當(dāng)子視圖在層級(jí)關(guān)系中添加或者被移除的時(shí)候,他們關(guān)聯(lián)的圖層也同樣對(duì)應(yīng)在層級(jí)關(guān)系樹當(dāng)中有相同的操作胆胰。
實(shí)際上這些背后關(guān)聯(lián)的圖層才是真正用來在屏幕上顯示和做動(dòng)畫狞贱,UIView僅僅是對(duì)它的一個(gè)封裝,提供了一些iOS類似于處理觸摸的具體功能蜀涨,以及Core Animation底層方法的高級(jí)接口瞎嬉。
5)但是為什么iOS要基于UIView和CALayer提供兩個(gè)平行的層級(jí)關(guān)系呢?為什么不用一個(gè)簡(jiǎn)單的層級(jí)來處理所有事情呢厚柳?原因在于要做職責(zé)分離氧枣,這樣也能避免很多重復(fù)代碼。在iOS和Mac OS兩個(gè)平臺(tái)上别垮,事件和用戶交互有很多地方的不同便监,基于多點(diǎn)觸控的用戶界面和基于鼠標(biāo)鍵盤有著本質(zhì)的區(qū)別,這就是為什么iOS有UIKit和UIView碳想,但是Mac OS有AppKit和NSView的原因烧董。他們功能上很相似,但是在實(shí)現(xiàn)上有著顯著的區(qū)別胧奔。
繪圖逊移,布局和動(dòng)畫,相比之下就是類似Mac筆記本和桌面系列一樣應(yīng)用于iPhone和iPad觸屏的概念龙填。把這種功能的邏輯分開并應(yīng)用到獨(dú)立的Core Animation框架胳泉,蘋果就能夠在iOS和Mac OS之間共享代碼,使得對(duì)蘋果自己的OS開發(fā)團(tuán)隊(duì)和第三方開發(fā)者去開發(fā)兩個(gè)平臺(tái)的應(yīng)用更加便捷岩遗。
實(shí)際上扇商,這里并不是兩個(gè)層級(jí)關(guān)系,而是四個(gè)喘先,每一個(gè)都扮演不同的角色钳吟,除了視圖層級(jí)和圖層樹之外,還存在呈現(xiàn)樹和渲染樹窘拯,將在第七章“隱式動(dòng)畫”和第十二章“性能調(diào)優(yōu)”分別討論红且。
3.圖層的能力
如果說CALayer是UIView內(nèi)部實(shí)現(xiàn)細(xì)節(jié)坝茎,那我們?yōu)槭裁匆娴亓私馑兀刻O果當(dāng)然為我們提供了優(yōu)美簡(jiǎn)潔的UIView接口暇番,那么我們是否就沒必要直接去處理Core Animation的細(xì)節(jié)了呢嗤放?
某種意義上說的確是這樣,對(duì)一些簡(jiǎn)單的需求來說壁酬,我們確實(shí)沒必要處理CALayer次酌,因?yàn)樘O果已經(jīng)通過UIView的高級(jí)API間接地使得動(dòng)畫變得很簡(jiǎn)單。
但是這種簡(jiǎn)單會(huì)不可避免地帶來一些靈活上的缺陷舆乔。如果6)你略微想在底層做一些改變岳服,或者使用一些蘋果沒有在UIView上實(shí)現(xiàn)的接口功能,這時(shí)除了介入Core Animation底層之外別無選擇希俩。
我們已經(jīng)證實(shí)了圖層不能像視圖那樣處理觸摸事件吊宋,那么他能做哪些視圖不能做的呢?這里有一些UIView沒有暴露出來的CALayer的功能:(CALayer高級(jí)用法)
陰影颜武,圓角璃搜,帶顏色的邊框
3D變換
非矩形范圍
透明遮罩
多級(jí)非線性動(dòng)畫
我們將會(huì)在后續(xù)章節(jié)中探索這些功能,首先我們要關(guān)注一下在應(yīng)用程序當(dāng)中CALayer是怎樣被利用起來的鳞上。
4.使用圖層
首先我們來創(chuàng)建一個(gè)簡(jiǎn)單的項(xiàng)目这吻,來操縱一些layer的屬性。打開Xcode篙议,使用Single View Application模板創(chuàng)建一個(gè)工程唾糯。
在屏幕中央創(chuàng)建一個(gè)小視圖(大約200 X 200的尺寸),當(dāng)然你可以手工編碼涡上,或者使用Interface Builder(隨你方便)趾断。確保你的視圖控制器要添加一個(gè)視圖的屬性以便可以直接訪問它。我們把它稱作layerView吩愧。
運(yùn)行項(xiàng)目芋酌,應(yīng)該能在淺灰色屏幕背景中看見一個(gè)白色方塊(圖1.3),如果沒看見雁佳,可能需要調(diào)整一下背景window或者view的顏色
四.核心繪圖
6> View和layer的區(qū)別
圖層不會(huì)直接渲染到屏幕上脐帝,UIView是iOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都是繼承自它糖权。它本身完全是由CoreAnimation來實(shí)現(xiàn)的堵腹。它真正的繪圖部分,是由一個(gè)CALayer類來管理星澳。UIView本身更像是一個(gè)CALayer的管理器疚顷。一個(gè)UIView上可以有n個(gè)CALayer,每個(gè)layer顯示一種東西,增強(qiáng)UIView的展現(xiàn)能力腿堤。
6.1>都可以顯示屏幕效果
6.2> 如果需要用戶交互就要用UIVIew,其可接收觸摸事件(繼承UIResponder),而CALayer不能接收觸摸事件
6.3> 如果沒有用戶交互可選用CALayer,因?yàn)槠渌趲燧^小,占用的資源較少
7> new和alloc init的區(qū)別
采用new的方式只能采用默認(rèn)的init方法完成初始化阀坏,采用alloc的方式可以用其他定制的初始化方法。
五.動(dòng)畫
1> ios界面切換
2> iOS中各種動(dòng)畫的類型&特點(diǎn)&使用場(chǎng)景
CAPropertyAnimation
是CAAnimation的子類笆檀,也是個(gè)抽象類忌堂,要想創(chuàng)建動(dòng)畫對(duì)象,應(yīng)該使用它的兩個(gè)子類:CABasicAnimation和CAKeyframeAnimation
屬性解析:
keyPath:通過指定CALayer的一個(gè)屬性名稱為keyPath(NSString類型)酗洒,并且對(duì)CALayer的這個(gè)屬性的值進(jìn)行修改士修,達(dá)到相應(yīng)的動(dòng)畫效果。比如樱衷,指定@”position”為keyPath棋嘲,就修改CALayer的position屬性的值,以達(dá)到平移的動(dòng)畫效果
CABasicAnimation
CAPropertyAnimation的子類
屬性解析:
fromValue:keyPath相應(yīng)屬性的初始值
toValue:keyPath相應(yīng)屬性的結(jié)束值
隨著動(dòng)畫的進(jìn)行箫老,在長(zhǎng)度為duration的持續(xù)時(shí)間內(nèi)封字,keyPath相應(yīng)屬性的值從fromValue漸漸地變?yōu)閠oValue
如果fillMode=kCAFillModeForwards和removedOnComletion=NO哥倔,那么在動(dòng)畫執(zhí)行完畢后史煎,圖層會(huì)保持顯示動(dòng)畫執(zhí)行后的狀態(tài)碉钠。但在實(shí)質(zhì)上,圖層的屬性值還是動(dòng)畫執(zhí)行前的初始值牲蜀,并沒有真正被改變。比如绅这,CALayer的position初始值為(0,0)涣达,CABasicAnimation的fromValue為(10,10),toValue為(100,100)证薇,雖然動(dòng)畫執(zhí)行完畢后圖層保持在(100,100)這個(gè)位置度苔,實(shí)質(zhì)上圖層的position還是為(0,0)
CAKeyframeAnimation
CApropertyAnimation的子類,跟CABasicAnimation的區(qū)別是:CABasicAnimation只能從一個(gè)數(shù)值(fromValue)變到另一個(gè)數(shù)值(toValue)浑度,而CAKeyframeAnimation會(huì)使用一個(gè)NSArray保存這些數(shù)值
屬性解析:
values:就是上述的NSArray對(duì)象寇窑。里面的元素稱為”關(guān)鍵幀”(keyframe)。動(dòng)畫對(duì)象會(huì)在指定的時(shí)間(duration)內(nèi)箩张,依次顯示values數(shù)組中的每一個(gè)關(guān)鍵幀
path:可以設(shè)置一個(gè)CGPathRef\CGMutablePathRef,讓層跟著路徑移動(dòng)甩骏。path只對(duì)CALayer的anchorPoint和position起作用。如果你設(shè)置了path先慷,那么values將被忽略
keyTimes:可以為對(duì)應(yīng)的關(guān)鍵幀指定對(duì)應(yīng)的時(shí)間點(diǎn),其取值范圍為0到1.0,keyTimes中的每一個(gè)時(shí)間值都對(duì)應(yīng)values中的每一幀.當(dāng)keyTimes沒有設(shè)置的時(shí)候,各個(gè)關(guān)鍵幀的時(shí)間是平分的
CABasicAnimation可看做是最多只有2個(gè)關(guān)鍵幀的CAKeyframeAnimation
CAAnimationGroup
CAAnimation的子類饮笛,可以保存一組動(dòng)畫對(duì)象,將CAAnimationGroup對(duì)象加入層后论熙,組中所有動(dòng)畫對(duì)象可以同時(shí)并發(fā)運(yùn)行
屬性解析:
animations:用來保存一組動(dòng)畫對(duì)象的NSArray
默認(rèn)情況下福青,一組動(dòng)畫對(duì)象是同時(shí)運(yùn)行的,也可以通過設(shè)置動(dòng)畫對(duì)象的beginTime屬性來更改動(dòng)畫的開始時(shí)間
CATransition
CAAnimation的子類,用于做轉(zhuǎn)場(chǎng)動(dòng)畫无午,能夠?yàn)閷犹峁┮瞥銎聊缓鸵迫肫聊坏膭?dòng)畫效果媒役。iOS比Mac OS X的轉(zhuǎn)場(chǎng)動(dòng)畫效果少一點(diǎn)
UINavigationController就是通過CATransition實(shí)現(xiàn)了將控制器的視圖推入屏幕的動(dòng)畫效果
屬性解析:
type:動(dòng)畫過渡類型
subtype:動(dòng)畫過渡方向
startProgress:動(dòng)畫起點(diǎn)(在整體動(dòng)畫的百分比)
endProgress:動(dòng)畫終點(diǎn)(在整體動(dòng)畫的百分比)
UIView動(dòng)畫
UIKit直接將動(dòng)畫集成到UIView類中,當(dāng)內(nèi)部的一些屬性發(fā)生改變時(shí)指厌,UIView將為這些改變提供動(dòng)畫支持
執(zhí)行動(dòng)畫所需要的工作由UIView類自動(dòng)完成刊愚,但仍要在希望執(zhí)行動(dòng)畫時(shí)通知視圖,為此需要將改變屬性的代碼放在[UIView beginAnimations:nil context:nil]和[UIView commitAnimations]之間
Block動(dòng)畫
幀動(dòng)畫
4.UICollectionView
1> 如何實(shí)現(xiàn)瀑布流,流水布局
1.1> 使用UICollectionView
1.2> 使用自定義的FlowLayout
1.3> 需要在layoutAttributesForElementsInRect中設(shè)置自定義的布局(item的frame)
1.4> 在 prepareLayout中計(jì)算布局
1.5> 遍歷數(shù)據(jù)內(nèi)容,根據(jù)索引取出對(duì)應(yīng)的attributes(使用layoutAttributesForCellWithIndexPath),根據(jù)九宮格算法設(shè)置布局
1.6> 細(xì)節(jié)1: 實(shí)時(shí)布局,重寫shouldInvalidateLayoutForBoundsChange(bounds改變重新布局,scrollview的contentoffset>bounds)
1.7> 細(xì)節(jié)2: 計(jì)算設(shè)置itemsize(保證內(nèi)容顯示完整,uicollectionview的content size是根據(jù)itemize計(jì)算的),根據(jù)列最大高度/對(duì)應(yīng)列數(shù)量求出,最大高度累加得到
1.8> 細(xì)節(jié)3: 追加item到最短列,避免底部參差不齊.
2> 和UITableView的使用區(qū)別
1)必須使用下面的方法進(jìn)行Cell類的注冊(cè):
? - (void)registerClass:forCellWithReuseIdentifier:
? - (void)registerClass:forSupplementaryViewOfKind:withReuseIdentifier:
? - (void)registerNib:forCellWithReuseIdentifier:
2)collectionView與tableView最大的不同點(diǎn)踩验,collectionView必須要使用自己的layout(UICollectionViewLayout)
如:
? UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
? flowLayout.itemSize = CGSizeMake(52, 52); // cell大小
? flowLayout.minimumInteritemSpacing = 1; // cell間距
? flowLayout.minimumLineSpacing = 1; // cell行距
? flowLayout.sectionInset = (UIEdgeInsets){81,1,1,1}; // cell邊距
創(chuàng)建collectionView需要帶Layout的初始化方法:
? - (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
5.UIImage
1> 有哪幾種加載方式
1.1> 二進(jìn)制 imageWithData
1.2> Bundle imageWithName
1.3> 本地路徑 imageWithContentOfFile
1.4>
6.webview
1>解決webview的內(nèi)存占用和泄露
7.描述九宮格算法
1> 1> 根據(jù)格子寬appW高appH和每行格數(shù)totalCol計(jì)算格子間隙marginX
CGFloat marginX = (self.view.frame.size.width - totalCol * appW)/(totalCol + 1);
2> 2> 根據(jù)序號(hào)i和每行格數(shù)totalCol計(jì)算行號(hào)列號(hào)
int row = i / totalCol;
int col = i % totalCol;
3> 3> 根據(jù)格子間隙鸥诽、格子寬高和行號(hào)列號(hào)計(jì)算x,y
CGFloat appX = marginX + col * (appW + marginX);
CGFloat appY = row * (appH + marginY);
- 實(shí)現(xiàn)圖片輪播圖
1> 1> UIScrollView設(shè)置contentSize,添加圖片并設(shè)置frame箕憾,設(shè)置分頁
2> 2> 添加分頁控制器牡借,在UIScrollView滾動(dòng)代理方法中根據(jù)contentOffset計(jì)算當(dāng)前頁數(shù)并設(shè)置
3> 設(shè)置定時(shí)器,主動(dòng)改變contentOffset,設(shè)置定時(shí)器的模式進(jìn)行并發(fā)操作(終極方案定時(shí)器放在異步線程)
五.iOS網(wǎng)絡(luò)框架
1> NSURLConnection和NSURLSession的區(qū)別
1.1> 異步請(qǐng)求不需要NSOperation包裝
1.2> 支持后臺(tái)運(yùn)行的網(wǎng)絡(luò)任務(wù)(后臺(tái)上傳下載)
1.3> 根據(jù)每個(gè)Session做配置(http header袭异,Cache,Cookie,protocal,Credential)钠龙,不再在整個(gè)App層面共享配置
1.4> 支持網(wǎng)絡(luò)操作的取消和斷點(diǎn)續(xù)傳(繼承系統(tǒng)類,重新main方法)
1.5> 改進(jìn)了授權(quán)機(jī)制的處理
網(wǎng)絡(luò)
一.網(wǎng)絡(luò)基礎(chǔ)
1.數(shù)據(jù)解析
1> XML解析方式
SAX 方式解析
-只讀
-速度快
-從上向下
-通過5個(gè)代理方法解析御铃,每個(gè)代理方中都需要寫一些代碼碴里!
-如果要實(shí)現(xiàn)SAX解析,思路最重要上真!
-適合比價(jià)大的XML的解析
DOM解析的特點(diǎn)
-一次性將XML全部加載到內(nèi)存咬腋,以樹形結(jié)構(gòu)
-好處,可以動(dòng)態(tài)的修改睡互,添加根竿,刪除節(jié)點(diǎn)
-內(nèi)存消耗非常大!尤其橫向節(jié)點(diǎn)越深就珠!
-iOS默認(rèn)不支持 DOM 解析寇壳!
-在 MAC 端,或者服務(wù)器端開發(fā)妻怎,都基本上使用 DOM 解析
-在 iOS 端如果需要使用 DOM 方式解析壳炎,可以使用第三方框GData/KissXML(XMPP)
-適合比較小的 XML 文件
-在 MAC 中,蘋果提供了一個(gè) NSXML 的類蹂季,能夠做 DOM 解析冕广,在 iOS 不能使用!
2> json&xml的區(qū)別
1)解碼難度: json的解碼難度基本為零,xml需要考慮子節(jié)點(diǎn)和父節(jié)點(diǎn)
2)數(shù)據(jù)體積&傳輸速度: json相對(duì)于xml來講,數(shù)據(jù)體積小,json的速度遠(yuǎn)遠(yuǎn)快于xml
3)數(shù)據(jù)交互: json與JavaScript的交互更加方面,更容易解析處理,更好的數(shù)據(jù)交互
4)數(shù)據(jù)描述: xml對(duì)數(shù)據(jù)描述性比較好
3.網(wǎng)絡(luò)傳輸
1>DNS是如何工作的
DNS是domain name server的簡(jiǎn)稱,每個(gè)網(wǎng)絡(luò)的計(jì)算機(jī)都有ip,但是不好記,所以用域名替代(如www.baidu.com),在 Internet 上真實(shí)在辨識(shí)機(jī)器的還是 IP偿洁,所以當(dāng)使用者輸入Domain Name 后撒汉,瀏覽器必須要先去一臺(tái)有 Domain Name 和IP 對(duì)應(yīng)資料的主機(jī)去查詢這臺(tái)電腦的 IP,而這臺(tái)被查詢的主機(jī)涕滋,我們稱它為 Domain Name Server睬辐,簡(jiǎn)稱DNS,例如:當(dāng)你輸入www.pchome.com.tw時(shí),瀏覽器會(huì)將www.pchome.com.tw這個(gè)名字傳送到離他最近的 DNS Server 去做辨識(shí)溯饵,如果查到侵俗,則會(huì)傳回這臺(tái)主機(jī)的 IP,進(jìn)而跟它索取資料丰刊,但如果沒查到隘谣,就會(huì)發(fā)生類似 DNS NOT FOUND 的情形,所以一旦DNS Server當(dāng)機(jī)啄巧,就像是路標(biāo)完全被毀壞寻歧,沒有人知道該把資料送到那里
2> POST請(qǐng)求常見的數(shù)據(jù)格式
2.AFN
1>實(shí)現(xiàn)原理
AFN的直接操作對(duì)象AFHTTPClient不同于ASI,是一個(gè)實(shí)現(xiàn)了NSCoding和NSCopying協(xié)議的NSObject子類秩仆。 AFHTTPClient是一個(gè)封裝了一系列操作方法的“工具類”码泛,處理請(qǐng)求的操作類是一系列單獨(dú)的,基于NSOperation封裝 的澄耍,AFURLConnectionOperation的子類噪珊。AFN的示例代碼中通過一個(gè)靜態(tài)方法,使用dispatch_once()的方式創(chuàng)建 AFHTTPClient的共享實(shí)例齐莲,這也是官方建議的使用方法痢站。在創(chuàng)建AFHTTPClient的初始化方法中,創(chuàng)建了OperationQueue并 設(shè)置一系列參數(shù)默認(rèn)值选酗。在getPath:parameters:success:failure方法中創(chuàng)建NSURLRequest瑟押,以 NSURLRequest對(duì)象實(shí)例作為參數(shù),創(chuàng)建一個(gè)NSOperation星掰,并加入在初始化發(fā)方中創(chuàng)建的NSOperationQueue。以上操作都 是在主線程中完成的嫩舟。在NSOperation的start方法中氢烘,以此前創(chuàng)建的NSURLRequest對(duì)象為參數(shù)創(chuàng)建NSURLConnection 并開啟連結(jié)。
2> 傳遞指針 如何使一個(gè)方法返回多個(gè)返回值
傳參指針變量的地址,方法內(nèi)部通過*運(yùn)算符使用該地址可以修改該地址保存的內(nèi)容(引用對(duì)象的地址),當(dāng)外部再次使用該指針變量取出引用對(duì)象時(shí),引用對(duì)象已經(jīng)在方法內(nèi)部發(fā)生了改變,指針變量指向其他數(shù)據(jù),相當(dāng)于方法的返回值(經(jīng)方法處理后生成的外部可使用的結(jié)果數(shù)據(jù)).
十一:AFNetworking&ASIHttpRequest&MKNetWorking
一家厌、底層實(shí)現(xiàn)
1播玖、AFN的底層實(shí)現(xiàn)基于OC的NSURLConnection和NSURLSession
2、ASI的底層實(shí)現(xiàn)基于純C語言的CFNetwork框架
3饭于、因?yàn)镹SURLConnection和NSURLSession是在CFNetwork之上的一層封裝蜀踏,因此ASI的運(yùn)行性能高于AFN
二、對(duì)服務(wù)器返回的數(shù)據(jù)處理
1掰吕、ASI沒有直接提供對(duì)服務(wù)器數(shù)據(jù)處理的方式果覆,直接返回的是NSData/NSString
2、AFN提供了多種對(duì)服務(wù)器數(shù)據(jù)處理的方式
(1)JSON處理-直接返回NSDictionary或者NSArray
(2)XML處理-返回的是xml類型數(shù)據(jù)殖熟,需對(duì)其進(jìn)行解析
(3)其他類型數(shù)據(jù)處理
三局待、監(jiān)聽請(qǐng)求過程
1、AFN提供了success和failure兩個(gè)block來監(jiān)聽請(qǐng)求的過程(只能監(jiān)聽成功和失敗)
- success : 請(qǐng)求成功后調(diào)用
- failure : 請(qǐng)求失敗后調(diào)用
2钳榨、ASI提供了3套方案舰罚,每一套方案都能監(jiān)聽請(qǐng)求的完整過程
(監(jiān)聽請(qǐng)求開始、接收到響應(yīng)頭信息薛耻、接受到具體數(shù)據(jù)营罢、接受完畢、請(qǐng)求失敱荨) - 成為代理饲漾,遵守協(xié)議,實(shí)現(xiàn)協(xié)議中的代理方法
- 成為代理候醒,不遵守協(xié)議能颁,自定義代理方法
- 設(shè)置block
四、在文件下載和文件上傳的使用難易度
1倒淫、AFN
*不容易實(shí)現(xiàn)監(jiān)聽下載進(jìn)度和上傳進(jìn)度
*不容易實(shí)現(xiàn)斷點(diǎn)續(xù)傳
*一般只用來下載不大的文件
2伙菊、ASI(ipv6)
*非常容易實(shí)現(xiàn)下載和上傳
*非常容易監(jiān)聽下載進(jìn)度和上傳進(jìn)度
*非常容易實(shí)現(xiàn)斷點(diǎn)續(xù)傳
*下載大文件或小文件均可
3、實(shí)現(xiàn)下載上傳推薦使用ASI
五敌土、網(wǎng)絡(luò)監(jiān)控
1镜硕、AFN自己封裝了網(wǎng)絡(luò)監(jiān)控類,易使用
2返干、ASI使用的是Reachability兴枯,因?yàn)槭褂肅ocoaPods下載ASI時(shí),會(huì)同步下載Reachability矩欠,但Reachability作為網(wǎng)絡(luò)監(jiān)控使用較為復(fù)雜(相對(duì)于AFN的網(wǎng)絡(luò)監(jiān)控類來說)
3财剖、推薦使用AFN做網(wǎng)絡(luò)監(jiān)控-AFNetworkReachabilityManager
六、ASI提供的其他實(shí)用功能
1癌淮、控制信號(hào)旁邊的圈圈要不要在請(qǐng)求過程中轉(zhuǎn)
2躺坟、可以輕松地設(shè)置請(qǐng)求之間的依賴:每一個(gè)請(qǐng)求都是一個(gè)NSOperation對(duì)象
3、可以統(tǒng)一管理所有請(qǐng)求(還專門提供了一個(gè)叫做ASINetworkQueue來管理所有的請(qǐng)求對(duì)象)
- 暫停/恢復(fù)/取消所有的請(qǐng)求
- 監(jiān)聽整個(gè)隊(duì)列中所有請(qǐng)求的下載進(jìn)度和上傳進(jìn)度
MKNetworkKit 是一個(gè)使用十分方便乳蓄,功能又十分強(qiáng)大咪橙、完整的iOS網(wǎng)絡(luò)編程代碼庫。它只有兩個(gè)類, 它的目標(biāo)是使用像AFNetworking這么簡(jiǎn)單虚倒,而功能像ASIHTTPRequest(已經(jīng)停止維護(hù))那么強(qiáng)大美侦。它除了擁有 AFNetworking和ASIHTTPRequest所有功能以外,還有一些新特色魂奥,包括:
1菠剩、高度的輕量級(jí),僅僅只有2個(gè)主類
2捧弃、自主操作多個(gè)網(wǎng)絡(luò)請(qǐng)求
3赠叼、更加準(zhǔn)確的顯示網(wǎng)絡(luò)活動(dòng)指標(biāo)
4擦囊、自動(dòng)設(shè)置網(wǎng)絡(luò)速度,實(shí)現(xiàn)自動(dòng)的2G嘴办、3G瞬场、wifi切換
5、自動(dòng)緩沖技術(shù)的完美應(yīng)用涧郊,實(shí)現(xiàn)網(wǎng)絡(luò)操作記憶功能贯被,當(dāng)你掉線了又上線后,會(huì)繼續(xù)執(zhí)行未完成的網(wǎng)絡(luò)請(qǐng)求
6妆艘、可以實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的暫停功能
7彤灶、準(zhǔn)確無誤的成功執(zhí)行一次網(wǎng)絡(luò)請(qǐng)求,摒棄后臺(tái)的多次請(qǐng)求浪費(fèi)
8批旺、支持圖片緩沖
9幌陕、支持ARC機(jī)制
10、在整個(gè)app中可以只用一個(gè)隊(duì)列(queue)汽煮,隊(duì)列的大小可以自動(dòng)調(diào)整
6.性能優(yōu)化
1> 如何進(jìn)行性能優(yōu)化
1.1> 內(nèi)存優(yōu)化的點(diǎn) 重用 懶加載
1.2> 渲染優(yōu)化 盡量使用不透明的圖 把 views 設(shè)置為透明
1.3> 在ImageView設(shè)置前,盡量先調(diào)整好圖片大小 尤其放在uiscrolliview中自動(dòng)縮放耗能
1.4> 避免使用過大的xib 和分鏡的區(qū)別 一次性加載
1.5> 不要阻塞主線程 除渲染,觸摸響應(yīng)等 盡量異步處理 如存儲(chǔ),網(wǎng)絡(luò) 異步線程通知
1.6> 緩存 網(wǎng)絡(luò)響應(yīng),圖片,計(jì)算結(jié)果(行高) 網(wǎng)絡(luò)響應(yīng)NSUrlconnection默認(rèn)緩存request,設(shè)置策略 非網(wǎng)絡(luò)請(qǐng)求 使用nscache nsdictionary
1.7> 避免反復(fù)處理數(shù)據(jù) 在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)
1.8> 選擇正確的數(shù)據(jù)格式 json 速度快 解析方便 xml sax方式逐行解析 解析大文件不占用內(nèi)存和損失性能
1.9> 優(yōu)化tableview 重用cell 緩存行高 cell子視圖盡量少且不透明
1.10> 選擇正確的數(shù)據(jù)存儲(chǔ)選項(xiàng) plist nscoding NSUserDefaults sqlite coredata
八.算法
1.交換數(shù)值的幾種方法 中間變量 加減法 異或
2.oc/c實(shí)現(xiàn)常用排序
二叉樹
鏈表
寫一個(gè)單鏈表,要求可以插入數(shù)據(jù)和刪除單個(gè)數(shù)據(jù)
遞歸
@interface Singleton: NSObject
+(instance)shareInstance;
@end
import “Singleton”
@implemention Singleton
static Singleton *_instance = nil;
+(instance)shareInstance{
static dispatch_once_t onceToken;
dispatch_once({
_instance = [[seif alloc]init];});
return _instance;}
項(xiàng)目
1.實(shí)用技術(shù)
2.知名第三方框架
3.開發(fā)技巧
1> description方法
2.靜態(tài)庫
如何給靜態(tài)庫添加屬性 分類+runtime
如何調(diào)用私有方法 performselector category(前向引用)