iOS基礎(chǔ) 3.0

前言

6、什么是KVC、KVO?
7、通知和協(xié)議的不同之處?
8、單例是什么?優(yōu)缺點是什么?
9、什么是懶加載?優(yōu)缺點是什么?
10、static什么時候使用?有什么作用?

6、什么是KVC、KVO?

KVC(Key-Value Coding)
??KVC是一種通過鍵值訪問對象的屬性的機(jī)制,允許通過鍵(屬性名)來訪問修改對象的屬性值。這使得我們可以通過字符串形式訪問對象的屬性,而不需要直接調(diào)用相應(yīng)的方法。

在項目中,以下一些情況下你可能會使用KVC
1、設(shè)置和獲取對象的屬性
??KVC提供了一種方便的方式來設(shè)置和獲取對象的屬性,尤其是當(dāng)屬性名以字符串形式存在時。這對于在運(yùn)行時動態(tài)地訪問或修改對象的屬性非常有用。

// 設(shè)置對象屬性
[object setValue:@"John" forKey:@"name"];

// 獲取對象屬性
NSString *name = [object valueForKey:@"name"];

2、字典和模型的轉(zhuǎn)換
??當(dāng)從服務(wù)器或其他數(shù)據(jù)源獲得數(shù)據(jù)時,通常以字典的形式提供。使用KVC,你可以方便將字典中的鍵值對映射到對象的屬性,實現(xiàn)字典和模型對象之間的轉(zhuǎn)換。

NSDictionary *data = @{@"name": @"John", @"age": @25};

// 使用KVC將字典轉(zhuǎn)換為對象
Person *person = [[Person alloc] init];
[person setValuesForKeysWithDictionary:data];

3、動態(tài)地訪問屬性
??當(dāng)需要動態(tài)地訪問或操作對象的屬性時,KVC提供了一種方便的機(jī)制。這對于通用的數(shù)據(jù)操作、表單處理等場景非常有用。

NSString *propertyName = @"name";
NSString *propertyValue = [object valueForKey:propertyName];

4、集合操作
??KVC提供了一套用于集合操作的方法,例如對數(shù)組中的每個元素執(zhí)行某個操作、計算數(shù)組中的最大或最小值等。這對于處理集合數(shù)據(jù)非常方便。

NSArray *numbers = @[ @10, @20, @30 ];

// 計算數(shù)組中的總和
NSNumber *sum = [numbers valueForKeyPath:@"@sum.self"];

5、在自定義控制臺輸出中使用
??在調(diào)試時,通過覆蓋description方法并使用KVC來生成自定義控制臺輸出,可以方便地查看對象的內(nèi)部狀態(tài)。

- (NSString *)description {
    return [NSString stringWithFormat:@"Person - Name: %@, Age: %@", [self valueForKey:@"name"], [self valueForKey:@"age"]];
}

優(yōu)點:

  • 靈活性:提供了一種靈活的方式來訪問和修改對象的屬性,特別是在處理動態(tài)和未知屬性的情況下。
  • 簡化代碼:通過KVC,可以減少訪問和修改對象屬性的代碼量,使代碼更加簡潔。
//正常情況下某個類的創(chuàng)建
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;

@end


//使用KVC
NSDictionary *data = @{@"name": @"John", @"age": @25};
// 使用 KVC 將字典轉(zhuǎn)換為對象
Person *person = [[Person alloc] init];
[person setValuesForKeysWithDictionary:data];
  • 便于集合操作:提供了一套用于集合操作的方法,例如對數(shù)組中的每個元素執(zhí)行某個操作、計算數(shù)組中的最大或最小值等。
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;

@end

@implementation Person
@end

// 創(chuàng)建包含 Person 對象的數(shù)組
NSArray *people = @[ [[Person alloc] initWithName:@"John"],
                    [[Person alloc] initWithName:@"Jane"],
                    [[Person alloc] initWithName:@"Bob"] ];

// 使用 KVC 獲取所有人的姓名組成的新數(shù)組
NSArray *names = [people valueForKeyPath:@"@each.name"];

NSLog(@"Names: %@", names);
  • 實現(xiàn)通用方法:使得能夠?qū)崿F(xiàn)通用的數(shù)據(jù) 操作,例如字典和模型之間的轉(zhuǎn)換。

缺點

  • 運(yùn)行時錯誤:由于KVC使用字符串形式來訪問屬性,編譯器無法提供錯誤檢查,因此在運(yùn)行時可能會發(fā)生拼寫錯誤或傳遞了不存在的屬性名,導(dǎo)致崩潰。
  • 性能開銷:相對于直接方法調(diào)用,KVC的性能開銷較大。因此,對性能有嚴(yán)格要求的場景下,可能不適合大規(guī)模使用KVC。
  • 不支持編譯器優(yōu)化:不容易被編譯器優(yōu)化,因為它是在運(yùn)行時動態(tài)解析的,這可能導(dǎo)致一些性能上的損失。

KVO(Key-Value Observing)
??KVO允許一個對象監(jiān)聽另一個對象特定屬性值的變化。當(dāng)被觀察的對象的屬性發(fā)生改變時,觀察者會收到通知。這提供了一種在對象之間保持同步的機(jī)制。

在項目中,以下一些情況下你可能會使用KVO
1、UI更新
??當(dāng)數(shù)據(jù)模型的屬性變化時,需要更新用戶界面。

// 添加 KVO 觀察者
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

// 實現(xiàn) KVO 觀察者方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        // 在這里執(zhí)行刷新 UI 的操作
        [self updateUIWithNewName:change[NSKeyValueChangeNewKey]];
    }
}

2、數(shù)據(jù)同步
??當(dāng)多個對象之間需要保持?jǐn)?shù)據(jù)同步時,可以使用KVO。一個對象的屬性變化將會通知到觀察者觀察者可以做出相應(yīng)的響應(yīng),保持?jǐn)?shù)據(jù)的一致性
3、觀察屬性變化執(zhí)行特定操作
??在屬性變化時,需要執(zhí)行一些特點的操作,而不是僅僅更新UI。
4、監(jiān)控網(wǎng)絡(luò)請求狀態(tài)
??在進(jìn)行網(wǎng)絡(luò)請求時,有時需要監(jiān)控網(wǎng)絡(luò)請求的狀態(tài)變化,以便在請求完成時執(zhí)行一些操作。
5、自定義觀察者模式
??KVO提供了一種機(jī)制來實現(xiàn)觀察者模式,用于建立對象之間的通信。這樣可以減少對象之間的直接耦合。

ps:使用KVO時應(yīng)該遵循一些最佳實踐,如正確注冊移除觀察者,處理觀察者通知時的線程安全等。

優(yōu)點

  • 松耦合:KVO實現(xiàn)了觀察者模式,使得觀察者(監(jiān)聽者)和被觀察者之間的耦合度較低。對象不需要直接調(diào)用觀察者的方法,而是通過通知的方式進(jìn)行通信。
  • 動態(tài)性:KVO允許在運(yùn)行時動態(tài)地注冊和取消觀察者,以及動態(tài)地選擇觀察的屬性。這種動態(tài)性使得在不同場景下適應(yīng)變化更加容易。
// 被觀察的對象
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;

@end

@implementation Person
@end

// 觀察者
@interface Observer : NSObject

@end

@implementation Observer

- (instancetype)init {
    self = [super init];
    if (self) {
        // 創(chuàng)建被觀察對象
        Person *person = [[Person alloc] init];

        // 添加觀察者
        [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

        // 模擬屬性變化,觸發(fā) KVO
        person.name = @"John";

        // 移除觀察者
        [person removeObserver:self forKeyPath:@"name"];
    }
    return self;
}

// 實現(xiàn) KVO 觀察者方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"Name changed to: %@", change[NSKeyValueChangeNewKey]);
    }
}

@end
  • 簡化代碼:使用KVO可以簡化代碼,特別是在需要響應(yīng)屬性變化并執(zhí)行相應(yīng)操作的情況下。這有助于避免在代碼中插入大量的回調(diào)方法。

缺點

  • 難以調(diào)試:由于KVO是在運(yùn)行時進(jìn)行動態(tài)注冊移除的,因此在調(diào)試時可能會導(dǎo)致一些難以追蹤的問題。觀察者的添加和移除時機(jī)需要特別注意,否則可能會導(dǎo)致崩潰不符合預(yù)期的行為。
  • 性能開銷:KVO的實現(xiàn)涉及到動態(tài)方法解析消息轉(zhuǎn)發(fā),相對于直接調(diào)用方法來說,會有一些性能開銷。在性能要求較高的場景中,可能需要謹(jǐn)慎使用KVO。
  • 不支持對基本數(shù)據(jù)類型的直接觀察:KVO主要適用于對象,不直接支持對基本數(shù)據(jù)類型(例如NSInteger、CGFloat等)的觀察。

7、通知和協(xié)議的不同之處?

??通知協(xié)議時iOS中兩種不同的機(jī)制,用于實現(xiàn)對象之間的通信和協(xié)作。

通知

  • 發(fā)布/訂閱模式:采用發(fā)布/訂閱模式,允許一個對象發(fā)布通知,而其他對象則可以注冊成為觀察者并在通知發(fā)生時得到通知。
  • 中心化管理:通知的管理由通知中心(NSNotificationCenter)來完成,對象通過通知中心注冊和接收通知。
  • 一對多關(guān)系:一個通知可以有多個觀察者,觀察者可以訂閱多個通知。
  • 松散耦合:發(fā)送通知的對象和接收通知的對象之間的關(guān)系相對松散,它們不需要直接知道對方的存在。
  • 異步:通知是異步的,通知的發(fā)送和接收不需要在同一時間和線程上。
// 發(fā)送通知的代碼
[[NSNotificationCenter defaultCenter] postNotificationName:@"SomeNotification" object:nil];

// 接收通知的代碼
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"SomeNotification" object:nil];

// 通知處理方法
- (void)handleNotification:(NSNotification *)notification {
    NSLog(@"Received notification: %@", notification.name);
}

協(xié)議

  • 定義接口:協(xié)議定義了一組方法,表示一種接口,對象通過采用協(xié)議來表明它們實現(xiàn)了這個接口。
  • 實現(xiàn):一個類可以采用一個或多個協(xié)議,表示它們具有協(xié)議定義的方法。
  • 強(qiáng)制執(zhí)行:采用協(xié)議的類必須實現(xiàn)協(xié)議中定義的所有方法,否則會在編譯時報錯
  • 一對一關(guān)系:協(xié)議通常用于實現(xiàn)一對一的關(guān)系,一個類實現(xiàn)一個協(xié)議。
  • 編譯時檢查:編譯器會檢查是否實現(xiàn)了協(xié)議中的所有方法,確保符合協(xié)議的要求
// 定義一個協(xié)議
@protocol MyProtocol
- (void)doSomething;
@end

// 類采用協(xié)議
@interface MyClass : NSObject <MyProtocol>
@end

@implementation MyClass
- (void)doSomething {
    NSLog(@"Doing something");
}
@end

如果通信涉及到多個對象,且這些對象之間的關(guān)系比較松散通知是一個不錯的選擇。

如果通信是一對一的關(guān)系,并且需要確保采用協(xié)議的對象實現(xiàn)了一組特定的方法,協(xié)議是更適合的選擇。

8、單例是什么?優(yōu)缺點是什么?

??單例是一種設(shè)計模式,它確保一個類只有一個實例,并提供一個全局訪問點來獲取該實例。單例模式通常使用靜態(tài)方法或類方法(類似于sharedInstance)來返回唯一的實例。

優(yōu)點

  • 全局訪問:可以在整個應(yīng)用程序中通過單一的訪問點獲取相同的實例,方便數(shù)據(jù)共享操作。
  • 避免重復(fù)創(chuàng)建:由于單例只有一個實例,可以避免重復(fù)創(chuàng)建相同類型的對象,減少資源占用。
  • 共享狀態(tài):單例可以用于共享狀態(tài),例如應(yīng)用配置信息、登錄狀態(tài)等。

缺點

  • 全局狀態(tài):單例引入了全局狀態(tài),可能會導(dǎo)致代碼的耦合性增加,使得代碼難以測試和維護(hù)。
  • 隱藏依賴:在某些情況下,單例可能會隱藏類之間的依賴關(guān)系,增加代碼的復(fù)雜性。
  • 生命周期管理:單例的生命周期通常貫穿整個應(yīng)用程序,可能會導(dǎo)致對象持有時間過長,無法及時釋放。
// MySingleton.h
@interface MySingleton : NSObject

@property (nonatomic, strong) NSString *data;

+ (instancetype)sharedInstance;

@end

// MySingleton.m
@implementation MySingleton

// 靜態(tài)變量用于保存唯一實例
static MySingleton *_sharedInstance = nil;

+ (instancetype)sharedInstance {
    // 使用GCD確保線程安全創(chuàng)建單例
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[super alloc] init];
    });

    return _sharedInstance;
}

- (instancetype)init {
    // 防止通過init方法創(chuàng)建新的實例
    NSAssert(!_sharedInstance, @"Use sharedInstance method to get the instance.");
    self = [super init];
    if (self) {
        // 初始化
    }
    return self;
}
@end

9、什么是懶加載?優(yōu)缺點是什么?

??懶加載是一種延遲加載對象或執(zhí)行操作的技術(shù),它在需要的時候才進(jìn)行加載執(zhí)行,而不是在應(yīng)用啟動時就立即加載或執(zhí)行。懶加載通常用于延遲加載視圖、數(shù)據(jù)或其他資源,以提高應(yīng)用程序的性能資源利用率。

優(yōu)點

  • 性能優(yōu)化:懶加載可以減少應(yīng)用程序啟動時資源消耗,因為只有在需要的時候才會加載相應(yīng)的對象或執(zhí)行相關(guān)的操作。這有助于提高應(yīng)用程序的啟動速度響應(yīng)性能。

  • 節(jié)省資源:對于一些不一定會被使用的對象數(shù)據(jù),懶加載可以避免不必要的資源占用,從而節(jié)省內(nèi)存其他系統(tǒng)資源。

  • 更快的啟動時間:通過延遲加載,應(yīng)用程序啟動時需要加載的資源較少,從而加快啟動時間。

缺點

  • 復(fù)雜性增加:在代碼中使用懶加載可能會增加代碼的復(fù)雜性,因為你需要管理對象的狀態(tài)并確保在需要時正確地進(jìn)行加載。這可能導(dǎo)致一些潛在的錯誤,如內(nèi)存泄露邏輯錯誤

  • 可能引起延遲:如果懶加載的時機(jī)選擇不當(dāng),可能導(dǎo)致在需要對象或數(shù)據(jù)時出現(xiàn)短暫的延遲,因為此時才進(jìn)行加載。

  • 可能影響代碼可讀性:過度使用懶加載可能會導(dǎo)致代碼難以理解,特別是對于新加入的開發(fā)人員。適度使用,并在必要時添加注釋以解釋懶加載的原因和時機(jī)。

10、static什么時候使用?有什么作用?

??static關(guān)鍵字用于不同的上下文,其作用取決于它所修飾的內(nèi)容。

1、靜態(tài)局部變量:在方法調(diào)用之間保留其值,而不像普通局部變量那樣在每次調(diào)用時重新初始化。這可以用于實現(xiàn)在方法之間保持狀態(tài)的需求。

- (void)someMethod {
    static NSInteger counter = 0;
    counter++;
    NSLog(@"Counter: %ld", counter);
}

2、靜態(tài)全局變量:在文件范圍內(nèi)可見,但是其作用域限制在當(dāng)前文件中。這可以用于在整個文件中共享狀態(tài)或數(shù)據(jù)

// 在文件的頂部或?qū)崿F(xiàn)文件的全局作用域內(nèi)
static NSInteger globalCounter = 0;

- (void)someMethod {
    globalCounter++;
    NSLog(@"Global Counter: %ld", globalCounter);
}

3、靜態(tài)函數(shù):作用域限制在當(dāng)前文件中,不可被其他文件訪問。這可以用于實現(xiàn)文件內(nèi)部的私有函數(shù),不暴露給其他文件使用。

// 在文件的頂部或?qū)崿F(xiàn)文件的全局作用域內(nèi)
static NSInteger multiplyByTwo(NSInteger number) {
    return number * 2;
}

- (void)someMethod {
    NSInteger result = multiplyByTwo(5);
    NSLog(@"Result: %ld", result);
}

4、靜態(tài)常量:用于定義在整個文件內(nèi)都可見的常量,避免魔法數(shù)字的使用。常量通常以static const的形式定義,確保其在編譯時被優(yōu)化。

static const NSInteger MaxItemCount = 10;

- (void)someMethod {
    NSLog(@"Max Item Count: %ld", MaxItemCount);
}
  • static的主要作用是限制變量或函數(shù)的作用域,使其僅在定義它們的文件內(nèi)可見。

  • 方法內(nèi)部使用static關(guān)鍵字可以使局部變量在方法調(diào)用之間保留其值

  • 全局范圍內(nèi)使用static可以限制變量、函數(shù)或常量的作用域,使其在當(dāng)前文件中可見。

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

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

  • OC的理解與特性 OC作為一門面向?qū)ο蟮恼Z言,自然具有面向?qū)ο蟮恼Z言特性:封裝、繼承、多態(tài)。它既具有靜態(tài)語言的特性...
    蝸牛上上升閱讀 920評論 0 0
  • 1. 父類實現(xiàn)深拷貝時,子類如何實現(xiàn)深度拷貝。父類沒有實現(xiàn)深拷貝時,子類如何實現(xiàn)深度拷貝。 1.1 深拷貝同淺拷貝...
    iYeso閱讀 1,968評論 0 13
  • 1. 父類實現(xiàn)深拷貝時,子類如何實現(xiàn)深度拷貝。父類沒有實現(xiàn)深拷貝時,子類如何實現(xiàn)深度拷貝。 1.1 深拷貝同淺拷貝...
    i愛吃土豆的貓閱讀 506評論 0 1
  • 1、category和extension的區(qū)別 category是分類,可以為類增加自定義方法 extension...
    大猿媛閱讀 402評論 1 1
  • 一、類別 OC不像C++等高級語言能直接繼承多個類,不過OC可以使用類別和協(xié)議來實現(xiàn)多繼承。 1、類別加載時機(jī) 在...
    笨笨編程閱讀 395評論 0 0

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