【团购-自己实现代理 Objective-C语言】

一、我们上节课,实现了数据加载,下面是不是有个加载更多啊,

加载更多

1.我们先把这个“加载更多”给大家做一下,

这个加载更多,注意看,因为这个加载更多,是显示在UITableView的最底部的,

它会随着UITableView一起滚动吧,

证明,它是在UITableView的tableFooterView里面显示的吧,

然后,点一下它,它能点,证明它是个按钮吧,

拼命加载

点一下它,点完以后,会显示什么,是不是会显示这么一个转的这么一个效果,

然后,转完以后,会向数据中,真的加一条数据啊,

会向数据里面,确实增加一条数据,

这就是基本这么一个效果,

好,那么注意,接下来,我们就来给大家看一下,中间这个怎么来显示,

好,接下来,咱们就试着实现一下,下面这个东西,

2.由于下面,我们要在tableFooterView里面,加这么一个东西吧,

加这么一个东西

加这么一个东西,

大家首先想到,这可能是个按钮,

那么,我么给它加一个按钮,设置个背景色,看看,按钮能不能实现我们这么一个效果,

注意,下面我们这个黄色的一条,距离左右都有一段距离啊,

黄色这条,距离左右都有一段距离,

加载更多,我们要在最下面,footer里面显示一个东西吧,

所以,我们就在控制器的View,加载完毕以后,

viewDidLoad,找一下,

这是控制器的View加载完毕以后的方法,

然后,

- (void)viewDidLoad{

[super viewDidLoad];

self.tableView.rowHeight = 44;

//设置UITableView的footerView,

//那么,设置footerView,用的是哪个属性,

self.tableView.tableFooterView =

类型

因为它的类型,是一个UIView,

所以说,任何类型,是不是都可以设置过来,

比如说,给它来一个UIButton,

UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];

btn.backgroundColor = [UIColor redColor];

//是不是给它来个红色背景啊,

self.tableView.tableFooterView = btn;

运行一下看看,

运行一下看看

看到了吗,我这里根本就没有设置Button的Frame,

没有设置它的宽和高,X和Y,什么都没给,

但是,默认,它的宽是多少,和屏幕一样宽,

高,是不是默认有一个高度啊,

并且,它距离Footer的左上角,是不是0,0,点,

也就是说,对于我们这个FooterView里面的控件来说,你不需要设置Frame,它默认就有一个大小,

那么,我改一下吧,我改一下它的Frame,看看我怎么改,

btn.frame = CGRectMake(20,5,30,10);

距离左边,20,距离上边,5,宽度给个30,高度给个10,

我是不是给了它这么一个Frame,

来,咱们看一下,给这么几个值,它会管用吗,

管用

距离左边,是不是20,距离上边,5 ,有吗,没有吧,

是不是紧贴住上边的啊,

距离上边5,是不是设了跟没设一样,

宽度是30,起作用吗,

是不是宽度是30,也不起作用,

高度是10,起作用吗,起作用了,

来,我把高度变成100,

距离上边,变成50,咱们来看,

btn.frame = CGRectMake(20,50,30,100);

这两个哪个会起作用呢,

高度

是不是高度100,是不是变了,是不是距离上边50,根本就不起作用,

也就是说,这个FooterView,UITableView的FooterView,

我们只能改它的X的值,和它的高度,

它的宽和Y,是没法改的,

明白,这是一个特点,所以说,我们不可能改它的宽和Y,

//tableView的footerView,只能修改X和height的值,

//Y和width不能改,

好,那么这两个是不能改的,既然它不能改,

大家想想,既然宽度都不能改,

那么我能不能直接通过,修改frame的方式,实现这个效果,左右都是,

效果

左右都有两条儿,这个效果,

因为你可以改X,距离左边10,这个是不是可以实现,

但是距离右边这个值,你只能是让按钮变的窄一些,不要那么宽了,

这样的话,它会距离右边,是不是有点儿距离,

但是,我们发现,宽,是不是不能改,

宽度不能改,所以说,我们是没法通过直接修改这个按钮的frame,

来实现我们左右都有一定距离这个效果的,

没法实现的,

明白,这是第一,

第二,当我们点击“加载更多”的时候,它是不是要变成一个小的那个“等待指示器”,那个东西吧,

然后这儿显示几个字儿,“正在努力加载“,

是不是当你点击的时候,里面的控件,是不是要变成其他的几个控件,

也就意味着,我们这个footerView,

不仅仅是一个按钮,

是不是还有可能有其他子控件,

正是因为这些原因,

所以说,我们实现这些功能,不会直接给这个footerView里面,加一个按钮,就完了,

在这个footerView里面,是不是有好几个子控件啊,

并且还要实现左右各有一条儿这个效果,

所以说,我们这个时候,思路就是,

在UITableView的footerView下面,首先给它一个大的一个UIView,

然后,在UIView里面,我们再,摆一些其他子控件,

实现这个效果,

明白我的意思吗,,

3.这个时候呢,这个footerView,我们要放一个UIView,

UIView里面,要放其他子控件,

这个时候,我们也可以用一个xib来实现,

如果不用xib,是不是得自己写代码,一个一个来加这个子控件,

这样比较麻烦,所以说,这个时候,我们也要用一个xib来实现,这个footerView,这个东西,

好,这个时候,我们就拽一个xib吧,

xib,是不是要新建一个,相当于是View里面的东西,

新建

ok,新建一个文件,

新建

新建一个Empty,

新建

我们叫什么,CZFooterView.xib

4.这个footerView,是不是整体是一个UIView啊,

整体是UIView,所以我们要拽一个UIView过来,

拽

拽一个UIView过来,

拽一个UIView过来,默认这个UIView,我们能改它的大小吗,不能吧,

不能

是不是默认都是600,600,不能改吧,

要想让它能改,得怎么办,

怎么办

得把这个UIView的Size,改成freeform吧,

是不是可以给它自由大小吧,

然后呢,这里就有三个点儿了,

三个点

有了三个点儿以后,就表示它可以改了,

宽度是不是和那个是一样宽的,320,

高度,我们可以给它来个多少,来个44,可以吧,

这样的话,下面这个UIView的高和宽,就有了吧,

高和宽

6.然后,注意,我们这个实现这个思路的时候,不是说,让这个UIView的背景色,变成黄色,

背景

UIView,整个就是320,

在UIView里面,加一个按钮,这个按钮的宽度,比如说是,300,

距离左边,是10,距离右边是10,

所以,这样的话,是不是就可以实现这个效果了,

8.我们给它加一个按钮,

宽是多少,300,高是多少,高是不是占满整个这个东西啊,

有点距离是不是也行,整个它是44,给它来个40,可以吧,

按钮

既然是40,距离上面就是几,2吧,

现在居中了吧,

距离左边呢,来个10,

距离右边,也是10 吧,好,

文字

然后,给它来个,文字变成,“加载更多……”

然后呢,接下来,是不是设置这个按钮的背景色啊,

按钮的背景色,BackgroundColor,

是不是在这里,

背景色

是不是在这里,background吧,什么颜色,

背景色

什么颜色,橘黄色吧,

橘黄色

这是不是就这个效果啊,

这就是我们“加载更多”,这个按钮,

有了这个按钮以后,不仅如此,当我们,点击这个加载更多的时候,

是不是要变成,左边是一个“指示器”,右边显示一个“正在努力加载……”,这几个东西吧,

所以说,当你点击它的时候,要让这个加载更多,按钮隐藏,

同时,替换显示的是不是一个等待指示器,和一个Label,

和一个文字,

也就是说,当点击按钮的时候,要让被点击的这个加载更多按钮隐藏,

同时,是不是显示另外两个控件吧,

所以说,另外两个控件,要么是一起显示,要么是一起隐藏,

什么时候一起显示呢,

当你点击“加载更多”的时候,这个加载更多按钮隐藏掉,

另外那个“转的那个指示器”,和那个“正在努力加载……”那个Label,

它们俩一起显示,

当内容加载完毕以后,这两个东西一起隐藏,

然后这个橘黄色的“加载更多”按钮,是不是再显示出来,

是不是这个“加载更多”按钮,和那两个控件,是不是正好相反的吧,显示,

这个显示,“加载更多”按钮显示,那个“等待指示器”和那个Label隐藏吧,

当那个“等待指示器”和Label显示,的时候,这个“加载更多”按钮它就隐藏了,

好,所以说,我们这里,可以怎么做呢,

10.可以在这个下面,在这个UIView里面,再拽一个小的UIView,

在这个小的UIView里面,放两个子控件,

一个是那个“等待指示器”,一个是那个Label,

上面显示“正在努力加载……”,这么几个文字,

加载

拖一个小的UIView上来,

小

好,那么整体呢,是320宽,我让里面这个白色View的宽度,变成多少,变成220,怎么样,

220太大了,200吧,

然后,高度呢,让它也变成40吧,

它距离上边,就是2,

距离下边,也是2,

然后呢,让它距离左边……,320减200,等于120,120 除以2,等于60吧,

让它距离左边,X = 60,

这样它就刚好居中,

它刚好是把刚才那几个文字,盖住了,

按钮

当显示它的时候,后面的也就看不到了,

然后,里面呢,当我们,当大家用那个手机的时候,当你们联网的时候,联网操作,下面是不是有个小东西,它转啊,

转圈儿那个东西,就是等待指示器,

WaitingActive

在这里

在这里,

在

这个就是等待指示器吧,

叫什么,UIActivityIndicatorView,

活动指示器,

然后把它拽过来,

拽

拽到这儿,然后呢,旁边,有一个Label,来个“正在努力加载……”

正在努力加载

字体改成14号字,

改字体

文字改成“正在努力加载……”

改文字

努力

正在努力加载,这样是不是OK了,

好,这样的话,Label就有了,接下来,

我们来看,这个xib里面,

1)有了一个View,

2)这个View里面,有了一个等待的这么一个View,

3)还有个“加载更多”按钮,

等会儿,我们就希望,在footerView里面,显示这个UITableView

三、接下来,我们就要在footView里面,加载这个xib里面的View,显示到footerView里面,

1.在footerView里面,要加载那个xib,

这个是不是就删掉它,就不要了吧,

删掉

注释掉吧,留个代码痕迹,

//通过xib,设置UITableView的footerView,

//是不是要加载xib,

[[NSBundle mainBundle] loadNibNamed:@“CZFooterView” owner : nil options : nil];

//这样加载完毕以后,是不是这个xib中的所有子控件,是不是都加载起来了,

//我们里面,只有一个,现在是不是只要一个,

//lastObject,firstObject,是不是都可以,

[[[NSBundel mainBundle] loadNibNamed:@“CZFooterView” owner : nil options : nil] lastObject];

//然后,这里,返回,就是什么,UIView,吧,

UIView *footerView = [[[NSBundle mainBundle] loadNibNamed:@“CZFooterView” owner : nil options : nil] lastObject];

//然后,我们让这个self.tableView.tableFooterView,

//等于我们这个footerView,

self.tableView.tableFooterView = footerView;

等于

//这样的话,是不是设置好下面的footerView了,

//来,咱们这个时候,运行,看一看,

有了

//是不是有了,但是,我们发现,一开始,这个玩意儿,就不让它显示吧,

//是不是一开是要它显示那个“加载更多”,

//怎么样让它一开始不显示呢,

//对,你直接设置这个View,让这个View整体一开始隐藏掉,咋让它隐藏,Hidden,就勾一下,

隐藏一

让它一开始隐藏掉,

Hidden

勾上以后,再Command + R 运行,

隐藏

好,这个时候,是不是一开始隐藏掉了,

就不显示那个View了,

3.然后,我希望,当我点击,这个按钮的时候,希望要有点击事件啊,

你是不是要给这个按钮注册点击事件啊,

既然你要给这个按钮注册点击事件,是不是要通过拖线的方式,给它注册一个点击事件,

既然要拖线,所以这个View,它能使用系统默认的这个View类吗,

系统

是不是又得自己定义一个FooterView类了吧,

所以说,是不是得再写一个类啊,

再写一个类,继承自UIView,

再写一个类,

类

继承自UIView类,那么这个类的名字,怎么起呢,注意看,

这个类的名字,一般,和这个xib的名字是一样的,这样的话,别人一看,就知道,它们三个是一起的,

这个类的名字,最好和这个xib的名字是一样的,

类

写好这个以后,我们直接让当前xib里面,这个View对应的类,这儿改成我们自己的类,

类

这样的话,我们在控制器里面,通过xib创建这个View,还是UIView吗,

UIView

不是了吧,成了什么了,是不是我们自定义的那个View了,

引入“CZFooterView”的头文件,

引入头文件

#import “CZFooterView.h“

在viewDidLoad中,

CZFooterView *footerView = [[[NSBundle mainBundle] loadNibNamed:@“CZFooterView” owner : nil options : nil] lastObject];

类

4.变成我们FooterView类以后,接下来,因为这个xib里面这个View已经有对应的自定义的类来支持了,所以说,这个时候,就可以怎么办了,

就可以拖线了吧,

首先,这个类里面,没有类扩展,

类扩展

所以要怎么办,在CZFooterView.m文件中,加一个类扩展,

@interface CZFooterView ()

加一个类扩展,

类扩展

给这个“加载更多”按钮拖线,

拖线

1)一个按钮,先把这个按钮的属性引用起来,

引用

选择Connection:Outlet,

Name,叫什么呢,btnLoadMore,

2)这个“等待View”,是不是也要用一个属性引用起来,

等待View

因为等会儿咱们是不是要写代码,要操作这两个东西吧,

等待

Connection,选择Outlet,

Name,叫什么呢,waitingView,等待的这个View吧,

3)然后呢,给“加载更多”按钮,注册一个单击事件,

单击
单击

Connection,选择,Action,

Name,叫什么呢,btnLoadMoreClick,

Type,选择,id,

Event,选择,Touch Up Inside,

Argument,选择,None,

Object,不勾选Footer View,

OK,这样的话,这个按钮的单击,“加载更多”这个按钮的单击事件,是不是就有了,

加载更多这个按钮的单击事件,就有了,

然后,我们再运行的时候,看一下,现在我们可以看到下面这个FooterView,但是FooterView,是不是没有这个单击事件,

单击事件没有

单击事件,还没有写代码呢,

接下来,我们在这里,去写代码,,

写代码

在这里插入图片描述

这就是我们这个“加载更多”按钮的单击事件,

5.加载更多按钮的单击事件,

/**

* 加载更多按钮的单击事件

*/

- (IBAction)btnLoadMoreClick{

//1.把“加载更多”按钮隐藏掉

//2.把“等待”那个View显示出来,

//3.创建一条新数据,加到这个TableView里面,

//4.刷新一下TableView,

}

是不是一共就这么四步啊,

这个能想明白吧,

在这里插入图片描述

因为增加完一条数据,刷新完毕以后,才会显示吧,

不刷新,是不显示的,

1)隐藏“加载更多”按钮,

self.btnLoadMore.hidden = YES ;

2)显示“等待指示器”所在的那个View

self.waitingView.hidden = NO ;

我们这是一个加载,和隐藏,我们先看看这个功能,能用不能用,试一下,

点击

点击,诶,可以用吧,看到了吗,一点,那个“加载更多”按钮,是不是就没有了,这个等待这个View,是不是显示出来了,

但是有没有感觉,好像有点儿不太正常啊,

不转吧,不转,

这个时候,用户以为死机了呢,对吧,

所以说,这个时候,得让它转,注意,这个不转,是它默认的一个特性,这个“等待指示器”,它默认就是不转的,你需要让它转,得设置一个属性,

这个“等待指示器”,人家默认就是不转的,怎么让它转呢,它有一个属性,叫做Animating,

Animating

Behavior,行为,Animating,把它勾上,

默认它是不执行动画的,

你把它的Behavior的Animating,勾上,

这样的话,只要它一显示,它就开始动画的方式,

就是“转”的方式,

然后呢,当这个“等待指示器”,当被隐藏掉以后,是不是就可以不转了,所以,可以把这个Hides When Stopped,勾上,

当它停止以后,可以把它隐藏掉,

当然我们这里勾不勾都行,

因为我们反正要把整个这个View,把它隐藏掉,

这样的话,我么再运行,

这样的话,它就开始转了,但是,转还不够,转的时候,我还要干点儿活儿吧,

事实上,我们应该,在它转的时候,联网去采集数据吧,

但是我们现在学网络了吗,没有,所以我们能做吗,不能,所以我们只能装一下,做个假的,

做个假的是怎么做个假的呢,

当你在加载的时候,我们可以向那个数组那个集合里面,创建一个新的模型,创建一条新的模型,给它设置数据,并且,把这个新的模型,加到那个goods那个集合里面,然后呢,接下来,goods这个集合里面,数据就变了,我们只要刷新一下tableView,刷新一下这个界面,然后是不是整个数据就有了,

所以说,接下来,我们要做的就是,

1)创建一个模型,

2)把模型加到集合里面,

3)刷新UITableView,

把这三步搞定,就可以了,

创建模型,会创建吗,

二、创建模型,

1.在哪里创建模型,是不是在这个footerView里面,

创建模型

2.增加一条数据里面,要做的有这么几步,

第一步

1)创建一个模型对象,

2)把模型对象,加到控制器的goods集合当中,

3)刷新数据,

那么,创建一个模型,非常简单,直接new一个模型,给它设置数据,就可以了,

但是,第二步,这儿有一点点难度,注意听,

创建

你这儿创建一个模型以后,是不是要把模型加到goods集合里面,

要把模型,加到goods集合里面,

在这里,能访问到那个goods集合吗,

注意,我们这是哪个类,

哪个类

footerView这个类吧,自己写的这个footerView这个类型吧,

类型

这个类里面,你能访问到控制器这个类型里面的goods这个集合属性吗,

集合

肯定访问不到吧,

所以说,这就是一个问题,

那么,大家告诉我,这个时候该咋办,

在我们的这个自定义的View里面,

你要想访问控制器里面那个属性,你是访问不到的,这个时候,大家首先想到的,就是通过代理,

注意,怎么去想这个问题,这么去想这个问题,

现在谁,要做什么,它能做到吗,办不到,

然后它看一看,谁能做到这个事情,那么就让谁,来做为我的代理,

你生活中,比如说是,你开车去了一个酒店,然后呢,吃了很多东西,喝了很多酒,出来以后,你是不是醉了,你敢开车吗,敢……,

你要是不怕进去,那你就开,

那么,一般人,是不是都,就算他不怕罚钱,他也怕自己撞死吧,

就算他不怕自己撞死,他不会怕撞死别人的,主要是他怕撞死自己,

那么,他肯定是自己不能开车,

那么,这个时候,现在就是,这个人想开车回家,但是他喝醉了,他不能开车,对吧,所以说,他这个时候,看谁能开车,

代驾,对,说得非常好,直接打个电话,代驾是不是可以帮他开车吧,

所以说,这个时候,那个代驾,作为他的代理吧,

他让那个代驾公司作为他的代理,帮他开车,把他送回去,

明白我的意思吧,

所以说,我们这儿,和这个非常非常像,注意听,

现在是,我们这个自定义的footerView,

加载

现在是这个footerView,它希望创建一个模型,向我们那个模型数组中,加一条记录,

footerView,希望访问到goods那个数组集合,

但是,footerView,是不是访问不到,

它是不是没有这个能力,

然后它就看,谁,可以访问到那个goods集合,

它找了一圈儿,发现,这个控制器,那个goods集合,是不是在控制器里面,所以说,它发现,控制器可以访问到那个goods集合吧,

控制器,可以访问到goods集合,

所以说,这个时候,footerView,它就想,能不能让控制器,作为我的代理对象,

能,所以,这个时候,footerView,就想,把控制器,作为我的代理,然后呢,我让控制器帮我去把这个模型,加到那个goods集合里面,是不是就OK了,

所以说,这个时候,就是我们自己实现代理,

我们前两天,说代理,是不是我们用别人写好的代理,

现在我们是不是要自己写代理啊,

我们要自己去写代理了,明白我的意思吗,

自己写代理,有个问题就是,你得想清楚,谁要作为谁的代理,

这个必须想明白,这个如果想不明白,就别写了,根本写不出来,

那么,怎么就把这个问题想明白了,

你就想,你现在想干啥,我现在想在goods集合中,加一个模型,

你能做到吗,如果能做到,就不需要代理了,

你做不到,因为你访问不到那个goods集合对象,

那么,你就看,谁能做到,goods集合,是不是在控制器里面,

所以说,控制器是不是可以做到啊,

既然,控制器可以做到,那么就让谁作为我的代理,控制器吗,对吧,

我做不了这件事儿,别人谁能做到这件事儿,我是不是就让谁作为我的代理,

所以说,控制器就可以作为你的代理,

所以说,将来,代理对象,就是谁,就是控制器对象吧,

那么,既然控制器对象,要作为你的代理对象,

所以说,控制器对象,是不是得遵守你的代理协议啊,

所以说,别人,要作为你的代理对象,你要找代理,这个时候,是应该你来发布一个代理协议,然后让控制器来遵守这个协议啊,

所以说,当自己写代理的时候,就这么几点,大家要注意,

1)第一,你要做什么事儿,能不能做到,如果能做到,直接做,

如果做不到,找代理,

2)第二,你要找代理,就得你自己发布一个代理协议,让将来,谁作为你的代理对象,它来遵守你这个协议吧,

所以说,要写代理的时候,

1)第一步,确定,谁要找代理,谁要找代理,就让谁来发布这个代理协议,

2)第二步,谁能帮你干活儿,能帮你干活儿的那个人,就是你的代理对象,

将来就把它设置为你的代理对象,

3)第三步,让它来遵守你的代理协议,

4)第四步,让它去实现你的代理方法,

其实,当你自己写代理的时候,无非是这么几点,需要你注意,

1)在哪儿去写代理协议,

2)谁是代理对象,谁来遵守这个代理协议,

把这些搞明白,就OK了吧,

3.现在我们知道,谁要找代理了吗,

footerView要找代理吧,

那么,谁作为它的代理对象,

是不是控制器啊,

好,这些弄明白以后,既然footerView,它要找代理,它是不是就得发布一个代理协议,

我们说,代理协议,它就是一个什么,就是一个协议吗,对吧,

协议里面,是不是就是一堆的什么,方法的声明吧,

协议里面,就是一堆的方法的声明,

那么既然它是一堆的方法的声明,在你写这个代理协议的时候,

你是不是得知道,我这个代理里面,应该写什么方法吧,

如果你都不知道应该有什么方法,那么你这个代理,是不是根本没法去发布这个代理协议吧,

我们虽然知道了footerView,它要找代理,

所以说,我们是不是在footerView里面,它要发布一个代理协议吧,

那么,但是我们还不知道这个代理协议里面,应该写什么样的方法吧,

那么,怎么来确定,你要写什么样的方法呢,

注意,这个代理协议中,应该写什么样的方法,就取决于现在,你这个footerView,想干什么,footerView想干啥,footerView,现在是不是想增加一个模型,然后把模型加到goods里面吧,

其实,它就是想增加一条数据啊,

所以说,在那个代理协议里面,写这个方法,就是用来增加一条数据的方法,

你可以把这个方法名儿,起成addNewModel,

或者说,你也可以把它起成一个什么呢,我们增加一个数据的方法,其实就是当用户点击完毕以后,loadMore,这个button,以后,是不是要做的一个事情,所以说,这个代理协议中的方法,也可以把它名字叫做,loadMore,具体这个方法名儿,咱们等会儿再起吧,

反正你就得知道,当你写协议的时候,协议里面到底有什么方法,取决于你当前要找代理对象的这个控件,它想干啥,它想干啥,协议里面那个方法,你就写这个方法,然后,再来遵守协议的那个代理对象,它把它实现了以后,是不是你直接调那个方法,就做了你想做的事儿了,

2.来,我给大家画个图,来理解吧,

来,注意看, 右边是什么,猜一猜,

代理

footerView吧,

左边是什么,控制器吧,

代理

现在,footerView,它是不是想做一件事儿,

但是它做不了,它发现控制器能做,所以说,footerView要把控制器作为它的代理,

既然footerView要找代理,所以说,得手动的为footerView增加一个属性,叫什么,delegate吧,

就是这个属性的名字,叫做delegate,

为什么要叫delegate,因为系统里面的代理,它的名字就叫delegate,所以说,我为了模仿一下系统里面的代理,所以我也把它的属性,叫做delegate,

你如果不叫delegate,行不行,代码上是可以的,运行也不报错,

但是这个时候,就属于你这个人比较奇怪,所以你进了一个团队以后,我们代理名字都叫delegate,你代理名字非要叫daili这个拼音,虽然别人也能明白,但是这个人,会觉得,这个人没有文化,

所以说,我们要为 footerView,找一个代理,所以说,就要在footerView中,加一个delegate,属性啊,

加一个delegate属性,我们刚才说,你footerView要找代理,将来代理对象,得遵守一个代理协议,你footerView是不是还得发布一个代理协议,

既然你footerView要发布一个代理协议,

第一步,是不是得确定这个代理协议的名称,

我们之前有一个控件,叫UITableView,它是不是有个代理啊,它的代理名字叫什么,UITableViewDelegate,吧,

那么,我们现在这个控件名称,叫做CZFooterView,

CZFooterView

它的代理,你觉得叫啥,CZFooterViewDelegate,吧,

要为CZFooterView编写代理协议,那么代理协议名称就叫,

CZFooterViewDelegate,

代理

好,这样的话,是不是确定了这个协议了,

然后呢,确定了协议以后,编写协议方法吧,

2.编写协议方法,

编写CZFooterViewDelegate中的方法,

编写完方法以后,控制器遵守那个协议吧,

实现协议中的方法,

协议

这样的话,我们最终,把delegate设置成控制器,这样就搞定了,

设置

好,我们现在知道这个整体的流程,整体的过程了吗,

接下来,咱们从代码级别,来给大家过一遍,

3.代理

1)第一步,它要找代理,我先给它写一个代理协议,

代理协议

这个代理协议,怎么写呢,写在哪儿呢,不需要新建一个文件,来写,直接写在这个控件的.h头文件里面,就OK了,

为什么直接写这儿呢,因为这个代理协议是为了这个CZFooterView,为这个控件而生的,也就是说了,只有当你用到这个控件的时候,才会用到那个代理协议吧,

所以说,这个代理协议,不需要写在别的地方,只要写在这个控件的头文件里面,就可以了,因为,当你用到这个控件的时候,一定会导入它的头文件,只要导入它的头文件,把你的代理协议是不是也导进来了,

所以说,当你为某个控件写代理协议的时候,就把这个协议写到这个控件的头文件里面,就OK了,

协议

协议咋写,还记得吗,@protocol,回车,

协议

这个代理协议名字,我们是为这个控件写代理协议,

协议

我们是为这个控件写代理协议,CZFooterView,所以就叫什么,CZFooterViewDelegate,

好,这个协议就写好了,

协议

后面,这表示啥意思,

协议你

表示这个协议,也遵守了NSObject,这个协议啊,

任何协议,都会遵守这个协议的,

好,这个协议写完了,协议里面,是不是要写一个协议方法啊,

我们想想,我们最初写这个协议的目的是啥,为啥要写它,

目的

是点击完“加载更多”按钮之后,要更新模型数据吧,

所以说,你这个方法名儿,就可以起一个“更新模型数据”,或者也可以起一个,当这个loadMoreButton,点完以后,都可以,

来,咱们给它起个名称,我们这个协议,是用来更新模型数据的,那么我么就可以给它起一个,比如说是,在起名的时候,我们还是先别着急起名,

我们想想,我们那个UIScrollView,是不是有一个代理方法,叫什么,

凡是UIScrollView的所有代理方法,都叫scrollView,什么什么什么,吧,

是不是都叫scrollView什么什么什么吧,还记得吗,

忘了,咱们看看,

看看
代理

UIScrollViewDelegate,注意看,凡是UIScrollViewDelegate里面的方法,

名字都是以什么开头的,scrollView什么什么,scrollView什么什么吧,

代理

是不是,如果它没有参数,只把自己传过来,

把自己传过来

是不是任何一个代理,注意看,在这个UIScrollView的代理里面,每一个代理方法,是不是都是把UIScrollView控件自己先传过来了,

如果还有其他的参数,是不是它在后面再传其他的参数,

如果没有其他的参数,只有一个参数,就把自己传过来了,

这是我们写代理的一个规范,

所以说,我们为自己的控件写代理的时候,也要先把控件自己传过来,

如果有别的参数,后面再写其他参数,

如果没有别的参数,就写这么一个参数,就够了,

你不能说这个代理协议,代理方法中,没有参数,这样是不行的,

必须至少有一个参数,就是控件自己,

这是我们的规范,

好,那么所以说,命名规则,就是什么控件的代理方法,就是什么控件,后面跟具体的名字吧,

名字

然后,后面有一个参数,是控件自己,

好,既然这样,大家说,这个代理方法,应该以什么开头,

- (void)footerView……

然后呢,我们这个是footerView,是用来更新数据的吧,

所以我们可以给它起个,footerViewUpdateData,

或者说,footerViewAfterClickedLoadMoreButton,

是不是都可以,

参数

然后呢,这里来个参数,参数呢,就是,你是谁的代理方法,就要把那个控件自己传过来,

- (void)footerViewUpdateData:(CZFooterView *)footerView;

那么,这个控件,是哪个控件,CZFooterView,

然后,后面就是一个footerView,这个参数名儿,

参数

但是,注意看,你在这个写协议的时候,能不能访问到这个类型,

代理

为什么访问不到这个类型,

因为,你写这个时候,

代理

这个时候,还没定义啊,

没定义

那么,你在这儿,要访问这个类型,咋办,

咋办
这样

这样,是不是就搞定了,

这就是我们,协议,写好了,

好,现在我们要为footerView写协议,

第一步,协议已经定义好了,

协议定义好以后,第二步,是不是就可以为当前footerView写一个delegate属性了,

delegate属性

我这儿就要问了,是pcopy,还是pstrong啊,

代理

pstrong还是pcopy?

问题

@property(nonatomic , copy) NSString *name;

@property(nonatomic , strong ) NSString *name;

这儿是应该copy,还是strong 啊,

先别管这个,先说后面这些,

这个地方,我们说,这个属性的数据类型,是什么类型,

ID

id,对,数据类型,是id类型,然后呢,

是不是加个协议吧,数据类型是,

id加协议

id加协议,数据类型是id加协议,id< CZFooterViewDelegate >

数据类型

然后,接下来,我们这个地方,是不是要写一个属性名儿了,

属性名儿,叫什么,delegate,

这就是我们这个delegate,属性的类型,就是id 加协议,就是id < CZFooterViewDelegate > ,

属性

然后,这个地方,是写weak,还是写我们的strong,

weak,为什么,

weak

weak,为什么,好,注意听,

我们之前给大家说过一点,就是UI控件,当我们在控制器里面,通过一个连线,用一个属性来引用UI控件吧,UI控件里面,最好使用weak吧,

但是,使用strong,是不是也对,

但是注意这里,这里这个关键字,必须使用weak,这儿如果要是用strong,就错了,这叫错误,

UI控件,如果你用strong,也行,也没啥错误,也能运行,也没有什么特别的,一点儿都不错,是可以的,

但是,这个代理协议,如果这个地方,你要是用strong,就错了,

那么这个咱们稍后再解释,为什么,

但是我再提醒大家注意一下,并不是所有的代理,都必须得用weak,

有时候,代理是必须得用strong的,

但是,对于我们UI控件的代理,CZFooterView,是不是我们自己定义的一个UI控件吧,对于一个UI控件来说,它的代理,必须使用weak,

如果是strong,就错了,所以我们先记住这个东西,等会儿咱们再去解释为什么,

大家知道为什么吗,那不知道,那就等会儿再解释,

知道的话,那就更好了,

来,看一下,那么我们首先,

1)定义了一个代理协议,

2)第二,为这个控件是不是增加了一个代理这个属性了吧,

属性

3)第三步,该干啥了,是不是我们得,第三步,我们先别着急,我们先把这个自定义控件都写完,第三步,我们是不是当这个代理,当我们程序运行的时候,是不是要用这个代理啊,用这个代理,ok,那我们看一下这儿怎么用啊,这么来用,

在这个UIView,里面,在这个footerView里面,

代理

第三步的时候,是不是要开始创建一个模型对象了,

是不是更新这个tableView啊,

这两步,我们通通把它放到代理里面,

代理

通通让这个代理方法来执行,

就是让控制器那个代理方法,在那个代理方法中,控制器自己去创建一个模型,控制器自己去更新UITableView,

所以说,这个地方,根本不需要写这么复杂,都别管里面怎么写的,根本不需要关心,怎么办,直接“调用代理方法”,

//调用代理方法,实现下面的功能,

调用代理方法

咋调用呢,调用代理,还记得吧,调用代理说过吗,忘记了,

注意,这儿可不是先设置代理,设置代理,是等会儿的事儿,我们现在是在footerView这个里面,在footerView里面,我们是不是写了一个delegate属性啊,self.delegate,属性,你只管用这个delegate属性,就可以了,

将来会有人给它设计的,明白,

但是不是我们自己设计,明白吧,这个地方能听明白我的意思吗,如果听不明白,咱们就先写,必须得听明白,

在这里插入图片描述

这里有个代理,这个代理将来是不是就是控制器啊,

我们说,控制器里面,有一个方法,有什么方法,

方法

我们说,控制器里面,有一个方法,是什么方法,就是这个footerViewUpdateData,方法吧,

我们说,将来控制器里面,必须得实现这个方法,既然必须得实现,那么,我们这儿给它加个什么关键字,@required,吧,

代理

这样如果不实现,你就告诉它,它就有问题吧,

它一定会有这个方法,既然一定会有这个方法,在CZFooterView.m文件中,

footerView里面,我们直接self.delegate,调footerViewUpdateData:(CZFooterView *),方法,把当前的self,

调方法

把当前的self,传进来,

代理

把当前的self,传进来,

self传进来

注意,这个self,指的是谁,

当前这个footerView,这个自定义控件,自己吧,

自己

指的是这个自定义控件,自己,

也就是说,当用户点了这个loadMoreButton,这个按钮之后,

1)第一步,你就隐藏“加载更多”按钮,

2)第二步,显示“等待指示器”,

3)第三步,你要增加一个模型,刷新UITableView,直接调这个代理方法,在控制器这个代理方法当中,它内部就会帮我们增加一个模型,刷新UITableView,啊,明白我的意思吗,

代理

那么,这样的话,在这个方法内部,就会实现这一堆功能,

功能

但是,这儿有一个小小的问题,一旦这个控制器,它就比较讨厌,这个控制器,它遵守你这个代理方法了,遵守这个代理协议了,但是它就是没有实现这个方法,这个时候,没有实现这个方法,你一调,是不是有问题了,

所以说,我们这里,得保证这个控制器,这个代理对象,它一定得遵守了这个方法以后,才调用,

所以说,我们在调方法之前,

//调用footerViewUpdateData方法之前,为了保证调用不出错,所以要先判断一下代理对象是否真的实现了这个方法,如果实现了这个方法,再调用,否则,就不调用,这样就可以保证不出错了,

调用

//如何判断这个代理是否实现了这个方法呢,怎么判断,

if(self.delegate respondsToSelector:(SEL))

调用

if([self.delegate respondsToSelector:@selector(selector))

//把这个方法传进来,footerViewUpdateData,

if([self.delegate respondsToSelector:@selector(footerViewUpdateData:)){

//code;

}

判断

//footerViewUpdateData,这个方法传进来,

代理

//这样的话,如果代理它实现了这个方法,这个时候,它返回的就是YES,如果是YES,我们是不是再去调这个方法啊,

调

//如果这儿返回的是NO,表示代理对象就没有实现这个方法,没有实现方法,我们就不调了,明白了吗,

//那么我们代理方法中,在代理方法中,

代理

//在代理方法中,

代理

//在代理方法中,是不是就执行了这一堆操作啊,

//3.增加一条数据

//3.1创建一个模型对象

//3.2把模型对象加到控制器的goods集合当中

//4.刷新UITableView

[self.delegate footerViewUpdateData:self];

//就执行了这一堆操作,

5.好,现在我们就是,当用户点击按钮的时候,

1)第一,隐藏这个按钮,

2)第二,显示“等待指示器“,

3)第三,是不是调代理,来实现更新数据啊,

接下来,我们这个自定义控件,就写好了,

接下来,我们是不是该让我们的控制器,去遵守协议,实现方法吧,

好,然后我们找到我们的控制器,

控制器

找到我们的viewDidLoad方法,

找到方法

在这个viewDidLoad里面,我们是不是创建好这个footerView了,

创建

创建好footerView以后,设置footerView的代理了吗,没有吧,

//设置footerView的代理,

footerView.delegate = self;

//footerView里面有个什么属性,delegate属性吧,把这个delegate属性,设置成谁,self,吧,

//把控制器自己,作为控件的代理,

//我们一般是不是,无论什么控件,都习惯把控制器自己作为这个控件的代理,

代理

注意,这里报了个警告,原因是什么,

在这里插入图片描述

是不是没有遵守这个代理协议吧,

既然你控制器要作为我的代理,CZFooterView的代理对象,所以说,控制器就应该怎样,

遵守协议

遵守我这个协议吧,

遵守

既然你遵守了我这个协议,所以说,控制器就应该什么,实现这个方法吧,

#pragma mark - CZFooterView的代理方法,

代理方法

6.怎么来实现呢,直接这么实现一下,

方法

- (void)footerViewUpdateData:(CZFooterView *)footerView{

//code;

}

//是不是就一个方法,

在这个里面,在这个里面,要做的事情,其实就是

这些事情

其实就是这些事情,

这些事情

拷过来,

3.增加一条数据,

其实就是创建一个模型,怎么创建,

CZGoods *model = [[CZGoods alloc] init] ;

model.title = @"驴肉火烧“;

model.price = @“6.0”;

model.buyCount = @“1000”;

model.icon = @“37e4761e6ecf56a2d78685df7157f097”;

//图片我就随便指一张图片了

//这样的话,这个模型,是不是都创建好了,

模型

//3.2 把模型加到我们的那个集合里面吧,

self.goods add……

加到集合里面

//注意,有没有addObject这个方法,没有吧,因为我这个goods这儿用的是什么数据类型,NSArray吧,

goods

//我们得把它变成NSMutableArray,

变成

//变成NSMutableArray,

变成

//这样是不是才可以向上增加,

//然后,这个地方,是不是这儿得改,

得改

#pragma mark - 懒加载数据

- (NSArray *)goods

{……}

//是不是这儿得改,

改

//然后,找到viewDidLoad方法,

//什么viewDidLoad,代理方法,

代理

//是不是在这个代理方法里面,

//在这个地方吧,

代理

[self.goods addObject:model];

model加进来

//好,这样的话,注意看,我们数据模型,创建了一条模型,并且把它加到goods里面了,

//然后,是不是该刷新UITableView了,

//4.刷新UITableView

刷新

[self.tableView reloadData];

//好,我们试着看一下,OK不OK,

驴肉火烧

来,驴肉火烧,出来,

驴肉火烧

是不是有火烧了,

是不是数据,是不是先有了,

然后,其他是不是还有一些细节,我没处理一下吧,

细节

驴肉火烧,是不是有了,

好,我们先说到这儿吧,先去吃饭吧……

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风清晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值