02-数据解析

一、数据解析

在网络开发中,从服务器获取的二进制数据包括以下几种
 Html  图片
 视频
 音频
 zip
除了以上文件格式之外,最常见的数据莫过于JSON,偶尔也会有XML。无论JSON还是XML都是一种特殊格式的字符串,按照特定的规则描述数据结构。

1、准备工作--安装Apache服务器

安装Apache

  • 一、目的

    1. 能够有一个测试的服务器,不是所有的特殊网络服务都能找到免费的!
  • 二、为什么是 "Apache"

    1. 使用最广的 Web 服务器
    2. Mac自带,不需要额外的安装,只需要修改几个配置就可以,简单,快捷
    3. 有些特殊的服务器功能,Apache都能很好的支持
      例如:HTTP PUT/DELETE 操作,知识补充涉及的 HTTPS 服务
  • 三、 准备工作

    1>设置用户密码

  • 四、 配置服务器

    1. 配置服务器的工作
      1> 在Finder中创建一个"Sites"的文件夹,直接创建在/Users/apple(当前用户名)目录下
      2> 修",指向刚刚创建的文件夹
      3> 拷贝一个文件

    2. 配置服务器注意事项
      1> 关闭中文输入法
      2> 命令和参数之间需要有"空格"
      3> 修改系统文件一定记住"sudo",否则会没有权限
      4> 目录要在/Users/apple(当前用户名)

    3. 配置服务器
      提示:$开头的,可以拷贝,但是不要拷贝$
      // 切换工作目录
      $cd /etc/apache2

      // *** 备份文件,以防不测,只需要执行一次就可以了
      $sudo cp httpd.conf httpd.conf.bak

      // 提示:如果后续操作出现错误!可以使用以下命令,恢复备份过的httpd.conf 文件
      $ sudo cp httpd.conf.bak httpd.conf

      // vim里面只能用键盘,不能用鼠标
      // 用vim编辑httpd.conf
      $sudo vim httpd.conf

      // 查找DocumentRoot
      */DocumentRoot

      "将光标移动到首行"
      // 进入编辑模式
      *i
      "修改引号中的路径"

      // 进入命令模式

      *Mac 10.10 的 Apache 配置略微有一些不一样!
      在 httpd.conf 中找到
      Options FollowSymLinks Multiviews
      加一个单词 Indexes,修改后的结果如下:
      Options Indexes FollowSymLinks Multiviews
      /Users/flilili/Sites

      *ESC:q

      // 查找php
      */php

      "将光标移动到行首" c
      // 删除行首注释#
      *x

      // 保存并退出
      *:wq

      // 不保存退出!!!!!!!!!
      *:q!

      // 切换工作目录
      $cd /etc

      // 拷贝php.ini文件
      $sudo cp php.ini.default php.ini

      // 重新启动apache服务器
      $sudo apachectl -k restart

      如果提示以下错误是正常的:
      httpd: Could not reliably determine the server's fully qualified domain name, using teacher.local for ServerName
      httpd not running, trying to start

  常见问题:

  1. 如果点击info.php文件,出现下载,或者只是显示一小段文字

  解决办法:

  在终端中输入以下两个命令:
  // 关闭 apache 服务器
  $sudo apachectl -k stop

  // 重新再次启动 apache
  $sudo apachectl -k start

  #如果上面命令无效,可执行下面命令试试
  // 启动 apache 服务器
  $ sudo /usr/sbin/apachectl start
  // 关闭 apache 服务器
  $ sudo /usr/sbin/apachectl stop
  1. 在 MAC10.9之后,为了安全考虑,每次启动计算机,Apache服务器默认是不会自动启动的!

可以启动计算机之后,打开终端,输入以下命令:
// 启动 apache
$sudo apachectl -k start

  1. 最常见的问题
    交换文件已经存在,直接按字母 d,可以删除交换文件!


  2. 执行脚本的时候,显示不了,拒绝访问!原因大家用 NTFS 格式的 U 盘拷贝网络素材!会把文件本身的权限过滤掉!

以下是在终端中修改文件权限的指令!
$ chmod 644 info.php(要修改权限的文件名)
$ chmod 644 .

问题解惑
1> 为什么要设置用户密码?
答:apache是一个web服务器,一旦启动了服务器,从互联网上的任何一个人都有可能访问到我们的电脑,不设置密码意味着我们的电脑在互联网上是裸奔的,非常不安全。

2> 为什么Sites文件夹要创建在/Users/apple(当前用户名)目录下?在 Desktop 或 Document文件下创建可以不?
答:不可以。因为Desktop 或 Document文件是用户私人的文件夹目录。而我们配置的服务器是需要让所有网络用户以匿名的身份能够有权限访问这个目录,因此文件夹必须放在根目录里面。

3> 为什么修改系统文件一定用sudo?
答:因为修改系统文件只有系统管理员才能修改,所以要以系统管理员的身份去修改,使用 sudo 就代表是系统管理员的权限。

4> 为什么下面命令只需要执行一次就可以了?
$sudo cp httpd.conf httpd.conf.bak
答:如果 httpd.conf 文件在修改坏了之后再执行一次该命令,那么副本也是坏的了,所以只需要在修改之前执行一次就行了。

知识补充:

> /etc文件夹下的文件都是跟 mac 配置相关的文件。相当 window 下 system32 文件夹。

二、JSON

1、JSON 介绍

JSON本质上,就是一个“特殊格式”的字符串。

  •  JSON是网络上用来传输数据使用最广泛的数据格式,没有之一
  • JSON出生草根,是Javascrpit的子集& Java没有任何关系!

参考网站:http://www.w3cschool.cc。w3c 是国际互联网组织的缩写。

www.runoob.com

2、JSON的语法规则

  •  数据以 key/value 键值对表示。
  •  数据由逗号分割。
  •  花括号保存对象,对应OC的NSDictionary。
  •  方括号保存数组,对应OC的NSArray。

JSON格式化工具

3、JSON值

  •  数字(整数或浮点数)。
  • 字符串(在双引号中)。
  • 逻辑值(true或false)。
  •  数组(在方括号中)。
  • null

4、JSON解析--天气预报

一、解析天气预报

- (void)loadData1{
    // 创建 url
    NSURL *url = [NSURL URLWithString:@"http://www.weather.com.cn/adat/sk/101010100.html"];
    // 创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0];
    // 发送异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        
        NSLog(@"data = %@",data);
        NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        /*
         NSJSONReadingMutableContainers = (1UL << 0), 容器可变
         NSJSONReadingMutableLeaves = (1UL << 1), 叶子可变
         NSJSONReadingAllowFragments(碎片) = (1UL << 2) 顶级节点可以既不是数组也不是字典
         */
        
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
        
        NSLog(@"%@市 温度 %@ 风向 %@ 风力 %@ ",dict[@"weatherinfo"][@"city"],dict[@"weatherinfo"][@"temp"],dict[@"weatherinfo"][@"WD"],dict[@"weatherinfo"][@"WS"]);
    }];
}

专业名词解析
* 序列化
    向服务器发送数据之前,将 NSArray/NSDcitionary 转成二进制的过程。
* 反序列化
    从服务器接收到数据之后,将二进制数据转换成 NSArray/NSDcitionary的过程。

5、JSON解析--第三方框架

  • 1、常见的JSON解析第三方框架
     JSONKit(最快)
    SBJson
     TouchJSON
    .# 以上三个框架的性能依次降低。

  • 2、苹果原生(自带):NSJSONSerialization(性能最好)

  • 3、介绍JSONKit第三方框架的目的

    • JSON的解析并不是表面上这么简单。
    •  官方说JSONKit比苹果原生的JSON解析速度要快。
       JSONKit在很多老的项目中仍然在使用,知道'JSONKit'说明我们是资深的iOS程序员。
    •  JSONKit已经在2012年停止更新,适用于iOS5.0之前的版本开发使用。(苹果原生的NSJSONSerialization是iOS5.0之后出现)。
    •  了解 ARC & MRC 混编的方法
  • 4、JSONKit解析

    • 下载框架:http://github.com/johnezang/JSONKit

    • 导入框架文件:JSONKit.h & JSONKit.m。

    • 设置MRC标记

      • 选择"项目"-"Build Phases"-"Compile Sources"。
      • 找到JSONKit.m并且在Compiler Flags中添加-fno-objc-arc。 # -fno-objc-arc告诉编译器,编译JSONKit.m时不使用ARC。
      • 修改错误,利用自动修复功能,修改两处isa的错误。
    • 反序列化id result = [[JSONDecoder decoder] objectWithData:data];

  • 5、JSONKit性能测试
    测试代码如下

intlargeNumber =100*1000;
- (void)loadData{
    
    //创建url
    NSURL *url = [NSURL URLWithString:@"http://localhost/demo.json"];
    //创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0timeoutInterval:10.0];
    //发送异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        //绝对时间是自参考日期的时间间隔
        CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
        for(intindex =0; index < largeNumber; index ++) {
            // NSMutableDictionary *result = [[JSONDecoder decoder] objectWithData:data];
            NSMutableDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
        }
        NSLog(@"-----endTime = %f",CFAbsoluteTimeGetCurrent() - start);
        
        NSLog(@"-----endTime = %f",CFAbsoluteTimeGetCurrent() - start);
        //JKDictionary 其实就是 NSMutableDictionary 的 子类 //NSLog(@"------%@,%@",result,result[@"message"]);
        
    }];
}

通过测试验证结果如下:
JSONKit:4.907761秒
官方:0.299994秒

由此可得出结论:苹果原生的JSON解析速度远远比JSONKit快。
  如果工作中遇到使用第三方框架解析 JSON 的旧项目,建议替换为苹果原生的。
  替换的原则:看项目是否要支持iOS5.0之前的版本。如果不需要果断替换。
  替换步骤
      备份(给自己一个后悔的机会)
      删除JSONKit.h & .m文件
      哪里出错改哪里

三、PList解析

  • 1、PList主要在苹果开发中常用,很多后台并不会返回Plist的格式数据。有关PList的反序列化知道即可。
  • 2、PList解析代码如下
- (void)loadData{
    // 创建 url
    NSURL *url = [NSURL URLWithString:@"http://localhost/videos.plist"];
    // 创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0];
    // 发送异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        id result = [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error:nil];
        NSLog(@"%@   %@",result,[result class]);
    }];
}

NSPropertyListSerialization 参数:
-data:要反序列化的二进制数据
-options:选项,位移枚举类型
NSPropertyListImmutable = 0 不可变,
NSPropertyListMutableContainers= 1  容器可变,
NSPropertyListMutableContainersAndLeaves= 2  容器和叶子可变
- format:如果不希望知道格式,传人 NULL 即可
-error:错误信息

四、XML 解析

0.XML语法

  • 一个元素可以拥有多个属性

1、XML介绍

一、介绍

  • 1、XML的英文全称(eXtensible Markup Language) 中文名称可扩展标 记语言。

  • 2、XML的特点:

    • 语法规则很简单,且很有逻辑。
    • 出身名门,w3c制定,微软和 IBM 曾经共同大力推荐过的数据格式。
    • 专门设计用来传输和存储数据
  • 3、与HTML的区别:

    • HTML的标记不是所有都需要成对出现。
    • XML要求所有的标记必须成对出现。
    • HTML标记不区分大小写,XML则大小敏感,即区分大小写。

二、XML解析的方式

  • 苹果原生
    NSXMLParser:SAX方式解析,使用简单

    • 是只读的方式,从上向下的方式解析
    • 是苹果提供的解析方式
    • 使用 NSXMLParser 通过 代理 实现解析。
  • DOM解析

    • 是在MAC使用的解析方式。
    • 内存消耗极大,不适用于手机。因此苹果没有提供手机上DOM解析。
    • iPhone无法直接使用DOM方式解析XML。
  • 第三方框架

    • libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
    • GDataXML:DOM方式解析,由Google开发,基于libxml2
  • XML解析方式的选择建议

    • 大文件:NSXMLParser、libxml2
    • 小文件:GDataXML

2、SAX解析

2.0、NSLog确认解析思路

一、SAX解析步骤

  • 开始文档--准备工作
  • 开始"节点"
  • 发现节点内部的内容,每一个节点,可能需要多次才能找完
  • 结束"节点"
  • 结束文档--解析结束
  • 以上步骤2,3,4会不断循环,一直到所有解析完成。

二、代码演示XML的解析

/**
 *  加载 xml 数据
 */
- (void)loadData{
    // 创建 url
    NSURL *url = [NSURL URLWithString:@"http://localhost/videos.xml"];
    // 创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0];
    // 发送异步请求(由于解析 xml 是一个耗时的过程,所以新开启队列)
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        // 1.创建 xml 解析器
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
        // 2.设置代理来解析
        parser.delegate = self;
        // 3.解析器开始
        //解析 -- 一旦开始解析,后续的解析工作全部交给代理完成
        [parser parse];
    }];
}

5.iOS对NSURLRequest提供了7种缓存策略:(实际上能用的只有4种)
NSURLRequestUseProtocolCachePolicy // 默认的缓存策略(取决于协议)
NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求
NSURLRequestReloadIgnoringLocalAndRemoteCacheData // 未实现
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData // 忽略缓存,重新请求
NSURLRequestReturnCacheDataElseLoad// 有缓存就用缓存,没有缓存就重新请求
NSURLRequestReturnCacheDataDontLoad// 有缓存就用缓存,没有缓存就不发请求,当做请求出错处理(用于离线模式)
NSURLRequestReloadRevalidatingCacheData // 未实现

三、通过NSLog打印,确认XML解析思路

#pragma mark  - NSXMLParserDelegate 代理方法
/**
 *  开始解析
 */
- (void)parserDidStartDocument:(NSXMLParser *)parser {
    NSLog(@"1、开始解析");
}
/**
 *  解析到一个开始节点调用
 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    NSLog(@"2、开始节点 %@ %@",elementName,attributeDict);
}

/**
 *  解析到节点文字调用  一个节点的内容可以会调用多次该方法
 */
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    NSLog(@"3、发现节点内容======> %@",string);
}

/**
 *  解析到结束节点调用  elementName 没有反斜线 /
 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    NSLog(@"4、结束节点------%@",elementName);
}

/**
 *  解析结束调用
 */
- (void)parserDidEndDocument:(NSXMLParser *)parser{
    NSLog(@"5、结束文档");
}
2.1、画XML解析思维导图
  1. 懒加载 创建数组
  2. 开始节点 如果节点是vedio节点创建新对象 设置ID 将设置好的丢进数组 下一次重新赋值
  3. 发现节点内容 拼接字符串
  4. 结束节点 下一次开始节点要把上一次清空
  5. 结束解析(打印)
2.2、XML解析代码实现
#pragma mark  - NSXMLParserDelegate 代理方法
/**
 *  开始解析
 */
- (void)parserDidStartDocument:(NSXMLParser *)parser {
    // 清空数组
    [self.videos removeAllObjects];
}
/**
 *  解析到一个开始节点调用
 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    if ([elementName isEqualToString:@"video"]) {
        // 创建 video 模型
        self.currentVideo = [[Video alloc] init];
        // 设置 id
        self.currentVideo.videoId = @([attributeDict[@"videoId"] integerValue]);
    }
    // 清空当前正在拼接的字符内容
    [self.elementString setString:@""];
    // 错误写法
    //self.elementString = @"";
}

/**
 *  解析到节点文字调用  一个节点的内容可以会调用多次该方法
 */
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    [self.elementString appendString:string];
}

/**
 *  解析到结束节点调用  elementName 没有反斜线 /
 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    // 如果 elementName 是 video,则添加到数组中
    /* 最笨方法
     if ([elementName isEqualToString:@"video"]){
     [self.videos addObject:self.currentVideo];
     } else if ([elementName isEqualToString:@"name"]){
     self.currentVideo.name = self.elementString;
     } else if ([elementName isEqualToString:@"length"]){
     self.currentVideo.length = @(self.elementString.integerValue);
     } else if ([elementName isEqualToString:@"desc"]){
     self.currentVideo.desc = self.elementString;
     } else if ([elementName isEqualToString:@"imageURL"]) {
     self.currentVideo.imageURL = self.elementString;
     } else if ([elementName isEqualToString:@"videoURL"]){
     self.currentVideo.videoURL = self.elementString;
     } else if ([elementName isEqualToString:@"teacher"]){
     self.currentVideo.teacher = self.elementString;
     }
     */
    // 如果是 name,length,desc....则设置属性
    
    // 简便方法
    if ([elementName isEqualToString:@"video"]){
        [self.videos addObject:self.currentVideo];
    } else if(![elementName isEqualToString:@"videos"]){
        //使用 KVC 设置属性, KVC是一种以字符串形式间接设置数据的方式
        [self.currentVideo setValue:self.elementString forKey:elementName];
    }
}

/**
 *  解析结束调用
 */
- (void)parserDidEndDocument:(NSXMLParser *)parser{
    NSLog(@"%@",self.videos);
}

3、SAX解析重构

1、新建一个模型类HMSAXVideo,专门做解析工作。
2、提供类方法:+(void)saxParser:(NSData *)data finished:(void (^)(NSArray *))finished。
/**
 *  视频数组
 */
@property(nonatomic,strong) NSMutableArray *videos;
/**
 *  当前正在解析的视频
 */
@property(nonatomic,strong) HMVideo *currentVideo;
/**
 *  当前正在拼接的字符串
 */
@property(nonatomic,strong) NSMutableString *elementString;
/**
 *  解析完回调block
 */
@property(nonatomic,copy) void (^finishedBlock)(NSArray *);
// 如果回调的 block 在当前方法不执行,需要用一个属性记录
+(void)saxParser:(NSData *)data finished:(void (^)(NSArray *))finished{
    // 使用断言确保外界传人的回调不为空,如果为空,则崩溃提示
    NSAssert(finished != nil, @"必须传人回调");
    // 0.创建解析模型
    HMSAXVideo *sax = [[HMSAXVideo alloc] init];
    // 记录回调 block
    sax.finishedBlock = finished;
    // 1.创建 xml 解析器
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    // 2.设置代理来解析
    parser.delegate = sax;
    // 3.解析器开始解析
    // parse:是同步方法,会等所用代理方法执行完毕后,才会执行后面的代码
    [parser parse];
#warning 不能在parse方法调用后设置回调
    // 记录回调 block
    // sax.finishedBlock = finished;
}

#pragma mark - 懒加载
- (NSMutableArray *)videos {
    if(_videos == nil){
        _videos = [NSMutableArray array];
    }
    return _videos;
}

- (NSMutableString *)elementString {
    if (_elementString == nil) {
        _elementString = [NSMutableString string];
    }
    return _elementString;
}

#pragma mark  - NSXMLParserDelegate 代理方法
/**
 *  开始解析
 */
- (void)parserDidStartDocument:(NSXMLParser *)parser {
    // 清空数组
    [self.videos removeAllObjects];
}
/**
 *  解析到一个开始节点调用
 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    if ([elementName isEqualToString:@"video"]) {
        // 创建 video 模型
        self.currentVideo = [[HMVideo alloc] init];
        // 设置 id
        self.currentVideo.videoId = @([attributeDict[@"videoId"] integerValue]);
    }
    // 清空当前正在拼接的字符内容
    [self.elementString setString:@""];
}

/**
 *  解析到节点文字调用  一个节点的内容可以会调用多次该方法
 */
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    [self.elementString appendString:string];
}

/**
 *  解析到结束节点调用  elementName 没有反斜线 /
 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
   // 使用 KVC 设置属性
    if ([elementName isEqualToString:@"video"]){
        [self.videos addObject:self.currentVideo];
    } else if(![elementName isEqualToString:@"videos"]){
        [self.currentVideo setValue:self.elementString forKey:elementName];
    }
}

/**
 *  解析结束调用
 */
- (void)parserDidEndDocument:(NSXMLParser *)parser{
    dispatch_async(dispatch_get_main_queue(), ^{
        self.finishedBlock(self.videos.copy);
    });
}

五、UITableView展示数据

5.1、Stroyboard自定义cell

5.2、设置Cell数据

1、HMVideo模型中提供属性
//视频时长
@property (nonatomic, strong,readonly) NSString *time;
计算时间方式有两种
方式一:重写time属性getter方法
- (NSString *)time {
         int len = self.length.intValue;
         return [NSString stringWithFormat:@"%02d:%02d:%02d", len/3600,(len % 3600)/ 60,               (len % 60)];
}
方式二:
- (void)setLength:(NSNumber *)length {
    _length = length;
    int len = self.length.intValue;
    _time = [NSString stringWithFormat:@"%02d:%02d:%02d", len/3600, (len % 3600)/60, (len % 60)];
}

SDWebImage下载头像
UIImage *placeholder = [UIImage imageNamed:@"user_default"];
[self.iconView sd_setImageWithURL:video.fullImageUrl placeholderImage:placeholder options:SDWebImageRetryFailed | SDWebImageLowPriority];

参数
SDWebImageLowPriority:会在表格滚动的时候,暂停图像下载,性能会好很多
SDWebImageRetryFailed:图片下载失败后重试

5.3、集成下列刷新控件

  • 1、通过代码和storyboard
/**
 *  集成下拉刷新控件(通过代码)
 */
- (void)setRefreshControl{
    // 集成下拉控件(不需要设置frame)
    self.refreshControl = [[UIRefreshControl alloc] init];
    // 监听下拉事件
    [self.refreshControl addTarget:self action:@selector(loadData) forControlEvents:UIControlEventValueChanged];
    // 设置提示文字,颜色
    NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:@"努力加载中……" attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15],NSForegroundColorAttributeName:[UIColor redColor]}];
    self.refreshControl.attributedTitle = attributedTitle;
    // 设置菊花颜色
    self.refreshControl.tintColor = [UIColor grayColor];
}
  • 2、UIRefreshControl使用说明
    • 目前只对UITableviewController有用
    • 只能下拉刷新,不能上拉刷新
    • init或者viewdidload中创建UIRefreshControl,设置文字,颜色等信息
    • 系统自动管理UIRefreshControl,自动添加到tableview视图中;
    • 给UIRefreshControl添加监听方法,当值改变的时候调用方法用于数据请求
    • 该方法中请求数据确认完成之后,调用endRefreshing方法,关闭刷新

六、GDataXML解析xml

6.1、GDataXML介绍

在计算机领域,针对 XML 解析,还有 DOM 解析方式,在PC端和服务器被广泛使用

  • 背景

    • 主要用在 PC 端或服务器端。
    • 苹果提供了 NSXML 类支持 DOM 方式的解析
    • 不过 NSXML 类只能用在 MAC 开发,在iOS中无法直接使用。
  • DOM 特点(可读可写)

    • DOM 方式不仅能解析 XML文档,还能够修改:增加节点/删除节点、
    • 一次性将 XML 文档以树形结构读入内存。
    • 横向的节点越多,内存消耗越大。
    • 使用 DOM 解析适合于小的 XML 解析,并且能够动态维护。
    • 有些第三方框架提供了 DOM 方式的解析,GData/KissXML(XMPP)
    • 在 iOS开发中,如果要使用 DOM 方式解析,最好只是处理小的 XML

6.2、代码实现

需要配置:
command+b后会出现报错
在Build Settings里面“Header Search Paths ”"Other Linker Flags"
// libxml includes require that the target Header Search Paths contain
//
//   /usr/include/libxml2
//
// and Other Linker Flags contain
//
//   -lxml2

- (void)loadData {
    // 创建 url对象
    NSURL *url = [NSURL URLWithString:@"http://192.168.1.105/videos.xml"];
    // 创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 发送请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        // 创建视频数组
        NSMutableArray *videos = [NSMutableArray array];
        // 建立 xml 文档
        GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data error:NULL];
        
        // 获得根节点对象
        GDataXMLElement *rootElement = doc.rootElement;
        
        // 遍历子节点
        for (GDataXMLElement *childElement in rootElement.children) {
//            NSLog(@"child = %@",childElement);

            // 每遍历一次就创建一个视频对象
            HMVideo *video = [[HMVideo alloc] init];
 
          // 将模型对象添加到数组中
            [videos addObject:video];
            
            // 继续变量childElement的子节点
            for (GDataXMLElement *node  in childElement.children) {
                // 使用 KVC 赋值
//                NSLog(@"name = %@,value = %@",node.name,node.stringValue);
                [video setValue:node.stringValue forKey:node.name];

            }
            // 遍历属性字典数组
            for (GDataXMLNode *attr in childElement.attributes) {
                // 使用 KVC 赋值
//                NSLog(@"attr = %@,attrValue = %@",attr.name,attr.stringValue);
                [video setValue:attr.stringValue forKey:attr.name];
            }
        }
        NSLog(@"videos = %@",videos);
    }];
}

七、Copy,NSNumber,id

思考?为什么模型HMVideo中的属性都使用copy? 改为strong运行看看效果。

  • strong 和 copy 的区别

    • strong :在设置数值的时候,仅仅是引用计算+1
    • copy :在设置数值的时候,如果属性是可变的,会copy一个不可变的副本。copy动作是在setter方法中执行的。
  • 画图解析使用strong导致的效果。

  • 如果模型属性要使用strong

#下面的代码
[self.currentVideo setValue:self.elementString forKey:elementName];

#修改为
[self.currentVideo setValue:self.elementString.copy forKey:elementName];
  • 重写了属性的setter方法,就是接管了原有系统提供的setter方法。
# 如果重写了copy属性的 setter 方法,一定要copy,否则外面的copy属性就是strong属性。
比如重写了模型的name属性的 setter方法:
- (void)setName:(NSString *)name {
    _name = [name copy];
//    _name = name; 属性就相当于 strong 了  
}
  • NSNumber,id属性
    代码演示实际开发中不用NSNumber带来的问题。 Strong 基本数据类型
    代码演示服务器返回数据中有id键值对的问题。 id NSNumber ID

问题
1.kvc的利用
2.申明属性时strong&copy的使用,copy的实现在系统默认setter方法下实现。
3.获得了对象的第一个/最后一个值,怎么取全部值

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容