zoukankan      html  css  js  c++  java
  • iOS KVO 设计模式的应用

    #import "ActivityListViewController.h"

    #import "ActivityListViewCell.h"

    #import "Activity.h"

    @interface ActivityListViewController ()

    // 存放activity的数组

    @property (nonatomic,strong) NSMutableArray *modelArray;

    @end

    @implementation ActivityListViewController

    // 请求网络数据

    - (void)setNetWorkData

    {

        // 活动网址: http://project.lanou3g.com/teacher/yihuiyun/lanouproject/activitylist.php

        

        // 1. URL

        NSURL *url = [NSURL URLWithString:@"http://project.lanou3g.com/teacher/yihuiyun/lanouproject/activitylist.php"];

        

        // 2. request

        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];

        

        // 3. connection

        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {

            

            

            // 4. 解析数据

            NSDictionary *rootDic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

            

            // events

            NSArray *array = [rootDic objectForKey:@"events"];

            

            //  开辟空间

            self.modelArray = [NSMutableArray array];

            

            // kvc赋值

            for (NSDictionary *dic in array) {

                Activity *activity = [[Activity alloc] init];

                [activity setValuesForKeysWithDictionary:dic];

                [self.modelArray addObject:activity];

                

            }

            

            

            // 5. 刷新单元格数据

            // 原因: 网络数据请求需要时间,因此 单元格创建会在数据请求完成之前执行。所以,我们在数据请求完成之后,再次给单元格赋值。

            [self.tableView reloadData];

            

        }];

        

    }

    - (void)viewDidLoad {

        [super viewDidLoad];

        

        // 调用请求网络数据

        [self setNetWorkData];

        

        

        // Uncomment the following line to preserve selection between presentations.

        // self.clearsSelectionOnViewWillAppear = NO;

        

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.

        // self.navigationItem.rightBarButtonItem = self.editButtonItem;

    }

    - (void)didReceiveMemoryWarning {

        [super didReceiveMemoryWarning];

        // Dispose of any resources that can be recreated.

    }

    #pragma mark - Table view data source

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    #warning Incomplete implementation, return the number of sections

        return 1;

    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    #warning Incomplete implementation, return the number of rows

        return [self.modelArray count];

    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

        ActivityListViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell1" forIndexPath:indexPath];

        // Configure the cell...

        

        Activity *activity = self.modelArray[indexPath.row];

        

        // 查看activity中,是否已经下载图片,如果没有,则下载

        if (activity.picture == nil && activity.isDownLoading == NO) {

            

            [activity loadImage];

            

            

            // 下载图片后,给activity添加观察者

            // 1. 添加观察者

            [activity addObserver:self forKeyPath:@"picture" options:(NSKeyValueObservingOptionNew) context:(__bridge void * _Nullable)(indexPath)];

            // arc 需要 桥接,(__bridge void *)indexPath

            // mrc 里需要进行retain [indexPath retain],防止野指针

            

            

            

            

        }

        

        // 此时存在问题,当单元格第一次加载的时候,没有图片,因为,第一次加载时可能图片没有下载下来,赋值时就没有值。 当再次加载单元格时才有数据。

        

        // 原因: 数据请求下来后,没有被及时添加到单元格上。 数据有了,但是没有赋值。

        

        // 解决方案:使用 KVO 观察者模式,观察 activity,观察activity 的pICTure属性, tableViewController 去观察

        // 1. 被观察者 activity ,

        // 2. 被观察属性 picture

        // 3. 观察者 self (tableViewController)

        // 4. 执行操作  当图片下载下来后,执行观察方法,我们把下载下来的图片赋值给单元格。

        cell.activity = activity;

        

        return cell;

    }

    // 2. 实现kvo方法

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context

    {

        

        // 1. 获取改变的值--获取下载后的图片

        UIImage *newImage = (UIImage *)[change objectForKey:@"new"];

        

        // 2. 获取传递过来的数据 indexPath

        // 注意: 也需要强制转换,如果是arc,需要桥接

        NSIndexPath *indexPath = (__bridge NSIndexPath *)context;

        

        // 如果下载好的单元格正在被显示,我们才把图片赋值给它,否则就没有意义。如果一个没有正在显示的单元格数据,(重用队列里面的单元格)就会出现,单元格加载出来时,有别的数据。类似于,拿了一个脏盘子给你。

        

        // 3. 获取正在显示的单元格下标数组

        NSArray *array = [self.tableView indexPathsForVisibleRows];

        

        // 4. 判断indexPath 是否正在显示,即是否在数组中

        if ([array containsObject:indexPath]) {

            

            // 说明正在显示,把下载好的图片赋值给单元格

            // 获取单元格

            ActivityListViewCell *cell = (ActivityListViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];

            

            // 给单元格赋值

            cell.pictureView.image = newImage;

            

        }

        

        // 三、 触发观察者方法

        // ......

        

        // 四、移除观察者

        [object removeObserver:self forKeyPath:@"picture"];

        

        // 补充: mrc 如果想要观察者一直观察,又不想出现内容泄露,那么,可以把移除写在 dealloc 里面。

    }

  • 相关阅读:
    谁能撼动C语言的霸主地位?是Go?是Rust?还是...
    从入职到快速晋升,程序员能够从底层逆袭,究竟是什么原因?
    我敢说,这8个Linux基础命令,学了绝不吃亏!(强烈推荐)
    想从程序员到百万高管,你一定要避开这3个坑!(年轻人必读)
    注意!在Linux中删除特殊名称文件有这6种方式!(建议收藏)
    事实证明!这10个Linux系统操作指令,简直 “不讲武德” ,请大家耗子尾汁!
    最适合单片机编程的高级语言,除了C语言,别无选择!
    “Help”!如何学习C和C++才不茫然,才不是乱学?
    C语言丨不要阅读此文,除非你已掌握二叉树的这些操作
    团队编程项目作业2-团队编程项目开发环境搭建过程
  • 原文地址:https://www.cnblogs.com/xlsn0w/p/4978844.html
Copyright © 2011-2022 走看看