day3---通知、KVC/KVO、XML解析

一 通知
1.1 概念
通知(Notification)是观察者模式的一种具体表现,可以理解为广播模式,广播模式也是一种设计模式,类似于生活中的广播,比如:收音机。。

1.2 作用
一个对象不用知道消息的接受者是谁,就可以将一些消息发送给需要的接受者,要求,这些接受者必须先注册这个通知;
发送消息的对象无法知道有哪些对象,有多少个对象接受消息,也不知道这些对象是否存在,   
1.3 如何使用?
1)收听者打开收音机听广播,即找到一个通知中心NSNotificationCenter;
2)设置收听的频道,即注册收听哪个具体的频道(addObserver专门用来注册的方法)
3)发送者首先找到通知中心NSNotificationCenter,创建具体的通知对象NSNotification,使用通知中心发送通知;
4)收听者收到消息,处理消息响应相关的方法;
5)在不需要收听消息的时候(当对象销毁的时候),停止收听,找到通知中心,注销之前注册的那个通知(removeObserver)


1.4 NSNotificationCenter
NSNotificationCenter通知中心是一个单例对象,以保证通知中心只有一个NSNotification通知对象的类型;
NSNotification?
是一个通知对象的类型,用于封装通知的内容,参数等,通过他,把消息传递给观察者;

【注】比如一个对象A要发送通知,其中有对象B,C,D都来接受这个通知,需要事项以下步骤:
在     A   中:找到通知中心,创建通知对象,存储通知的内容,发送通知;
在B,C,D中:找到通知中心,并注册收听的某个频道;当A发消息时,B,C,D就会对应的响应相关的方法,处理功能。。

【注:一定要确保“当A开始发消息的时候,B,C,D这三个对象已经注册了”】

见【Demo】-【1-NSNotifacationCenter】

发送者找到通知中心,并发送信息,同时给消息命名:

  • (IBAction)changeColorBtnClick:(id)sender {

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"选择颜色" preferredStyle:UIAlertControllerStyleActionSheet];

    NSArray *arrayTitle = @[@"红色",@"蓝色",@"紫色",@"黄色"];
    NSArray *arrayColor = @[[UIColor redColor],[UIColor blueColor],[UIColor purpleColor],[UIColor yellowColor]];

for (int i=0; i<4; i++) {
    
    UIAlertAction *action = [UIAlertAction actionWithTitle:arrayTitle[i] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        //发送通知
        //第一个参数:给该条通知命名;
        [[NSNotificationCenter defaultCenter] postNotificationName:@"changedColor" object:arrayColor[i]];
        self.view.backgroundColor = arrayColor[i];
        
    }];
    
    [alert addAction:action];
}

[self presentViewController:alert animated:YES completion:nil];

}

接受者找到通知中心,根据消息名称注册通知;最后销毁注册的通知
//当我们使用storyboard创建对象时,默认初始化方法调用该方法

  • (instancetype)initWithCoder:(NSCoder *)coder
    {
    self = [super initWithCoder:coder];
    if (self) {

      //在初始化方法中注册通知
      //在通知中心,注册self为“changedColor”这条广播的观察者,一旦有任何其他对象,通知通知中心发送changedColor这条广播,self就能接受到,进而触发方法
      [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notification:) name:@"changedColor" object:nil];
    

    }
    return self;
    }

-(void)notification:(NSNotification *)noti
{
//noti.object 该消息对象传的参数
self.view.backgroundColor = noti.object;

}

  • (void)dealloc
    {
    //当对象销毁时,注销通知中心所注册的通知
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"changedColor" object:nil];

}

二 KVC/KVO
2.1 KVC 【** 重点 **】
KVC的全称“key-Value-Coding”键值编码
特点:
1)通过setValue:forKey:形式为帝乡的属性赋值,可以为对象的成员变量赋值;其中Key表示属性的名称,Value表示属性的值;

2)通过路径存取值  setValue: forKeyPath:

3)把字典转换成数据模型【开发中常用,重点】

见【Demo】-【2-KVC】

1)****************************************************************
//setValue: forKey: 的形式赋值
// 用kvc的形式给成员变量,属性赋值
[per1 setValue:@"男" forKey:@"_sex"];
[per1 setValue:@"老谈" forKey:@"name"];
NSLog(@"sex=%@",[per1 valueForKey:@"_sex"]);
NSLog(@"name=%@",per1.name);

2)****************************************************************
//通过路径存取值 setValue: forKeyPath:
//1.要保证路径上的属性对象是存在的
//2.路径上的key要与属性的名字一致
[per1 setValue:@100 forKeyPath:@"book.price"];
[per1 setValue:@"水浒传" forKeyPath:@"book.name"];

NSLog(@"price:%@",[per1 valueForKeyPath:@"book.price"]);
NSLog(@"name:%@",[per1 valueForKeyPath:@"book.name"]);

3)****************************************************************

Person *per2 = [[Person alloc] init];
NSDictionary *dict = @{@"age":@22,@"name":@"张三",@"sex":@"男",@"numberID":@"1001"};
[per2 setValuesForKeysWithDictionary:dict];                 【** 重点 **】

NSLog(@"age:%d",per2.age);
NSLog(@"name:%@",per2.name);
NSLog(@"sex:%@",[per2 valueForKey:@"sex"]);

//防止给没有声明的成员变量或者属性赋值,写下面这个方法:
//重写这个方法,当key在当前类中没有找到对应的属性名称时,会执行这个方法,重写之后,防止崩溃;
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{

}

//Person中写一个方法mySetValuesForKeysWithDictionary; 【简化,只有属性】
-(void)mySetValue:(id)value forKey:(NSString *)key
{
//value 20 key age
NSString *newStr = [NSString stringWithFormat:@"set%@:",[key capitalizedString]];

//根据字符串反射出对应的方法名
SEL sel = NSSelectorFromString(newStr);

[self performSelector:sel withObject:value];
�

}

//Person中写一个方法mySetValue: forKey:
-(void)mySetValuesForKeysWithDictionary:(NSDictionary *)dict
{
for (NSString *key in dict) {

    [self setValue:dict[key] forKey:key];
}

}

2.2 KVO
全称Key-Value-Observer,称为“观察者模式”;对符合KVC键值编码的变量的观察,主要是对变量的赋值操作的观察,如果一旦被观察的变量发生了改变,那么则,通知观察者,执行相关方法;

比如:
有一个数据模型Model,其中有一个属是NSString *message,我们在VC上,用一个UILabel显示这个值;只要message发生改变,那么就要对应的更新UILabel的显示;
界面A和界面B,在界面A有一个UILabel,显示这个model的message的值;
由界面Apush到界面B,在界面B中有一个UITextField,可以修改这个model对象的message的值,每次修改之后,对应的界面A上面的label就能对应的更新显示;

目前能实现这样的一个功能:
1.代理    2.单例    3.block     4.通知    5KVC/KVO
使用KVC/KVO设计模式,先设置A作为观察者,观察model的message的值是否发生改变;如果发生改变,自动的调用某个方法;

见【Demo】-【3-KVO】
  • (void)viewDidLoad {
    [super viewDidLoad];

    self.model = [[MyModel alloc] init];

    //kvo观察model的属性,那么必须使用kvc给model的属性赋值
    [self.model setValue:@"我是旧值" forKey:@"message"];
    //把当前对象注册为self.model的属性message的观察者
    //第一个参数:谁作为观察者
    //第二个参数:观察的是哪个成员变量
    //第三个参数:枚举值,表示观察的新值还是旧值
    [self.model addObserver:self forKeyPath:@"message" options:NSKeyValueObservingOptionNew context:nil];
    self.myLabel.text = self.model.message;
    }

//那么一旦,该model的成员变量message发生改变,就会自动让观察者调用下面的这个方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"message"]) {
self.myLabel.text = change[@"new"];
}

}

//故事版中界面跳转传值在下面方法中进行:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *secVc = segue.destinationViewController; //取得即将跳转的界面
secVc.model = self.model;

}

//在其他界面修改值
-(void)viewWillDisappear:(BOOL)animated
{
//使用KVC来修改
[self.model setValue:self.myField.text forKey:@"message"];

}

小知识:
运用GData进行解析XML文件的时候,做以下三件事:
1.Build Settings —>搜索header search 将header search Paths 路径改为/usr/include/libxml2
2.Build Phases —>在第二个目录中相应文件添加 -fno-objc-arc ,让ARC和MRC兼容
3.Build Phases —>在第三个目录添加新问价,搜索XML,添加libxml2.dylib

三 XML

+(NSArray *)arrayWithXMLData:(NSData *)data;

+(NSArray *)arrayWithXML2Data:(NSData *)data;

import "GDataXMLNode.h" //需要导入这个头文件

+(NSArray *)arrayWithXMLData:(NSData *)data
{
NSMutableArray *mArr = [NSMutableArray array];
/********** 第一种方式 *************/
//1.创建xml解析器
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
//判断xml解析器是否创建成功
if (doc)
{
//2.取得该xml数据的根节点(所有的节点都是GDataXMLElement类型的对象)
GDataXMLElement *rootElment = [doc rootElement];

    //3.通过根节点拿到子节点(books),返回的是一个数组,数组里面存放的是所有的books节点
    NSArray *booksArr = [rootElment elementsForName:@"books"];
    
    GDataXMLElement *booksElement = [booksArr lastObject];
    
    
    //4.取出books节点下的所有的book节点
    NSArray *bookArr = [booksElement elementsForName:@"book"];
    
    //5.遍历数组的bookArr
    for (GDataXMLElement *element in bookArr) {
        BookModel *model = [[BookModel alloc] init];
        model.name = [[[element elementsForName:@"name"] lastObject] stringValue];
        model.price = [[[element elementsForName:@"price"] lastObject] stringValue];
        model.summary = [[[element elementsForName:@"summary"] lastObject] stringValue];
        
        GDataXMLElement *autherElement = [[element elementsForName:@"auther"] lastObject];
        model.auther = [[[autherElement elementsForName:@"name"] lastObject] stringValue];
        
        [mArr addObject:model];
    }
}
return mArr;

}

+(NSArray *)arrayWithXML2Data:(NSData *)data
{
NSMutableArray *mArr = [NSMutableArray array];
/******** 第二种方法 *********/
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
if (doc) {
//根据xpath语句提供的节点的路径,渠道对应的节点,放到数组中
//@“/root/books/book”
//@“//book” 拿到所有的book节点
NSArray *array = [doc nodesForXPath:@"//book" error:nil];
for (GDataXMLElement *element in array) {
BookModel *model = [[BookModel alloc] init];
model.name = [[[element elementsForName:@"name"] lastObject] stringValue];
model.price = [[[element elementsForName:@"price"] lastObject] stringValue];
model.summary = [[[element elementsForName:@"summary"] lastObject] stringValue];

        GDataXMLElement *autherElement = [[element elementsForName:@"auther"] lastObject];
        model.auther = [[[autherElement elementsForName:@"name"] lastObject] stringValue];
        [mArr addObject:model];
        
        
        //取得节点的属性(GDataXMLNode)
        GDataXMLNode *idNode = [element attributeForName:@"id"];
        GDataXMLNode *lanNode = [element attributeForName:@"language"];
        NSLog(@"id = %@,lan = %@",[idNode stringValue],[lanNode stringValue]);
        
    }

}
return mArr;

}

你可能感兴趣的:(day3---通知、KVC/KVO、XML解析)