天天看點

OC學習日記11-KVC和KVOKVC和KVO

KVC和KVO

OC學習日記11-KVC和KVOKVC和KVO

前言

相信在OC裡面自學最有難度就是這個KVC和KVO了,很多人都不明白這個東西是什麼,經過老師的講解和我自己的了解,我是這樣看的:KVC是在原來OC舊版本裡面還沒有設定器跟通路器的時候,用于對受保護的成員變量進行設定和通路的,是以我們要用KVC進行讀寫,在現在,KVC最大的作用就是動态通路某些變量的時候,縮減代碼量,提高我們程式的可擴充性。

KVC

設計模式 -觀察者模式

設計模式是用來解決某一特定問題
           

觀察者模式

什麼是觀察者模式?

在工程中,一些類去觀察‘A’類,當‘A’類發生變化時,這些類就會收到消息,做出相應反應。
           

什麼時候使用觀察者模式?

當一個類需要發送消息給多個類的時候,就用觀察者模式。
           

觀察者模式的作用?

一對多的消息發送
           

在OC中如何實作觀察者模式?

OC中,觀察者模式的設計基礎,KVC/KVO
 KVC(鍵值編碼 Key-Value Coding)
 KVC提供了一種在運作時而非編譯時動态通路對象屬性與執行個體變量的方式。
           

建立一個學生Student的類

@interface Student : NSObject
{
    NSString *_name;
    NSInteger _age;
}
@property (nonatomic,strong)NSString *address;
           

重寫description方法

@implementation Student
-(NSString *)description{
    return [NSString stringWithFormat:@"My name is %@,%lu years old,living in %@",_name,_age,_address];
}
           

setValue forKey和valueForKey

設定一個學生類的對象,以及用setValue forKey的方式對它的成員變量指派。

Student *stu1=[Student new];
    [stu1 setValue:@"Rick" forKey:@"_name"];
    [stu1 setValue:@ forKey:@"_age"];
    [stu1 setValue:@"GZ" forKey:@"_address"];
    NSLog(@"%@",stu1);
           

用valueForKey進行通路

NSString *name=[stu1 valueForKey:@"_name"];
NSNumber *age=[stu1 valueForKey:@"_age"];
NSString *address=[stu1 valueForKey:@"_address"];
NSLog(@"name = %@, age = %@,address = %@",name,age,address);
           

動态通路

動态通路某些屬性時,使用一些可以運作時而不是編譯時改變的值

student.h檔案中

@property (nonatomic,assign)int p1;
@property (nonatomic,assign)int p2;
@property (nonatomic,assign)int p3;
-(int)getValuePropertyName:(NSString *)name;
-(int)getNewValuePropertyName:(NSString *)name;
           

我們可以通過寫兩個PropertyName方法去說明一下動态通路

student.m檔案中

-(int)getValuePropertyName:(NSString *)name{
    NSString *[email protected]"p1";
    NSString *[email protected]"p2";
    NSString *[email protected]"p3";
    if ([stu1 isEqualToString:name ]) {
        return self.p1;
    }
    else if ([stu2 isEqualToString:name ]) {
        return self.p2;
    }
    else if ([stu3 isEqualToString:name ]) {
        return self.p3;
    }
    else
    return ;
}
-(int)getNewValuePropertyName:(NSString *)name{
    NSNumber *number=[self valueForKey:name];
    return [number intValue];
}
           

主函數main.m

stu1.p1=;
    stu1.p2=;
    stu1.p3=;
    int a=[stu1 getValuePropertyName:@"p1"];
    NSLog(@"%d",a);

    int b=[stu1 getNewValuePropertyName:@"p1"];
    NSLog(@"%d",b);
    Book *book=[[Book alloc]init] ;
           

鍵路徑編碼

@interface Book : NSObject
{
    NSString *_bookName;
}
           

在student.h檔案中導入Book的頭檔案:#import “Book.h”

在主函數main.m中

[stu1 setValue:book forKeyPath:@"_book"];
    [stu1 setValue:@"葵花寶典,欲練神功" forKeyPath:@"_book._bookName"];
    NSString *bookName=[stu1 valueForKeyPath:@"_book._bookName"];
   NSLog(@"bookName = %@",bookName);
           

KVO

KVO的由來:

在程式設計的過程中,我們經常需要判斷目标是否發生變化,以便及時地做出對應的處理,此時蘋果公司就提供了一種政策,即‘OC運作時’提供了‘KVO’技術,其中‘KVO’是基于‘KVC’實作
 KVO的實作:
 1.注冊成為觀察者
 2.觀察者定義KVO回顧
 3.移除觀察者
 */


Hero *hero=[Hero new];

[hero setValue:@100 forKey:@"_hp"];
Observer *observer = [[Observer alloc]initWithHero:hero];
[hero setValue:@300 forKey:@"_hp"];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(Time:) userInfo:nil repeats:YES];
_hero = hero;
_observer=observer;
           

}

-(void)Time:(NSTimer *)timer{

NSUInteger _cutHP=[[_hero valueForKey:@”_hp”]integerValue];

_cutHP -=50;
if (_cutHP<=0) {
    NSLog(@"英雄挂了");
    [_hero setValue:@0 forKey:@"_hp"];
    [timer invalidate];

}
else{
    [_hero setValue:@(_cutHP) forKey:@"_hp"];
}
           

}

#import <Foundation/Foundation.h>
#import "Hero.h"
@interface Observer : NSObject
@property (nonatomic,strong)Hero *hero;
-(id)initWithHero:(Hero *)hero;
@end
           
-(id)initWithHero:(Hero *)hero{
    if (self =[super init]) {

        self.hero=hero;
        //1.注冊成為觀察者
        /*表示接受通知的對象,即觀察者,通常self
         建路徑參數,要觀察的鍵路徑
         标志KVO希望變化如何傳遞給觀察者,這些值可以使用‘|’進行多選
         上下文記憶體區,通常為nil
         */
        [self.hero addObserver:self forKeyPath:@"_hp" options:NSKeyValueObservingOptionNew context:nil];



    }
    return self;
}


//定義回溯
-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary<NSString *,id> *)change
                      context:(void *)context{
    NSLog(@"%@",[change objectForKey:NSKeyValueChangeNewKey]);
}

-(void)dealloc{
    NSLog(@"我挂了");
    /*
     移除的觀察者對象
     觀察的鍵路徑
     */
    [self.hero removeObserver:self forKeyPath:@"_hp"];
}
           
@interface Hero : NSObject
{
    NSUInteger _hp;
}
@end