iOS 面試題及答案20道41~60(三)

續(xù)寫iOS 面試題及答案20道21~40(二)

41.談?wù)剬C和Swift動態(tài)特性的理解

runtime其實就是OC的動態(tài)機制藤肢。runtime執(zhí)行的是編譯后的代碼,這時它可以動態(tài)加載對象瑟匆、添加方法憔杨、修改屬性、傳遞信息等。具體過程是督惰,在OC中,對像調(diào)用方法時旅掂,如[self.tableview reload],經(jīng)歷了兩個過程赏胚。

  1. 編譯階段: 編譯器會將OC代碼翻譯成objc_msgSend(self.tableview,@slector(reload)),把消息發(fā)送給self.tableview。
  2. 運行階段: 接收者(self.tableview)會響應(yīng)這個消息商虐,其間可能會直接執(zhí)行觉阅,轉(zhuǎn)發(fā)消息,也可能會找不到方法導(dǎo)致程序崩潰秘车。

所以典勇,整個流程是:編譯器翻譯->給接收者發(fā)送消息->接收者響應(yīng)消息。

接收者如何去響應(yīng)消息叮趴,就發(fā)生在運行時割笙。runtime執(zhí)行的是編譯后的代碼,而代碼的具體實現(xiàn)是運行時才能夠確定眯亦,這時它就可以動態(tài)加載對象伤溉、添加方法、修改屬性妻率、傳遞消息等乱顾。runtime的運行機制就是OC的動態(tài)特性。

Swift公認的是一個靜態(tài)語言宫静,它的動態(tài)特性都是通過橋接OC來實現(xiàn)的走净,像一些動態(tài)的特性其實是可以用Swift的面向協(xié)議的編程那樣使用的。

例子:
在OC中我們?nèi)討B(tài)的調(diào)用一個方法孤里,首先需要判斷這個方法是否存在然后再去調(diào)用它伏伯,這就是純正的動態(tài)特性:代碼

OC的動態(tài)特性

UserModel類的實現(xiàn)
@implementation UserModel
- (void)todoSomething{
    NSLog(@"正在做什么事情。");
}
@end

動態(tài)調(diào)用UserModel的方法扭粱。
UserModel *user = [UserModel new];
if([user respondsToSelector:NSSelectorFromString(@"todoSomething")]){
    [user performSelector:NSSelectorFromString(@"todoSomething")];
}

Swift的面向協(xié)議編程

面向協(xié)議的實現(xiàn)代碼
protocol TodoProtocol {
    func todosomething()
}

class UserModel: TodoProtocol {
    func todosomething() {
        print("要做的事情")
    }
}

調(diào)用代碼
let user:UserModel = UserModel()
if let user1 = user as? TodoProtocol {
    user1.todosomething()
    print("實現(xiàn)了這個協(xié)議")
}else{
    print("沒有實現(xiàn)這個協(xié)議")
}
這樣來使用舵鳞,這個協(xié)議的方法,其實這步驟判斷不需要因為swift中的協(xié)議的方法都是required的沒有optional琢蛤。

42.談?wù)刟s蜓堕、as!抛虏、as? 含義是什么?

1)as的三種使用方式

  • as第一種用法是將派生類轉(zhuǎn)換成基類套才,也就是說子類直接轉(zhuǎn)換成父類迂猴。 向上轉(zhuǎn)型。

代碼:

class Animal{
    var name:String
    init(_ name:String){
        self.name = name
    }
}
class catanimal : Animal {
}
class doganimal: Animal {
}
//as 向上強轉(zhuǎn) 子轉(zhuǎn)父
let cat = catanimal("湯姆") as Animal
let dog = doganimal("泰克") as Animal

showAnimalName(cat)
showAnimalName(dog)

如果是父類轉(zhuǎn)換成子類背伴,那么這種形式在Swift是會報錯的沸毁,就算是加上!強轉(zhuǎn)a!運行的時候也會崩潰。

  • as第二種用法消除多義性傻寂,數(shù)據(jù)類型轉(zhuǎn)換

比如說

let AnimalAge = 3 as Int  //3 有可能是Int 也有可能是CGFloat 也可能是long Int
let AnimalWeight = 20 as CGFloat
let AnimalHeight = (50 / 2) as Double
  • as的第三種用法switch語句中進行模式匹配息尺,通過switch愈發(fā)檢測對象的類型,根據(jù)對象類型進行處理疾掰。
switch animalType{
    case let animal as catanimal:
        print("是catanimal類型")
    case let animal as doganimal:
        print("是doganimal類型")
    default: break
}

2)as!的用法

向下轉(zhuǎn)型搂誉,強制轉(zhuǎn)換類型,有個缺點就是如果轉(zhuǎn)化失敗就會報錯誤静檬。
一般形式下可以這么使用炭懊,

catanimal是Animal的子類。

let animal:Animal = catanimal("湯姆")
let cat = animal as!catanimal

上述代碼就是將類型強制轉(zhuǎn)化拂檩,首先要注意一點侮腹,在強轉(zhuǎn)之前一定要判斷animal這個類是用catanimal這個類初始化的, 如果不這樣做的話稻励,是用Animal初始化的父阻,那么在第二行強制轉(zhuǎn)化的話就會報錯。

3)as?的用法

as?跟as!是一樣的用法钉迷,只不過as?如果轉(zhuǎn)化不成功的話會直接返回一個nil對象至非,成功的話返回可選類型。如果說能%100的會成功轉(zhuǎn)化那么請用as!如果說不能的話請用as?

使用例子:

let animal:Animal = catanimal("湯姆")
if let cat = animal as? catanimal {
    print("是catanimal類型")
}else{
    print("nil")
}

43.查看下述代碼輸出是什么糠聪?為什么荒椭?

protocol  Police{
    func HandlingCases()
}

extension Police{
    func HandlingCases(){
        print("Police doing Handling cases!" );
    }
}

struct Judge:Police{
    func HandlingCases(){
        print("Judge doing Handling cases!" );
    }
}

調(diào)用代碼
let police1:Police = Judge()
let police2:Judge = Judge()
    
police1.HandlingCases()
police2.HandlingCases()

兩個輸出的內(nèi)容都是Judge doing Handling cases!,
因為在Swift中protocol聲明了某個方法,在沒有extension擴展協(xié)議的情況下必須在實現(xiàn)類中實現(xiàn)該方法舰蟆,swift中的協(xié)議的方法都是required的趣惠,如果extension中實現(xiàn)了該方法,則在實現(xiàn)類Judge中可以不用去實現(xiàn)身害,一旦實現(xiàn)味悄,那么還是以實現(xiàn)類Judge的實現(xiàn)方法為準(zhǔn)。
HandlingCases方法在Police協(xié)議中聲明了塌鸯,police1雖然聲明的是Police但是實際實現(xiàn)還是Judge所以根據(jù)實際情況是調(diào)用了JudgeHandlingCases實現(xiàn)方法侍瑟。同樣道理police2也是如此。

但是如果說在Police中沒有生命方法HandlingCases,其他不變的情況下涨颜,那么police1费韭、police2的輸出就會不一樣了。因為police1的實際類型是Police庭瑰,Police中并沒有聲明HandlingCases,但是在類擴展中有實現(xiàn)該方法星持,實際類調(diào)用實際的方法,那么就會調(diào)用擴展類中實現(xiàn)HandlingCases弹灭,而police2的實際類型是Judge那肯定就會調(diào)用Judge中的實現(xiàn)方法督暂。

所以他們的輸出是:

police1輸出 Police doing Handling cases!

police2輸出 Judge doing Handling cases!

44.message send如果找不到對象,則會如何進行后續(xù)處理

這種形式一般會有兩種情況:1)對象是nil穷吮; 2)對象不為nil但是就是找不到對應(yīng)的方法逻翁;

1)對象為空的時候,在OC中向一個nil的對象發(fā)送消息是可以的酒来,如果這個方法的返回值是對象那么返回的是nil卢未,如果返回值是結(jié)構(gòu)體肪凛,那么就是0.
2)對象不為空堰汉,找不到方法,就會崩潰伟墙,報錯翘鸭。

45.method swizzling 是什么?

每一個類都會維護一個方法列表戳葵,并且方法名跟方法實現(xiàn)是一一對應(yīng)的就乓,也就是SEL(方法名)和IMP(方法實現(xiàn)的指針)的對應(yīng)關(guān)系,

method swizzling的意義就是運用runtime的特性跟方法來進行SEL和IMP這一對的IMP進行更換操作拱烁。如果SELa對應(yīng)IMPa SELb對應(yīng)IMPb 使用method swizzling后可以成為SELa對應(yīng)IMPb SELb對應(yīng)IMPa生蚁。

代碼實現(xiàn)

在本類實現(xiàn)2個方法:
- (void)onefunc{
    
    NSLog(@"one");
    
}

- (void)twofunc{
    
    NSLog(@"two");
    
}

在本類中調(diào)用代碼
SEL one = @selector(onefunc);
    
Method OneMethod = class_getInstanceMethod([self class], one);
    
SEL two = @selector(twofunc);
    
Method TwoMethod = class_getInstanceMethod([self class], two);
    
method_exchangeImplementations(OneMethod, TwoMethod);

這樣就可以看到調(diào)用onefunc會打印two, 調(diào)用twofunc會打印one

46.Swift和OCjective-C的自省(Introspection)有什么不同

自省在Objective-C中就是:判斷一個對象是否屬于某個類的操作戏自。它有兩種形式邦投。
[objc isKindOfClass:[SomeClass class]];
[objc isMemberOfClass:[SomeClass class]];

第一個判斷isKindOfClass是判斷objc是否為SomeClass或者其子類的實例對象。
第二個判斷isMemberOfClass是判斷objc僅僅是SomeClass這個類(非子類擅笔,當(dāng)前類)的實例對象志衣,并且不能檢測任何類都是基于NSObject類。

這兩種判斷的前提是objc必須是NSObject的子類猛们。

Swift中只有isKindOfClass類似的方法is念脯,很多的類并不是繼承自NSObject,不過比OC的功能更加強大弯淘,is可以判斷enum绿店、struct類型

自省操作一般和動態(tài)類型一起出現(xiàn),比如說OC中的id類型庐橙,以及Swift中的可選類型假勿、anyobject惕它。

cat是animal的子類
id animal = catInstance;

if([animal isKindOfClass:[animal class]]){
    NSLog(@"是 animal class");
    if(animal isMemberOfClass:[cat class]){
        NSLog(@"是 cat class");
    }
}else if([animal isKindOfClass:[any(其他類) class]]){
    NSLog(@"是 其他 class");
}

47.能否通過Category給已有的類添加屬性(property)

無論是Swift還是OC都可以用Category來添加屬性,只不過添加的方式不一樣废登。

Objective-C:
OC中通過Category中直接添加屬性(property)會報錯淹魄,提示找不到getter和setter方法,那是因為在Category中不會自動生成這兩個方法堡距,解決的方法就是運用runtime甲锡,關(guān)聯(lián)對象的形式來添加屬性,主要涉及到的兩個函數(shù)是羽戒,objc_getAssocicatedObject和objc_setAssociatedObject.
objc_getAssocicatedObject兩個參數(shù): 本類實例對象缤沦、 關(guān)聯(lián)屬性的key
objc_setAssociatedObject中的方法有4個參數(shù),分別是 本類實例對象易稠、關(guān)聯(lián)屬性的key缸废、新值、關(guān)聯(lián)策略驶社。

@interface UserModel : NSObject
@end
@implementation UserModel
@end


@interface UserModel(en)
@end

#import "UserModel+En.h"
#import <objc/runtime.h>

static void *EnNameKey = &EnNameKey;

@implementation UserModel(en)

-(void)setEnName:(NSString *)EnName{
    objc_setAssociatedObject(self, &EnNameKey, EnName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)EnName{
    return objc_getAssociatedObject(self, &EnNameKey);
}

@end

Swift跟Objective-C的使用方式差不多企量,如下代碼

class UserModel {
    var Name:String = "小明"
}
var EnNameKey:Void?
extension UserModel{
    
    var EnName:String? {
        
        get{
            return objc_getAssociatedObject(self, &EnNameKey) as? String
        }
    
        set{
            objc_setAssociatedObject(self, &EnNameKey, "你的英文名字", objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
        
    }
}

48.談?wù)効磳code你有多少理解。

iOS開的IDE是Xcode亡电,它是apple開發(fā)的主流工具届巩,目前Xcode已經(jīng)更新到了9個版本。功能蘊含了開發(fā)份乒、測試恕汇、性能分析、文檔查詢或辖、源代碼管理等多方面功能瘾英。

C、C++與Objective-C密不可分颂暇,自動化用Ruby缺谴,熟悉的工具:fastlane、cocoapods蟀架、Automation工具的腳本大多是用javaScript瓣赂,剛發(fā)布的coreML采用的模型工具則是用Python開發(fā)的。最新的Xcode采用完全由Swift重寫的Source Editor片拍,在代碼修改煌集、補全、模擬器運行方面有了很大的提升捌省,目前苫纤,Xcode最大的缺點是穩(wěn)定性還不夠。

Xcode工具想用的熟練,則必須從Intruments性能分析和LLDB調(diào)試卷拘,一步一步進行由淺入深喊废、Swift最新的Playground也是一個不錯的工具。

49.LLDB中的p和po的區(qū)別

  • p是exor的縮寫栗弟。它的工作是把接受到的參數(shù)在當(dāng)前環(huán)境下運行編譯污筷,人后打印出對應(yīng)的值。
  • Po即expr-o-乍赫。操作跟p相同瓣蛀,如果接收的是一個指針,那么它會調(diào)用對象的description方法并打永壮А惋增;如果接收到的參數(shù)是一個core foundation對象,那么它會調(diào)用CFShow方法并打印改鲫,如果兩個方法都調(diào)用失敗鸳吸,那么po打印出和p相同的內(nèi)容铭拧。
  • Po相對于p來說可以多打印一些內(nèi)容判导,一般用p即可疙筹,畢竟打印的東西越少越快,效率越高讲弄。如果需要查看詳情就用Po措左。

50.description方法是干什么用的?

這個是iOS對象默認的一個方法避除,它的輸出格式一般為<類名: 對象的內(nèi)存地址>
也可以自定義這個輸出格式,NSObject類所包含胸嘁。

51.Xcode中的Buildtime issues和Runtime issues指的是什么瓶摆?

Buildtime issues一般分為三類:編譯器識別出的警告(Warning)、錯誤(Error)和靜態(tài)分析(Static Code Analysis)性宏。前兩者一般經(jīng)常會遇到群井,不用多說,靜態(tài)分析也可以分為三種:1)未初始化變量毫胜,未使用數(shù)據(jù)和API使用錯誤书斜。

Swift代碼:

class CusViewController: UIViewController {
    override func viewDidLoad() {
        let PeopleList:[UserModel]
        let somePeopleList = PeopleList
        let otherPeopleList:[UserModel]?
    }
}

分析代碼:
PeopleList并沒有初始化就去賦值給somePeopleList所以是未初始化報錯。
otherPeopleList并沒有使用酵使,那么就會出現(xiàn)未使用的數(shù)據(jù)荐吉,在viewDidLoad中沒有使用super.viewDidLoad()那么就是Api調(diào)用錯誤。

Runtime issues也有三類錯誤:線程問題口渔、UI布局和渲染問題样屠、內(nèi)存問題。線程的相關(guān)問題最多,最常見的就是數(shù)據(jù)的競爭痪欲。

var num = 0
let addnum1 = 10,addnum2 = 100
    
DispatchQueue.global().async {
    for _ in 0...10{
        num += addnum1
    }
}
    
for _ in 0...10 {
    num += addnum2
}

兩個線程都對num進行寫操作悦穿,這樣的話,誰先操作业踢,那么值就會根據(jù)方法+幾 因為數(shù)據(jù)直接就存在了爭搶關(guān)系栗柒,當(dāng)然最終結(jié)果是一樣的,但是中間的先后順序就會打亂了知举。

UI布局和渲染上面的時候尺寸設(shè)定傍衡、布局沒有給全,渲染設(shè)定模糊负蠕,因而造成的autolayout無法渲染蛙埂。
內(nèi)存上的問題就是內(nèi)存泄漏,比如循環(huán)引用等遮糖。

52.App啟動時間過長绣的,該怎么去優(yōu)化?

導(dǎo)致App啟動時間過長的原因有多種欲账,從理論上面來講有兩種情況:1)main函數(shù)加在之前屡江;2)main還是加載之后。

main 函數(shù)加載之前赛不,如果想要分析這塊兒的代碼惩嘉,需要去Xcode中添加DYLD_PRINT_STATISTICS環(huán)境變量,并將其值設(shè)置為1踢故,這樣就可以得到如下的啟動日志:
還有很多的靜態(tài)變量文黎,如果想查看的話,在終端man dyld會打印出你要的靜態(tài)變量的列表殿较,可以一個一個的去打印看看耸峭。
例子:

Total pre-main time: 339.26 milliseconds (100.0%) //總的時間  毫秒
         dylib loading time: 154.24 milliseconds (45.4%) //庫加載
        rebase/binding time:  78.42 milliseconds (23.1%) //重定向/綁定
            ObjC setup time:  69.27 milliseconds (20.4%) //對象設(shè)置
           initializer time:  37.18 milliseconds (10.9%) //初始化
           slowest intializers :
             libSystem.B.dylib :   8.49 milliseconds (2.5%) //系統(tǒng)庫
    libMainThreadChecker.dylib :  17.09 milliseconds (5.0%) //系統(tǒng)庫

從上面打印的內(nèi)容來看,大致就是上面的四個方面: 動態(tài)庫加載淋纲、重定位綁定對象劳闹、設(shè)置對象、對象的初始化洽瞬。
通過上述打印我們可以通過以下方式來優(yōu)化App的啟動時間:

  • 減少動態(tài)庫的數(shù)量本涕,動態(tài)庫加載時間會減少,apple推薦的動態(tài)庫數(shù)量不超過6個伙窃。

  • 減少Objective-C的類數(shù)量菩颖,例如合并和刪除,這樣可以加快動態(tài)鏈接对供,重定位/綁定耗費的時間會相應(yīng)的減少位他。

  • 使用initialize方法替代load方法氛濒,或盡量將load方法中的代碼延后調(diào)用。對象的初始化所耗費的時間會相應(yīng)減少鹅髓。

在main之后的app啟動時間主要是要優(yōu)化第一個界面的渲染速度舞竿,主要是看進入Viewdidload viewwillAppear這兩個方法是否有其他操作。

53.如何檢測代碼中的循環(huán)引用窿冯?

目前所了解的有兩種方式:

1) 使用Xcode中的Memory Debug Graph骗奖。在Xcode中運行代碼,在有可能循環(huán)引用的地方添加斷點醒串,然后點擊如圖所示的按鈕就能查看是否循環(huán)引用执桌。

上圖中的內(nèi)容,點擊了這個按鈕以后左邊是類芜赌,右邊是類圖仰挣,其中誰引用了誰,這里很清楚的可以看到引用示意圖缠沈。

2) 使用Instruments里面的leaks選項--這是一個專門檢測內(nèi)存泄漏的工具膘壶,在進入首頁以后,發(fā)現(xiàn)leak Checks中出現(xiàn)內(nèi)存泄漏洲愤,就是出現(xiàn)小紅點的時候颓芭,可以將導(dǎo)航欄中的選項切換到call tree模式下,如果調(diào)試自己寫的代碼的話柬赐,建議勾選Display Settings 中勾選 "Separate by Thread"和"Hide System Libraries"兩個選項亡问。這樣可以隱藏系統(tǒng)和應(yīng)用程序本身的調(diào)用路徑,從而更方便地找出retain cycle位置肛宋。

54.怎么解決EXC_BAD_ACCESS

產(chǎn)生EXC_BAD_ACCESS的主要原因是訪問了某些已經(jīng)被釋放掉的對象州藕,或者訪問了它們已經(jīng)釋放的成員變量或方法。解決方法主要有下面幾種:

  • 設(shè)置全局斷點悼吱,快速定位缺陷所在:這種方法效果一般慎框。
  • 重寫Object和respondsToSelector方法:這個方法效果一般,并且要在每個class上進行定點排查后添,所以不推薦使用該方法。
  • 使用Zombie和Address Sanitizer:可以在絕大多數(shù)情況下定位問題代碼薪丁,

55.如何在Playground中執(zhí)行異步操作

閱讀下述代碼遇西,打印結(jié)果是什么?

import Foundation

let urlstr = URL.init(string: "https://api.apiopen.top/getSingleJoke")
let task = URLSession.shared.dataTask(with: urlstr!) { (data, response, error) in
    do {
        
        let dict:NSDictionary =  try JSONSerialization.jsonObject(with: data!, options: []) as! NSDictionary
        print(dict.object(forKey: "message") as! String)
        print(dict)
    } catch {
        print(error)
    }
} //這個是初始化任務(wù)严嗜,但是并沒有執(zhí)行粱檀,下面必須調(diào)用恢復(fù),證明這個任務(wù)已經(jīng)開始只不過暫停漫玄,字面意思哈茄蚯。

task.resume()  //恢復(fù)任務(wù)

答案是:什么都不會打印出來压彭,原因是playground在執(zhí)行完所有的操作以后會自動退出,要讓playground打印出異步執(zhí)行的內(nèi)容渗常,需要具備延時運行的特征壮不,所以需要在Playground中添加下述代碼:

import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

56.在Playground中實現(xiàn)一個10行的列表,每行顯示一個0~100的整數(shù)皱碘。

啥也不說了上代碼


import UIKit
import PlaygroundSupport

class ViewController :UITableViewController{
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
}

extension ViewController {
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text = "\(Int(arc4random_uniform(100)))"
        return cell
    }
    
}

PlaygroundPage.current.liveView = ViewController()

57.runtime如何實現(xiàn)weak變量的自動置nil询一?

//問題延伸
Weak指針不會增加所引用對象的引用計數(shù),并且在引用對象被回收的時候自動置nil癌椿,通常解決循環(huán)引用的問題健蕊,自動置nil的原理是什么?

Runtime維護了一個Weak的表踢俄,用于存儲指向某個對象的所有Weak指針缩功。Weak表就是一個hash表(哈希表),Key是所指對象地址都办,Value是Weak指針的地址(這個地址的值是所指對象的地址)的數(shù)組嫡锌。
在對象被回收的時候,經(jīng)過層層調(diào)用脆丁,會最終將這個Weak表中所有的Weak指針全部置nil世舰。

源碼在Runtime的源碼中有個文件objc-weak.mm 其中就有這段代碼。

/** 
 * Called by dealloc; nils out all weak pointers that point to the 
 * provided object so that they can no longer be used.
 * 
 * @param weak_table 
 * @param referent The object being deallocated. 
 */
void 
weak_clear_no_lock(weak_table_t *weak_table, id referent_id) 
{
    objc_object *referent = (objc_object *)referent_id;

    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
    if (entry == nil) {
        /// XXX shouldn't happen, but does with mismatched CF/objc
        //printf("XXX no entry for clear deallocating %p\n", referent);
        return;
    }

    // zero out references
    weak_referrer_t *referrers;
    size_t count;
    
    if (entry->out_of_line()) {
        referrers = entry->referrers;
        count = TABLE_SIZE(entry);
    } 
    else {
        referrers = entry->inline_referrers;
        count = WEAK_INLINE_COUNT;
    }
    
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            if (*referrer == referent) {
                *referrer = nil;
            }
            else if (*referrer) {
                _objc_inform("__weak variable at %p holds %p instead of %p. "
                             "This is probably incorrect use of "
                             "objc_storeWeak() and objc_loadWeak(). "
                             "Break on objc_weak_error to debug.\n", 
                             referrer, (void*)*referrer, (void*)referent);
                objc_weak_error();
            }
        }
    }
    
    weak_entry_remove(weak_table, entry);
}

根據(jù)對象地址槽卫,找到weak指針的數(shù)組跟压,遍歷所有數(shù)組的weak指針置nil,最后將這個entry從weak表中刪除 weak_entry_remove(weak_table, entry);

58.介紹一下GCD歼培、NSOperation震蒋、NSTread分別是是什么?NSOperation和GCD比有哪些優(yōu)缺點躲庄?

GCD是一個基于C語言的多線程編程的解決方式查剖。NSOperation是更加注重面向?qū)ο蟮亩嗑€程編程的解決方式。NSTread是一個輕量級的多線程編程方式噪窘。

NSOperation更加抽象化笋庄,抽象化的方式可以使多線程管理并發(fā),順序倔监,依賴關(guān)系時更加靈活:

  • 性能上:GCD接近底層直砂,基于C語言的代碼執(zhí)行更加高效,理論上速度比NSOperation快
  • 異步隊列操作上浩习,管理順序静暂、依賴關(guān)系,這些面向?qū)ο蟮木幊虝臃奖闳崿F(xiàn)谱秽,而GCD在這種方式上面會更加麻煩洽蛀,代碼量會更多摹迷。
  • 日常使用上,如果是簡單的異步操作回調(diào)的形式建議是GCD郊供,簡單方便峡碉,如果對一些異步操作管理過程中有更多的線程順序、依賴關(guān)系那么建議用NSOperation

最后扯個犢子颂碘, 這玩意就是看你用的哪個熟悉异赫。只要能夠快速準(zhǔn)確的實現(xiàn),用什么都是一樣的头岔。

59.怎么用Copy關(guān)鍵字

copy一般用在NSString塔拳、NSArray、NSDictionary等屬性字段的修飾符峡竣。

因為這些屬性都有與之對應(yīng)可變的子類靠抑。用copy修飾的上述幾個類型,在賦值的時候有坑會賦到可變的類型的指針适掰,如果這個可變子類用strong修飾颂碧,那么一旦這個可變對象的值被修改了,那么這個對象也就被修改了类浪,所以copy就是為了復(fù)制一份不可變的對象付給copy修飾的對象载城。

    //mutableString這個參數(shù)是類A的一個變量類型是NSMutableString
    NSMutableString* mutableString = [[NSMutableString alloc]initWithString:@"mutablestring"];
    
    UserModel *user = [[UserModel alloc]init];
    
    //首先將字符串賦值
    user.title = @"title";
    user.title = mutableString; //這時候title==mutableString==@"mutablestring"
    
    //修改mutableString的值
    [mutableString appendString:@"111"];
    
    //得到的結(jié)果是user.title == mutableString == @"mutablestring111"
    NSLog(@"title=%@--%p mutableString=%@--%p",user.title,user.title,mutableString,mutableString);

最終 title在不知不覺中就被修改了。所以用copy费就,修飾出來的屬性都是不可變的诉瓦。
在setter方法中:

- (void)setStr:(NSString*)str
    if(_Str != str){
        [_Str release];
        _Str = [str copy];
}

60.什么是MVC、MVP力细、MVVM睬澡?MVVM的每一層關(guān)系是什么?

MVC 是Model眠蚂、View煞聪、Controller。
View與Controller通信逝慧、Model與Controller通信 View與Model嚴格意義上是完全解耦合的昔脯。

  • View與Controller:

    • action:點擊、滑動笛臣、跳轉(zhuǎn)栅干、刷新UI、網(wǎng)絡(luò)請求等捐祠,用戶與View交互觸發(fā)、控制器方法
    • 委托delegate:View向Controller詢問一些自己無法做到的事情桑李,讓Controller去解決踱蛀,比如說獲取數(shù)據(jù)
    • 數(shù)據(jù)Model:View跟Controller要需要顯示的數(shù)據(jù)窿给,Controller需要訪問Model,從Model中獲取數(shù)據(jù)告訴View讓其顯示
  • Model與Controller

    • 廣播(Notification)率拒,Controller注冊監(jiān)聽Model的數(shù)據(jù)變化的通知崩泡,當(dāng)Model變化的時候告訴ControllerModel數(shù)據(jù)更新了
    • KVO(KEY-Value-Observing):Model作為Controller的屬性,Controller監(jiān)聽這個屬性變化猬膨,當(dāng)Model屬性被修改時角撞,這個Controller會接收到通知
分離了視圖層和業(yè)務(wù)層
耦合性低
開發(fā)速度快
可維護性高

MVP 是Model-View(Controller)-Presenter

MVP模式也是一種經(jīng)典的界面模式。MVP中的M代表Model, V是View, P是Presenter勃痴。在MVP里,Presenter完全把Model和View進行了分離沛申,主要的程序邏輯在Presenter里實現(xiàn)。而且尖淘,Presenter與具體的View是沒有直接關(guān)聯(lián)的,而是通過定義好的接口(協(xié)議)進行交互著觉,從而使得在變更View時候可以保持Presenter的不變,重用

優(yōu)點

低耦合
可重用性
獨立開發(fā)
可測試

缺點

如果view跟Presenter的交互太過于頻繁饼丘,那就會跟特定的界面過于緊密,如果視圖變更葬毫,那么presenter也要跟著變更了镇辉。

MVVM 是 Model View ViewModel

Model:業(yè)務(wù)邏輯處理贴捡、數(shù)據(jù)控制(本地緩存、網(wǎng)絡(luò)加載)
View(Controller):顯示用戶可見烂斋、用戶交互
ViewModel:組織View和Model的邏輯層

View綁定到ViewModel汛骂,然后執(zhí)行一些命令在向它請求一個動作。
ViewModel跟Model通訊帘瞭,反過來ViewModel在告訴View更新UI

優(yōu)點

低耦合
可重用性
獨立開發(fā)
可測試

缺點

因為ViewModel跟Presenter不一樣的是所有的數(shù)據(jù)都是協(xié)議蝶念、接口回調(diào),而ViewModel則是數(shù)據(jù)綁定到View上面担敌,如果是數(shù)據(jù)bug問題全封,很難定位到數(shù)據(jù)哪一步出錯马昙。
在一個模塊中  viewModel中如果Model的數(shù)據(jù)很大刹悴,長期不釋放颂跨,這是一個不必要的花銷。
數(shù)據(jù)雙向綁定不利于代碼的重用恒削,開發(fā)中常見的重用都是view钓丰,一個view中綁定一個model,不同的模塊中的model不同琢歇,到時候如果只簡單的重用view梦鉴,Model不做任何變化的話不太現(xiàn)實肥橙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宠互,隨后出現(xiàn)的幾起案子椭坚,更是在濱河造成了極大的恐慌善茎,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,835評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汁掠,死亡現(xiàn)場離奇詭異考阱,居然都是意外死亡鞠苟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評論 2 383
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跨细,“玉大人冀惭,你說我怎么就攤上這事∶铰ィ” “怎么了戚丸?”我有些...
    開封第一講書人閱讀 156,481評論 0 345
  • 文/不壞的土叔 我叫張陵限府,是天一觀的道長。 經(jīng)常有香客問我世澜,道長姻几,這世上最難降的妖魔是什么蛇捌? 我笑而不...
    開封第一講書人閱讀 56,303評論 1 282
  • 正文 為了忘掉前任络拌,我火速辦了婚禮,結(jié)果婚禮上混萝,老公的妹妹穿的比我還像新娘。我一直安慰自己车要,他們只是感情好崭倘,可當(dāng)我...
    茶點故事閱讀 65,375評論 5 384
  • 文/花漫 我一把揭開白布司光。 她就那樣靜靜地躺著,像睡著了一般榆俺。 火紅的嫁衣襯著肌膚如雪坞淮。 梳的紋絲不亂的頭發(fā)上碾盐,一...
    開封第一講書人閱讀 49,729評論 1 289
  • 那天毫玖,我揣著相機與錄音,去河邊找鬼烹玉。 笑死阐滩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的继效。 我是一名探鬼主播装获,決...
    沈念sama閱讀 38,877評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼穴豫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了秤涩?” 一聲冷哼從身側(cè)響起筐眷,我...
    開封第一講書人閱讀 37,633評論 0 266
  • 序言:老撾萬榮一對情侶失蹤浊竟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肉拓,經(jīng)...
    沈念sama閱讀 44,088評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡暖途,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,443評論 2 326
  • 正文 我和宋清朗相戀三年驻售,在試婚紗的時候發(fā)現(xiàn)自己被綠了欺栗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,563評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡消请,死狀恐怖类腮,靈堂內(nèi)的尸體忽然破棺而出蚜枢,到底是詐尸還是另有隱情,我是刑警寧澤需频,帶...
    沈念sama閱讀 34,251評論 4 328
  • 正文 年R本政府宣布贺辰,位于F島的核電站,受9級特大地震影響莽鸭,放射性物質(zhì)發(fā)生泄漏吃靠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,827評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望族奢。 院中可真熱鬧越走,春花似錦、人聲如沸铜跑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嚼锄,卻和暖如春区丑,著一層夾襖步出監(jiān)牢的瞬間修陡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評論 1 264
  • 我被黑心中介騙來泰國打工宴杀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旺罢,地道東北人。 一個月前我還...
    沈念sama閱讀 46,240評論 2 360
  • 正文 我出身青樓正卧,卻偏偏與公主長得像炉旷,于是被迫代替她去往敵國和親叉讥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,435評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 基礎(chǔ) 1. 為什么說Objective-C是一門動態(tài)的語言? 2. 講一下MVC和MVVM翘骂,MVP帚豪? 3. 為...
    波妞和醬豆子閱讀 3,311評論 0 46
  • 續(xù)寫iOS 面試題及答案20道(一) 21.OC中什么是ARC狸臣?Objective-C的內(nèi)存管理機制是什么昌执? AR...
    struggle3g閱讀 1,326評論 0 6
  • 丫頭懂拾,你知道你昨天晚上有多美么,就像明星一樣檬果,尤其是低頭的時候唐断,頭發(fā)垂下脸甘,看的我驚心動魄。 昨天和你吵架在這里和你...
    海綿寶寶的小盤子閱讀 195評論 0 0
  • 在我身邊的許多動物都是最最常見的钝的。然而可愛的動物卻是成千上萬硝桩,數(shù)也數(shù)不清。如果說哪種動物才是最可愛的邢疙,在我...
    亂世浮華_8244閱讀 154評論 0 0
  • 轉(zhuǎn)眼疟游,一個學(xué)期的教育教學(xué)工作已經(jīng)結(jié)束了痕支,回顧這一學(xué)期以來,學(xué)生的點滴進步讓我無比欣慰另绩,但還存在著一些問題花嘶,今后還需...
    一簾夢幻葛寶梅閱讀 213評論 0 1