一、咱们上午就做了两件事儿,
1.把我们的数据,加载起来,
2.实现了下面这个”加载更多“按钮的功能,
3.只不过,我们加载数据的时候,用了一个自定义cell,
那么,基本加载数据的办法,我就不再说了,
基本,就是那些步骤,
只是把我们自定义cell部分,再给大家复习一下,
上午,我们在控制器里面,是不是有个数据源方法,
咱们上午,就是在我们这个数据源方法中,返回单元格的数据源方法中,
我们有这么四步,
1)第一步,获取模型数据,
2)第二步,创建单元格,
3)第三步,把模型,设置给单元格,
4)第四步,返回单元格,
只是在第二步,创建单元格的时候,以前是怎么创建的,
以前是直接UITableView *cell = 直接从缓存池里面取,如果不到的话,直接alloc init,这种方式创建,
然后,我们上午,创建cell的时候,就是用一个xib来表示,这里建了一个xib,在xib里面,拖拉拽,拽了这么一个cell,然后呢,设置一下这个cell的identifier,
设置它这么一个重用ID,
然后,我们在代码里面,让这个拽好的cell,与我们新建的具体这么一个类型,这个自定义类型,
自定义cell,相关联,
然后,这样的话,当通过xib,创建这个cell以后,就是创建这个类的一个对象,
然后,我们在这个控制器里面,我们用这个自定义的cell,调它的一个类方法,
调它的一个类方法,叫goodsCellWithTableView,
然后,在这个类方法里面,我们其实就是干什么呢,
其实,就是封装了一个通过xib,创建cell,的这么一个代码,
通过xib,创建cell的代码,就是,
1)首先,获取我们的根目录,在根目录里面,调它的loadNibNamed,这个方法,加载这个xib,@“CZGoodsCell”,
2)然后,这个方法,会返回一个数组,在这个数组当中,我们取得第一个对象,或者最后一个对象,就是我们这个xib里面,这个cell吧,
因为,这个xib里面,只有一个cell,所以说,获取到的就是这个cell,
OK,这样的话,在控制器里面,就可以自定义一个cell了,
拿到这个cell,
拿到这个cell以后,然后我们基本上上面这个滚动,就做完了,
上面这个数据,就做完了,
2.然后,接下来,我们就实现一个“加载更多”,
“加载更多”,它首先是在我们tableView的tableFooterView里面,
有一个“加载更多”,
因为,这个“加载更多”里面,不仅仅是一个按钮,
里面是不是有可能,有一些其他的一些控件吧,
所以说,我们这里,footerView里,要加一个UIView,
在UIView里面,再放一些其他的子控件,而不是下面只是一个按钮,
所以,我们这个时候,就发现,footerView,“加载更多”,这块儿代码,这个块儿内容,是不是也可以使用一个xib来描述啊,
所以,我们就又建了一个xib,
我们建两个xib了,
1)一个是描述单元格的一个xib:CZGoodsCell.xib,
2)一个是描述footerView的一个xib:CZFooterView.xib,
一个是描述单元格的xib,
一个是描述footerView的xib,
1)在这个xib里面,首先我们就拽了一个“加载更多”按钮,
2)然后,我们又放了一个,用来显示等待信息的View,
3)然后,我们通过拖线的方式,让两个属性和它相关联,
这里,两个属性,一个是btnLoadMore,一个是waitingView,
让这两个属性,分别和我们这个View,和上面按钮相关联,
设好关联以后,我们接下来,为我们这个“加载更多”按钮,注册单击事件,
这就是“加载更多”按钮的单击事件,
3.在这个单击事件里面,
1)首先,第一步,就是让我们,当点“加载更多”按钮的时候,就让“加载更多”按钮隐藏掉,
2)第二步,让waiting,那个“等待指示器”,显示出来,
3)第三步,更新数据,
但是我们发现,更新数据,其实就是创建新的model,把它加到那个数据集合里面,就可以了,但是我们在footerView里面,发现在这里是访问不到,无法访问到我们这个控制器里面这个goods集合的,
所以说,这个时候,就遇到一个问题,你在footerView这个自定义的一个View里面,想访问控制器里面那个集合,但是访问不到,这个时候,我们首先想到的就是什么,代理吧,
那么,在用代理之前,我们基本的思考方式,就是
1)首先,想现在要为谁找代理,footerView吧,
现在是不是要为footerView,是不是要为它找代理,
因为它想做一件事儿,它自己干不了,所以这个时候,它就看一下,谁能干了呢,因为那个goods集合是在我们的控制器里面,所以说,它发现,控制器能做这个事儿,所以说,这个时候,就找谁作为它的代理,控制器吧,
然后,到此为止,我们就分析出了,现在是谁要找代理,然后呢,让谁作为它的代理,那么就是footerView,它要干一件事儿,它干不了,所以,它要找代理,这件事儿,谁能干了,控制器能干了,所以说,让控制器作为它的代理对象,所以说,谁找代理,谁是代理,这两个就已经确定了,
然后,接下来,就是哪个控件要找代理,是不是要为这个控件,写一个代理协议啊,
2)写代理协议,现在就是,CZFooterView,这个控件要找代理,所以说,就在这个控件的头文件里面,新建这么一个,定义这么一个协议,
这个协议就是,为这个控件,CZFooterView,代理而生的一个代理协议,就是这个控件的一个代理协议,
一般命名规则就是,控件名后面,跟一个Delegate,
控件名后面,跟一个Delegate,就是这个控件的一个代理协议,
然后,写好代理协议以后,就是
3)代理协议里面这个方法,叫什么,
这个方法的命名规则就是,这个代理协议是哪个控件的代理协议,前面就是控件名,当然,去除那个前缀,控件名,后面加一个具体的方法名称,
然后,一般情况下,你为控件写代理,这个代理方法中,一定会有一个参数,这个参数就是,哪个控件写代理,这个参数就是对应的控件,
现在,我们的footerView,要找代理,所以说,为它写好了一个代理协议,
写好一个代理协议以后,紧接着,第二步,就是
4)为我们控件,加一个delegate属性,
为控件,加一个delegate,这个属性,
这个代理这个属性,一般名称就叫delegate,这是我们的约定,
然后呢,还有就是我们这个属性里面的类型,就是id类型,同时要用一个协议来约束一下,
id< CZFooterViewDelegate >
它必须是遵守这个协议的,
然后,我们的自定义控件里面,就是写代理,就基本写完了,
这里创建代理协议,这里有个代理属性,
然后,紧接着,就是自定义控件里面,什么时候要用到这个代理对象呢,在这个CZFooterView.m文件中,
5)当我们点击“加载更多”的时候,
接下来,是不是要调我们代理里面的这个方法,footerViewUpdateData:
来更新tableView的数据啊,
所以说,接下来,我们就是要用一下代理,
自定义控件里面,
1)第一,写代理协议,
2)第二,增加一个代理属性,
3)第三,使用代理,
在这个地方,首先判断,当前这个代理对象里面,是否有这个方法,
如果有这个方法,调一下当前这个footerView控件自己的delegate属性里面的,这个footerViewUpdateData:,方法,把当前footerView,自己传进来,
[self.delegate footerViewUpdateData:self];
这是不是就是使用代理,
这,就是使用代理,
那么,现在我们基本上这个footerView控件就写完了,
那么,它写完以后,要想用代理,是不是你得先给它设置一个代理对象啊,
3.所以说,这个时候,就找到我们控制器,
控制器这儿,viewDidLoad里面,在我们控制器的这个View加载完毕以后,接下来,我们就在这里,创建了一个footerView,
通过xib来创建footerView,
通过xib,创建好了这个footerView,
接下来,设置当前这个footerView控件的代理对象,等于控制器自己,
然后,我们就可以把footerView这个控件,设置给当前tableView的这个tableFooterView的这个属性了,
然后,footerView里面,就有这个我们自己写的这个footerView控件了,
然后,我们运行起来之后,你再点击“加载更多”,加载更多按钮被隐藏,同时显示“等待指示器”,同时“驴肉火烧”被显示出来了,
##
基本上,我们上午就说到这儿了,
二、我们希望的是,当点击“加载更多”的时候,这里显示这个“驴肉火烧”,同时,这个是不是要转一下,应该是这个转一下,然后是不是再显示这个“驴肉火烧”,
1.显示完毕以后,接下来,这个东西,是不是要再隐藏掉,等待指示器,再隐藏掉,
“加载更多”按钮,是不是再显示回来,
那么,这个操作,在哪儿写呢,
还是找到我们这个footerView,
我们希望是,一开始先隐藏”加载更多“按钮,
显示等待指示器,
然后呢,开始刷新数据,
先判断一下,代理是否实现了代理方法,footerViewUpdateData:
如果实现了代理方法,则调用代理方法
[self.delegate footerViewUpdateData:self];
然后,接下来,数据刷新完毕以后,把这两个再给它显示回来啊,
把“加载更多”按钮,再显示回来,
把“等待指示器”,再隐藏回去,
但是大家想,我如果这么写,对不对,
这么写大家觉得对不对,序号改一下,
这么写,大家觉得对不对,NO,和YES,改一下,
这样写是不对的,为什么,
这样写,你其实看不到效果的,
因为,你一开始,让它隐藏(加载更多按钮),让它显示(等待指示器),执行完这句代码,是不是紧接着,立刻执行这段代码(让加载更多按钮显示,让等待指示器隐藏),
相当于,你刚刚把它隐藏(加载更多按钮),把这个显示(等待指示器),然后呢,后来又把第一个显示(加载更多按钮),又把第二个隐藏(等待指示器),
是不是在很短很短的时间内,是不是它又恢复到原来的状态了,
所以,这样写,是不行的,
那么,我们为了模拟这个效果,是不是需要让它隔一段时间以后,再执行这段代码(让加载更多按钮显示,让等待指示器隐藏),
如果你希望,隔一段时间以后,再执行另外一段代码,这个时候就可以使用,dispatch,
5.隔一段时间再执行代码,dispatch,
注意,dispatch,是不是又这么多个dispatch啊,
用哪个呢,就找这个GCD的,
记的时候,你就记住,第一个单词是dispatch,后面有个GCD,
这些看都别看,直接选这个,
直接就选这个,然后回车,
直接就选这个GCD的dispatch,
然后这个地方,注意这个delayInSeconds,
这个就是延迟多少秒以后,执行,延迟多少秒以后,我们希望它延迟1.0秒钟以后,
延迟1.0秒钟以后,
延迟1.0秒钟以后,执行什么呢,
code to be executed after a specified delay,
在一个指定的、特定的,延迟以后,要执行代码啊,
我们这个,在1.0秒钟之后,然后再开始,加载我们的数据,
别一点它(“加载更多”按钮),立刻就把那个“红烧肉”显示出来,好像给人感觉很假的样子,其实本来就很假,但是我们为了模拟的像一些,
所以说,当点完“加载更多”以后,在1秒钟之后,我们再执行这个代码,
执行这个代码,是不是调用代理,调用代理,是不是把那个tableView的数据是不是刷新出来了,数据刷新出来了以后,紧接着,然后再把这两个按钮、这两个控件,恢复到原来的状态,让“加载更多”按钮显示,隐藏“等待指示器”,
这就是,当你点击这个按钮的时候(btnLoadMore),
1)首先要“加载更多”按钮隐藏,
2)让我们下面“等待指示器”显示,
3)隔一秒钟之后,刷新一下tableView,
给它增加一条新数据,当新数据增加完毕以后,
4)再把“加载更多”按钮,让它显示,
5)再让“等待指示器”隐藏,
运行一下看看,它会不会等待一秒钟,
是不是等待一秒钟了,
这个是不是也回来了(加载更多按钮),
这是不是就是这个效果吧,
这就是我们“加载更多”,模拟这么一个效果,
大家记这个dispatch的时候,你就先记dispatch,后面有个GCD,
用这个就OK了,
用这个,直接就双击,双击完毕以后,第一个参数,这里写的是,时间间隔,不是间隔,是“等待1秒钟”之后执行,里面的这个代码,
ok,这就是我们这里所说的这么一个延迟,
好,然后,紧接着我们再看一下,这个地方,
二、我们这个创建这个footerView,
1.我们这里创建这个footerView的代码,大家觉得有问题吗,在ViewController.m文件中,
我们这里创建这个footerView,这个代码,是不是直接通过xib,加载footerView的代码,是不是直接写在这个地方了,
把通过xib加载footerView,的代码,直接写在这里,
这样写好吗,不好,有什么不好,
还是那两个原因,
1)如果说,我有100个地方,用到了这个footerView,我是不是在100个地方,得手动去加载一下xib,是不是,这是第一个问题,
2)第二个问题是,你这个封装的不够,那么现在这个footerView,是通过xib来写的,可以这么写,一旦你footerView,它不再通过xib来创建了,这个时候,你把这个代码一改,是不是100个地方都得改,
因为100个地方,都是直接通过xib来加载的啊,
所以说,我们还是希望封装一个类方法,那么把这个通过xib加载这个自定义控件的代码,封装到这个类方法里面,
然后你需要用到这个footerView的地方,直接调这个类方法,创建一个footerView,就OK了,
就是,把这个也是封装到一个类方法里面,
把通过xib创建footerView控件的代码,封装到一个类方法当中,
CZFooterView *footerView = [[[NSBundle mainBundle] loadNibNamed:@“CZFooterView” owner:nil options:nil] lastObject];
2.所以说,我们把这个代码,再给它封装一下,来,找到我们的这个footerView,找到CZFooterView.h文件,
来一个类方法,+ (instancetype)footerView;
实现一下,在CZFooterView.m文件中,
+ (instancetype)footerView{
//在里面,其实很简单,就是通过xib,创建一个footerView,然后把它返回,
CZFooterView *footerView = [[[NSBundle mainBundle] loadNibNamed:@“CZFooterView” owner:nil options:nil] lastObject];
return footerView;
}
有人说,你这里面不就也是这句话吗,对,也是这句话,但是,你如果这么写的话,在控制器里面,调的时候,就没有必要这样调了吧,
是不是直接调它的类方法,就OK了,
CZFooterView *footerView = [CZFooterView footerView];
然后,如果说,哪一天,这个xib,这个footerView不是根据xib来创建的,你只要把footerView里面,把这个方法中的代码,改了就OK了,
对于控制器来说,控制器的这儿的代码,需要改吗,不需要吧,因为它是不是调这个方法去了,
这样就达到了,当需要修改的时候,只需要修改你特定的地方,不需要修改项目中其他的地方,
这样就尽量降低了耦合度,控制器就不会依赖于,对应的这个footerView了,footerView的改变,不会影响控制器的代码,这是我们的一种设计思想,
所以说,我们把footerView这里,再做一次封装,
好,到此为止,我们这个加载更多,也OK了,
三、然后,这里再给大家提一点,在我们这个代理方法当中,
1.找到控制器里面这个代理方法,控制器里面,有个footerView这个代理方法,