OC 和 Swift 問(wèn)題 (隨時(shí)補(bǔ)充)

問(wèn): 關(guān)鍵字static的作用是什么?

    1. 函數(shù)體內(nèi)static變量的作用范圍為該函數(shù)體,不同于auto變量,該變量的內(nèi)存只被分配一次,因此其值在下次調(diào)用時(shí)仍維持上次的值;
    1. 在模塊內(nèi)的static全局變量可以被模塊內(nèi)所用函數(shù)訪問(wèn),但不能被模塊外其它函數(shù)訪問(wèn);
    1. 在模塊內(nèi)的static函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個(gè)函數(shù)的使用范圍被限制在聲明它的模塊內(nèi);

問(wèn): 關(guān)鍵字const是什么含義? 分別解釋下列語(yǔ)句中const的作用?

const int a;
int const a;
const int *a;
int * const a;
int const * a const;

含義

    1. 欲阻止一個(gè)變量被改變,可以使用const關(guān)鍵字。在定義該const變量時(shí),通常需要對(duì)它進(jìn)行初始化,因?yàn)橐院缶蜎](méi)有機(jī)會(huì)再去改變它了;
    1. 對(duì)指針來(lái)說(shuō),可以指定指針本身為const,也可以指定指針?biāo)傅臄?shù)據(jù)為const,或二者同時(shí)指定為const;
    1. 在一個(gè)函數(shù)聲明中,const可以修飾形參,表明它是一個(gè)輸入?yún)?shù),在函數(shù)內(nèi)部不能改變其值;
    1. 對(duì)于類的成員函數(shù),若指定其為const類型,則表明其是一個(gè)常函數(shù),不能修改類的成員變量;

作用

const int a;            //a是一個(gè)常整型數(shù)
int const a;            //a是一個(gè)常整型數(shù)
const int *a;           //a是一個(gè)指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的,但指針可以)
int * const a;          //a是一個(gè)指向整型數(shù)的常指針(也就是說(shuō),指針指向的整型數(shù)是可以修改的,但指針是不可修改的)
int const * a const;    //a是一個(gè)指向常整型數(shù)的常指針(也就是說(shuō),指針指向的整型數(shù)是不可修改的,同時(shí)指針也是不可修改的)

問(wèn): 使用nonatomic一定是線程安全的嗎?

    1. nonatomic: 非原子性,set方法的實(shí)現(xiàn)不加鎖,不安全,性能高
    1. atomicatomic性能低,atomic通過(guò)鎖定機(jī)制來(lái)確保其原子性,但只是讀/寫(xiě)安全,不能絕對(duì)保證線程的安全,當(dāng)多線程同時(shí)訪問(wèn)的時(shí)候,會(huì)造成線程不安全??梢允褂镁€程鎖來(lái)保證線程的安全。

問(wèn): 對(duì)于語(yǔ)句N(xiāo)SString *obj = [[NSData alloc] init]; ,編譯時(shí)和運(yùn)行時(shí)obj分別是什么類型?

    1. 編譯時(shí)是NSString類型
    1. 運(yùn)行時(shí)是NSData類型

問(wèn): Objective-C如何對(duì)內(nèi)存管理的,說(shuō)說(shuō)你的看法和解決方法?

    1. 每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù)器,每個(gè)新對(duì)象的計(jì)數(shù)器是1,當(dāng)對(duì)象的計(jì)數(shù)器減為0時(shí),就會(huì)被銷(xiāo)毀
    1. 通過(guò)retain可以讓對(duì)象的計(jì)數(shù)器+1、release可以讓對(duì)象的計(jì)數(shù)器-1
    1. 還可以通過(guò)autorelease pool管理內(nèi)存
    1. 如果用ARC,編譯器會(huì)自動(dòng)生成管理內(nèi)存的代碼

注意:不管是MRC還是ARC都是在編譯時(shí)完成的


問(wèn): iOS數(shù)據(jù)持久化有哪些?

為何要持久化:iOS 開(kāi)發(fā)可以沒(méi)有持久化,持久化更多的是業(yè)務(wù)需求;比如記錄用戶是否登陸,下次進(jìn)應(yīng)用不需要再登陸。
因?yàn)?iOS沙盒機(jī)制,所以持久化分為兩類:沙盒內(nèi)沙盒外。

    1. 沙盒內(nèi)
      (1) NSKeyedArchiver: 只要遵循了 NSCoding 協(xié)議并正確實(shí)現(xiàn)了initWithCoderencodeWithCoder 方法的類都可以通過(guò)NSKeyedArchiver 來(lái)序列化。
      歸檔使用 archiveRootObject ,解歸檔使用 unarchiveObjectWithFile ;需要指定文件路徑。
      (2) NSUserDefaults: [NSUserDefaults standardUserDefaults]獲取NSUserDefaults對(duì)象,以key-value方式進(jìn)行持久化操作。
      (3) plist: 寫(xiě)入使用writeToFile,讀取使用xxxWithContentsOfFile;需要指定文件路徑。
      (4) 數(shù)據(jù)庫(kù): sqlite、CoreDataRealm
      (5) 文件: 這里要和plist區(qū)分一下,plist方式是字典/數(shù)組數(shù)據(jù)格式寫(xiě)入文件;而這里的文件方式不限數(shù)據(jù)格式。
    1. 沙盒外
      沙盒內(nèi)的方式在應(yīng)用被刪除后數(shù)據(jù)都會(huì)丟失,如果想要不丟失則需要使用KeyChain
      KeyChain本質(zhì)是一個(gè)sqlite數(shù)據(jù)庫(kù),其保存的所有數(shù)據(jù)都是加密過(guò)的。
      KeyChain分為私有和公有,公有則需要指定group,一個(gè)group中的應(yīng)用可以共享此KeyChain。
      使用KeyChain過(guò)程中要理解下面幾個(gè)問(wèn)題:
      ①:自己使用的KeyChain和系統(tǒng)自帶的KeyChain數(shù)據(jù)是隔離的,內(nèi)部應(yīng)該是不同數(shù)據(jù)庫(kù)文件;
      ②:KeyChain數(shù)據(jù)可備份到iCloud中;
      ③:不需要聯(lián)網(wǎng),也不用登陸iCloud賬號(hào);一個(gè)設(shè)備一個(gè)sqlite數(shù)據(jù)庫(kù),但是不同應(yīng)用組不共享數(shù)據(jù);
      ④:要在另一臺(tái)設(shè)備上使用當(dāng)前設(shè)備存儲(chǔ)的KeyChain信息,需要當(dāng)前設(shè)備進(jìn)行數(shù)據(jù)備份,再在另一設(shè)備上復(fù)原數(shù)據(jù);比較常用的是iCloud備份方式;
      ⑤:系統(tǒng)自帶的KeyChain中賬號(hào)密碼分類數(shù)據(jù)可在系統(tǒng)設(shè)置->賬號(hào)與密碼里面看到,你退出iCloud賬號(hào)還是存在,只是iCloud會(huì)幫你備份如果你設(shè)置了的話;這個(gè)和照片是一樣的道理。

問(wèn): id和NSObject*的區(qū)別?

  • id可以指向OC中的任何對(duì)象,而NSObject*只能指向NSObject及子類對(duì)象

問(wèn): strong 和 weak 的區(qū)別?


問(wèn): (堆和棧) 哪些數(shù)據(jù)是放在堆上的,哪些是放在棧上的?

  • 棧:由系統(tǒng)自動(dòng)分配,速度較快,不會(huì)產(chǎn)生內(nèi)存碎片,
  • 堆:是由alloc分配的內(nèi)存,速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過(guò)用起來(lái)最方便。

問(wèn): UITableView 優(yōu)化?

    1. cell復(fù)用
      我們經(jīng)常在注意 cellForRowAtIndexPath: 中為每一個(gè) cell 綁定數(shù)據(jù),實(shí)際上在調(diào)用 cellForRowAtIndexPath: 的時(shí)候 cell 還沒(méi)有被顯示出來(lái),為了提高效率我們應(yīng)該把數(shù)據(jù)綁定的操作放在 cell 顯示出來(lái)后再執(zhí)行,可以在tableView:willDisplayCell:forRowAtIndexPath:(以后簡(jiǎn)稱willDisplayCell)方法中綁定數(shù)據(jù)。
      注意 willDisplayCellcelltableview 展示之前就會(huì)調(diào)用,此時(shí) cell 實(shí)例已經(jīng)生成,所以不能更改 cell 的結(jié)構(gòu),只能是改動(dòng) cell 上的 UI 的一些屬性(例如 label 的內(nèi)容等)。
    1. cell高度的計(jì)算
      (1)定高的 cell,應(yīng)該采用如下方式:self.tableView.rowHeight = 88;
      (2)動(dòng)態(tài)高度的cell:tableView: tableViewheightForRowAtIndexPath:,該方法實(shí)現(xiàn)后,上面的 rowHeight 的設(shè)置將會(huì)變成無(wú)效。在這個(gè)方法中,我們需要提高 cell 高度的計(jì)算效率,來(lái)節(jié)省時(shí)間。
      自從 iOS8 之后有了 self-sizing cell 的概念,cell 可以自己算出高度,使用 self-sizing cell 需要滿足以下三個(gè)條件:
      ① 使用 Autolayout 進(jìn)行 UI 布局約束(要求 cell.contentView 的四條邊都與內(nèi)部元素有約束關(guān)系)。
      ② 指定 TableViewestimatedRowHeight 屬性的默認(rèn)值。
      ③ 指定 TableViewrowHeight 屬性為 UITableViewAutomaticDimension
    1. 渲染
      (1)當(dāng)有圖像時(shí),預(yù)渲染圖像,在 bitmap context 先將其畫(huà)一遍,導(dǎo)出成 UIImage 對(duì)象,然后再繪制到屏幕,這會(huì)大大提高渲染速度。具體內(nèi)容可以自行查找“利用預(yù)渲染加速顯示 iOS 圖像”相關(guān)資料。
      (2)渲染最好時(shí)的操作之一就是混合( blending )了,所以我們不要使用透明背景,將 cellopaque 值設(shè)為 Yes,背景色不要使用 clearColor,盡量不要使用陰影漸變等。
      (3)由于混合操作是使用 GPU 來(lái)執(zhí)行,我們可以用 CPU 來(lái)渲染,這樣混合操作就不再執(zhí)行??梢栽?UIViewdrawRect 方法中自定義繪制。
    1. 減少視圖的數(shù)目
      我們?cè)?cell 上添加系統(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 ,并重寫(xiě) drawRect 方法。
    1. 減少多余的繪制操作
      在實(shí)現(xiàn) drawRect 方法的時(shí)候,它的參數(shù) rect 就是我們需要繪制的區(qū)域,在 rect 范圍之外的區(qū)域我們不需要進(jìn)行繪制,否則會(huì)消耗相當(dāng)大的資源。
    1. 不要給cell動(dòng)態(tài)添加subView
      在初始化 cell 的時(shí)候就將所有需要展示的添加完畢,然后根據(jù)需要來(lái)設(shè)置 hide 屬性顯示和隱藏。
    1. 異步化UI,不要阻塞主線程
      我們時(shí)常會(huì)看到這樣一個(gè)現(xiàn)象,就是加載時(shí)整個(gè)頁(yè)面卡住不動(dòng),怎么點(diǎn)都沒(méi)用,仿佛死機(jī)了一般。原因是主線程被阻塞了。所以對(duì)于網(wǎng)路數(shù)據(jù)的請(qǐng)求或者圖片的加載,我們可以開(kāi)啟多線程,將耗時(shí)操作放到子線程中進(jìn)行,異步化操作。這個(gè)或許每個(gè) iOS 開(kāi)發(fā)者都知道的知識(shí),不必多講。
    1. 滑動(dòng)時(shí)按需加載對(duì)應(yīng)的內(nèi)容
      如果目標(biāo)行與當(dāng)前行相差超過(guò)指定行數(shù),只在目標(biāo)滾動(dòng)范圍的前后指定3行加載。
      滑動(dòng)很快時(shí),只加載目標(biāo)范圍內(nèi)的cell,這樣按需加載(配合SDWebImage),極大提高流暢度。

問(wèn): 消息列表頁(yè)面如何優(yōu)化?

首先我們發(fā)消息時(shí)候觀察一下消息列表的特性,當(dāng)發(fā)送一條消息時(shí)候,消息的數(shù)量會(huì)變化,列表會(huì)出現(xiàn)在最上邊的位置,列表內(nèi)的內(nèi)容會(huì)發(fā)生變化。從消息列表的特性,我們就可以分析出要優(yōu)化的點(diǎn)了。通過(guò)這些點(diǎn),我們做了一些優(yōu)化:

    1. 如果列表消息從沒(méi)顯示過(guò)需要刷新列表,創(chuàng)建好一個(gè)cell后,將cell插入到第一位上,cell插入的性能要高于刷新tableview的性能。
    1. 如果消息已經(jīng)顯示過(guò)了,但是并不是第一位,則需要刷新列表。
    1. 如果消息已經(jīng)顯示,并且是第一位,則只需要cell的內(nèi)容變化。
    1. 只修改cell里的內(nèi)容,不進(jìn)行刷新cell整體,這里要注意的是,一定要最小化刷新。刷新點(diǎn)越小,性能損耗越小。我們項(xiàng)目架構(gòu)是MVVM,采用了ReactiveCocoa框架,針對(duì)每個(gè)cell上的可變化的控件數(shù)據(jù)進(jìn)行了監(jiān)聽(tīng),每一個(gè)cell上對(duì)應(yīng)一個(gè)vm,這樣當(dāng)vm上的數(shù)據(jù)變化時(shí)候,cell上的數(shù)據(jù)也就跟著變了。做到了最小化刷新。
    1. 避免使用autolayout計(jì)算位置,這個(gè)很重要,在性能要求高的情況下,autolayout計(jì)算會(huì)很耗時(shí)間,尤其在算tableview高度的時(shí)候可見(jiàn)一斑。可喜的是消息列表的高度是固定的,所以在計(jì)算高度時(shí)候我們并未花費(fèi)時(shí)間。
    1. 使用(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath而不使用-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier來(lái)查找cell,因?yàn)橄逻叺姆椒〞?huì)多查一次,耗時(shí)更長(zhǎng)一點(diǎn)。
    1. cellForRowAtIndexPath方法只負(fù)責(zé)創(chuàng)建cell,willDisplayCell方法才給cell進(jìn)行賦值操作。從方法名字就可以看出來(lái)原因
    1. 當(dāng)來(lái)消息轟炸時(shí)候,必然會(huì)是不同的人發(fā)來(lái)的消息,會(huì)導(dǎo)致tableview不可避免的刷新,如果不加處理必然會(huì)卡頓,要知道,機(jī)器也是有瓶頸的。這里我們做的優(yōu)化是根據(jù)cpu的使用率選擇性的刷新tableview。后來(lái)我們發(fā)現(xiàn)微信也是有這個(gè)現(xiàn)象,并不是實(shí)時(shí)的刷新,我們猜測(cè)也是類似處理。
    1. 重繪制系統(tǒng)控件,相信你也發(fā)現(xiàn)了消息列表里,主要有兩個(gè)控件,一個(gè)是頭像,一個(gè)是label。而系統(tǒng)的UIImageView用來(lái)顯示頭像,未免有點(diǎn)重。我們的處理是使用UIView,設(shè)置Viewlayer.content來(lái)處理。針對(duì)layer層做的setImageWithUrl的第三方庫(kù)也不少,大家可以自行查詢。另一個(gè)就是label,如果你能集成UIView自己繪制一個(gè)label,我想也許會(huì)有一點(diǎn)效果。

問(wèn): 聊天界面如何優(yōu)化?

聊天界面的優(yōu)化算是比較繁瑣的了,但是優(yōu)化點(diǎn)跟回話列表的優(yōu)化差不多。上邊提到回話列表里最耗時(shí)的tableview的高度是固定的,而聊天界面的幾乎每條消息的高度都可能不一樣,所以我們?cè)趦?yōu)化聊天界面時(shí)候最重要的一點(diǎn)就是計(jì)算tableviewcell的高度。而我們?cè)谟?jì)算tableview的高度是怎么做的呢?

主要有兩個(gè)準(zhǔn)則:
(1) 第一個(gè)是能在后臺(tái)線程執(zhí)行的都放在后臺(tái)線程里。
(2) 第二個(gè)計(jì)算高度要放在顯示之前。

    1. 巧妙的選擇控件。(比如上個(gè)問(wèn)題提到的用UIViewlayer.content來(lái)代替UIImageView, 圖片加點(diǎn)擊也可以用view,然后監(jiān)聽(tīng)viewtouch事件,像button這種重量級(jí)的控件在性能為主的app面前,我對(duì)他們都是棄之如敝履。)
    1. 減少使用layer層的cornerRadiusmask等圓角的繪制,這會(huì)引發(fā)離屏渲染,增加cpu的占用率。如果業(yè)務(wù)需要的話,我們可以通過(guò)UIBezierPath來(lái)drawInRect它。
    1. 避免設(shè)置透明
    1. 避免autolayout設(shè)定控件位置
    1. 盡可能的減少視圖的層級(jí),如果你能把所有的控件都繪制到一個(gè)View上,可想而知性能會(huì)爆棚。

問(wèn): Swift的可選類型?


問(wèn): Swift 中 Struct 和 Class的區(qū)別 ?

    1. property初始化的不同:
      主要的差別就是 class 在初始化時(shí)不能直接把 property 放在 默認(rèn)的constructor 的參數(shù)里,而是需要自己創(chuàng)建一個(gè)帶參數(shù)的 constructor
    1. 變量賦值方式不同(深淺copy)
      struct 賦值“=”的時(shí)候,會(huì)copy一份完整相同的內(nèi)容給另一個(gè)變量 -> 【開(kāi)辟了新的內(nèi)存地址】 (深拷貝)
      class 賦值“=”的時(shí)候,不會(huì)copy一份完整的內(nèi)容給另一個(gè)變量,只是增加了原變量?jī)?nèi)存地址的引用而已 -> 【沒(méi)有開(kāi)辟了新的內(nèi)存地址】 (淺拷貝)
    1. immutable 變量
      Swift 語(yǔ)言的特色之一就是可變動(dòng)內(nèi)容和不可變內(nèi)容用 varlet 來(lái)甄別,如果初始為let的變量再去修改會(huì)發(fā)生編譯錯(cuò)誤。
      struct也遵循這一特性
      class不存在這樣的問(wèn)題
    1. structclass 的差別是 structfunction 要去改變 property 的值的時(shí)候要加上 mutating,而 class 不用。
    1. struct不能繼承,class可以繼承。
    1. struct分配在棧中,class分配在堆中。

Swift 用 Struct 作為數(shù)據(jù)模型時(shí)需要注意什么問(wèn)題?

優(yōu)點(diǎn):
    1. 安全性:因?yàn)?Struct 是用值類型傳遞的,它們沒(méi)有引用計(jì)數(shù)。
    1. 內(nèi)存:由于他們沒(méi)有引用數(shù),他們不會(huì)因?yàn)檠h(huán)引用導(dǎo)致內(nèi)存泄漏。
    1. 速度:值類型通常來(lái)說(shuō)是以棧的形式分配的,而不是用堆。因此他們比 Class 要快很多!
    1. 拷貝:Objective-C 里拷貝一個(gè)對(duì)象,你必須選用正確的拷貝類型(深拷貝、淺拷貝),而值類型的拷貝則非常輕松!
    1. 線程安全:值類型是自動(dòng)線程安全的。無(wú)論你從哪個(gè)線程去訪問(wèn)你的 Struct ,都非常簡(jiǎn)單。
缺點(diǎn): (需要注意的地方)
    1. Objective-C:當(dāng)你的項(xiàng)目的代碼是 SwiftObjective-C 混合開(kāi)發(fā)時(shí),你會(huì)發(fā)現(xiàn)在 Objective-C 的代碼里無(wú)法調(diào)用 SwiftStruct。因?yàn)橐?Objective-C 里調(diào)用 Swift 代碼的話,對(duì)象需要繼承于 NSObject。
      Struct 不是 Objective-C 的好朋友。
    1. 繼承:Struct 不能相互繼承。
    1. NSUserDefaultsStruct 不能被序列化成 NSData 對(duì)象。
總結(jié):如果模型較小,并且無(wú)需繼承、無(wú)需儲(chǔ)存到 NSUserDefault 或者無(wú)需 Objective-C 使用時(shí),建議使用 Struct。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,697評(píng)論 1 32
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,839評(píng)論 4 61
  • 近年來(lái),中國(guó)美妝市場(chǎng)取得了高速增長(zhǎng),私護(hù)產(chǎn)業(yè)就在當(dāng)中占了很大的份額,對(duì)于20歲到50歲的女性來(lái)說(shuō),私護(hù)產(chǎn)品的存在就...
    多情怨閱讀 210評(píng)論 0 0
  • 計(jì)算一個(gè)二進(jìn)制數(shù)中的1的個(gè)數(shù) 1.循環(huán)法 首先二進(jìn)制數(shù)有這么一個(gè)性質(zhì),當(dāng)一個(gè)數(shù)減去1再與原來(lái)的數(shù)字去&運(yùn)算,得到的...
    senninha閱讀 873評(píng)論 0 0
  • 在這次運(yùn)動(dòng)會(huì)中,無(wú)論是成功者,還是失敗者,都體會(huì)到了什么是悲喜交加,喜怒哀樂(lè),生活就是這樣,有苦有甜。只要你認(rèn)真,...
    衛(wèi)校一五助產(chǎn)閱讀 549評(píng)論 0 0

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