protocol - 1

来源:互联网 发布:php-fpm 1000并发量 编辑:程序博客网 时间:2024/05/16 17:40

优秀的文章:http://www.cnblogs.com/kenshincui/p/3869639.html#protocol

http://www.cnblogs.com/wendingding/p/3709604.html


学习iOS的协议我们先来看看面相对象的接口是什么?以java为例:

接口
接口是另一种定义数据类型的方式。它和类非常相似的。
相同之处:都有成员变量和成员方法
                  也可以形成继承关系
不同之处:接口中的属性都是常量(final)
                  接口中的方法是抽象方法(没有方法体)
引入接口的原因:Java只支持单重继承,每个类只能有一个超类。但实际应用中有时候需要多重继承--使用接口,一个类可以实现多个接口。

看到这里就大概明白了Objective-C实现协议的重要性了吧,Objective-C是不支持多重继承的,所以可以使用protocol来完成多重继承的效果,细细一想就会明白,一个ViewController只会继承UIViewController类从而拥有相关的控制视图的能力,然而如果你想要在它的属性UIView上展示多样的效果,例如你可以实现<UITableViewDelegate>协议来实现,如果你想要特定操作有弹出狂的警示效果, 你可以实现<UIAlertViewDelegate>的协议等等。从而完成行为的多态性。


我们来看看最常用的协议UITableView的官方定义:

DataSource部分:

@protocol UITableViewDataSource<NSObject>@required- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;@optional- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;    - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;                                                    - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index;  - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;@end


Delegate部分:(方法太多了,只展示常用的部分)

@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>@optional- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;@end


UITableView类的属性:

@property (nonatomic, assign)   id <UITableViewDataSource> dataSource;@property (nonatomic, assign)   id <UITableViewDelegate>   delegate;


观察上面的可以发现实现的语法很简单@protocol定义协议,协议在ObjC中是一组方法规范,实现协议的类就可以实现该协议所定义的方法。而@required就是必须实现的方法,例如上面datasource的定义的多少个section,每个section有多少行数。@optional就是可选的实现项。显然地@required和@optional都不是必须项。但是两者方法至少有一种需要被定义。

而在UITableView类的属性我们可以看到定义了两个id类型的变量,这个用 < SomeReusableDelegate > 约束起来的语法意义就是遵守这个协议。很显然不是所有的变量都命名为delegate,所以这一块语法叫ObjC的协议而不是委托,而委托delegate其实是一种设计模式,通过委托对象来实现所需的操作,而这种设计模式就是靠ObjC的协议来实现。

转大牛的一段话:

事实上在ObjC中协议的更多作用是用于约束一个类必须实现某些方法,而从面向对象的角度而言这个类跟接口并不一定存在某种自然关系,可能是两个完全不同意义上的事物,这种模式我们称之为代理模式(Delegation)。在Cocoa框架中大量采用这种模式实现数据和UI的分离,而且基本上所有的协议都是以Delegate结尾。

细细一想的确如此,实现两个协议protocol , 一个是dataSource 另外一个是delegate,  一个负责数据相关的方法的实现,另外一个负责UI相关的方法的实现,而这两者都是体现了约束的意味,你遵守了协议,你就必须去实现它们的方法,不然你遵守来干嘛?



而观察到每一个协议都会扩展<NSOject>  (在创建的时候默认添加的),进入头文件一看:

@protocol NSObject- (BOOL)isEqual:(id)object;@property (readonly) NSUInteger hash;@property (readonly) Class superclass;- (Class)class;- (instancetype)self;- (id)performSelector:(SEL)aSelector;- (id)performSelector:(SEL)aSelector withObject:(id)object;- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;- (BOOL)isProxy;- (BOOL)isKindOfClass:(Class)aClass;- (BOOL)isMemberOfClass:(Class)aClass;- (BOOL)conformsToProtocol:(Protocol *)aProtocol;- (BOOL)respondsToSelector:(SEL)aSelector;- (instancetype)retain OBJC_ARC_UNAVAILABLE;- (oneway void)release OBJC_ARC_UNAVAILABLE;- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;@property (readonly, copy) NSString *description;@optional@property (readonly, copy) NSString *debugDescription;@end

这里协议和普通的类一样具备普遍的面向对象继承的特性,NSObject充当一个“根协议”的作用,这里面提供了很多很有用的方法,例如判断是否拥有响应方法等。根据这个面向对象的继承特性,父类如果遵守了一个协议,子类也会相应地遵守。但是这里最有趣的是这两个属性:

@property (readonly) NSUInteger hash;@property (readonly) Class superclass;

一个整形的hash哈希变量和一个超类的属性,什么鬼? 不是说协议是定义一组 “行为” (方法)规范的接口吗?为什么有属性变量的?即使java中的接口是能定义变量的(只能定义常量final变量),为此百度和google了一下:

http://bbs.csdn.net/topics/391027845

http://stackoverflow.com/questions/21023822/how-to-declare-variables-in-protocol

不纠结了,大体说的就是没有意义的定义方式,如果实在要用则具体情况而言来添加static和extern。


具体实现:

在视图控制器中,将这两项委托的代理人置给自身:

    tableview.delegate   = self;    tableview.dataSource = self;

当然前提是要实现这个协议,不然会报下面这样的错误的哦:



另外提一个问题:为什么参数类型要填上weak ?  嘻嘻,其实就是防止(父子对象)之间循环引用导致的内存泄漏。



非常好的文章:http://bbs.9ria.com/thread-258284-1-1.html

0 0