理解:
@protocal 可以定义一个协议。一个类如果使用了这个协议,那么就要按照这个协议要求的去办事。最常见的就是UITableViewDelegate、UITableViewDataSource这个两个家伙。我们的类可以使用这两个协议,并对协议定义的方法进行实现(numberOfRowsInSection, heightForRowAtIndexPath...),然后需要绑定。因为我们的类已经实现了这个这两个协议。所以我们类中的tableview可以这样绑定:
tableview.delegate = self;
tableview.dataSource = self;
接下来就有疑问了,为什么写了上面2句话,我们的tableview就可以回调我们类中实现协议的函数呢。
可以想象UITableView中是如何回调我们定义的协议函数:(大概是这样:)
[_delegate heightForRowAtIndexPath:indexPath];
[_dataSource numberOfRowInSection:section];
注:上面的_delegate,_dataSource是代表的UITableView中封装的属性(对象)。
如果写过面向对象,ios中的协议,Java中的接口的话,应该可以理解上面的代码。
它这样写就是可以实现回调。疑问解决。
为了更好地说明@protocal的意义。看一个我写的小例子。
通过一个最简单的Delegate的使用去讲述Delegate:
首先是ViewController对delegate的定义,实现。
这里是ViewControlle类的代码:
1 #import <UIKit/UIKit.h> 2 3 //声明协议passValueDelegate 4 @protocol passValueDelegate <NSObject> 5 6 -(void)myPassValue:(NSString*)msg; 7 -(void)myCallback; 8 9 @end 10 11 //ViewController类使用上面定义的协议,并将实现协议中的两个方法 12 @interface ViewController : UIViewController<passValueDelegate>{ 13 14 } 15 16 //ViewController自己保有了一个passValueDelegate的协议对象 17 //类似UITableView类中保有了两个delegate/dataSource协议对象 18 @property NSObject<passValueDelegate> *mDelegate; 19 20 -(void)callMeToDo; 21 22 @end
1 #import "ViewController.h" 2 #import "BViewController.h" 3 4 @interface ViewController () 5 6 @end 7 8 @implementation ViewController 9 10 - (void)viewDidLoad { 11 [super viewDidLoad]; 12 13 //写了一个按钮,点击跳转到BViewController上 14 UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 80, 50)]; 15 button.layer.backgroundColor = [UIColor greenColor].CGColor; 16 [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; 17 [self.view addSubview:button]; 18 } 19 20 //此处是代码将会调用_mDelegate对象的实现的方法。具体可以看后面的代码。 21 -(void)callMeToDo{ 22 [_mDelegate myPassValue:@"cool"]; 23 [_mDelegate myCallback]; 24 } 25 26 -(void)buttonPressed:(id)sender{ 27 BViewController *bvc = [[BViewController alloc]init]; 28 //ViewController自己实现了这个协议, 29 // 然后bvc就可以引用ViewController的对象,回调ViewContrller中实现的两个方法。 30 bvc.myDelegate = self; 31 [self presentViewController:bvc animated:YES completion:nil]; 32 } 33 34 //ViewContrller使用协议,并强制实现的2个方法 35 -(void)myPassValue:(NSString*)msg{ 36 NSLog(@"%@", msg); 37 } 38 39 -(void)myCallback{ 40 NSLog(@"callback call now.."); 41 } 42 43 - (void)didReceiveMemoryWarning { 44 [super didReceiveMemoryWarning]; 45 // Dispose of any resources that can be recreated. 46 } 47 48 @end
这里是BViewContrller类的代码:
1 #import <UIKit/UIKit.h> 2 #import "ViewController.h" 3 4 @interface BViewController : UIViewController 5 6 //保有一个使用了passValueDelegate协议的对象 7 @property NSObject<passValueDelegate> *myDelegate; 8 9 @end
1 #import "BViewController.h" 2 3 @interface BViewController () 4 5 @end 6 7 @implementation BViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view from its nib. 12 } 13 14 - (IBAction)buttonPressed:(id)sender { 15 //按钮点击,回调ViewController中实现的方法。 16 //(有点和block类似。都是可以向前回调,但是本质不同) 17 //(block是函数的引用,而协议则是对象多态的表现。) 18 [_myDelegate myCallback]; 19 [_myDelegate myPassValue:@"Message from B_View_Controller"]; 20 21 } 22 23 - (void)didReceiveMemoryWarning { 24 [super didReceiveMemoryWarning]; 25 // Dispose of any resources that can be recreated. 26 } 27 28 @end
协议的好处是规范统一接口。如果你使用了某个协议,你一定是按照协议定义的函数接口写代码的。
这里是CViewController使用了ViewController中定义的协议,然后CViewController就要按照协议的规定,
实现协议中的两个方法。CViewController的代码如下:
1 #import <UIKit/UIKit.h> 2 #import "ViewController.h" 3 4 //使用ViewController中的协议passValueDelegate 5 @interface CViewController : UIViewController<passValueDelegate> 6 7 @end
1 #import "CViewController.h" 2 3 @interface CViewController () 4 5 @end 6 7 @implementation CViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view from its nib. 12 } 13 14 -(void)myPassValue:(NSString *)msg{ 15 NSLog(@"C:%@", msg); 16 } 17 18 -(void)myCallback{ 19 NSLog(@"C callback."); 20 } 21 22 - (void)didReceiveMemoryWarning { 23 [super didReceiveMemoryWarning]; 24 // Dispose of any resources that can be recreated. 25 } 26 27 @end
再举一个栗子。其实跟ViewController与BViewController的代码类似。
这时是DViewController实现了passValueDelegate协议。然后让ViewController的mDelegate来保有DViewController对象,
然后ViewController调用方法,就可以在ViewController中回调DViewController中的方法。
(上面的模式是不是跟UITableView的使用过程很类似。在当前的ViewController中把tableview的代理给绑定好,
然后可以在tableview中调用当前ViewController的代理实现方法。跟上面一开始讲的疑问很类似的模型)
代码也是很类似的。如下是DViewController的代码:
1 #import <UIKit/UIKit.h> 2 #import "ViewController.h" 3 4 //使用passValueDelegate协议 5 @interface DViewController : UIViewController<passValueDelegate> 6 7 @end
1 #import "DViewController.h" 2 3 @interface DViewController () 4 5 @end 6 7 @implementation DViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view from its nib. 12 } 13 14 //既然使用了协议,就要实现协议的方法。 15 -(void)myCallback{ 16 NSLog(@"this is D vc"); 17 } 18 19 -(void)myPassValue:(NSString *)msg{ 20 NSLog(@"i am D viewcontroller"); 21 } 22 23 24 - (IBAction)buttonPress:(id)sender { 25 //点击按钮,创建ViewController(可以理解为创建一个UITableView对象) 26 ViewController* vc = [[ViewController alloc]init]; 27 //绑定代理 28 vc.mDelegate = self; 29 //主动回调。(可以理解为tableview中的reload函数,主动reload) 30 [vc callMeToDo]; 31 //总结上面的代码:tableview可以不用主动回调, 32 // 因为tableview是一个控件,控件是一个监听者,他可以根据点击交互来发起对协议函数的回调。 33 //上面是为了举例,所以使用了主动的回调。 34 } 35 36 - (void)didReceiveMemoryWarning { 37 [super didReceiveMemoryWarning]; 38 // Dispose of any resources that can be recreated. 39 } 40 41 @end
上面的代码,已经描述了protocal的使用,以及原理。
总结:
1。具体使用:在统一规范函数接口。所有类都需要用到功能可以使用protocal来规范统一。
比如:人,牛,马都是动物,他们都有几个共同的特点:跑,吃,喝。
这就是动物都拥有的功能,此时就可以使用protocal来规范统一接口。
2。函数回调,代理。类似于block,但是跟block又有很大的差别。请求网络,获取到服务器数据后,回调到初始界面。
此时可以让初始界面实现协议,然后让请求服务器的类保有一个初始界面的协议对象,然后当获取到数据的时候,
服务器可以根据这个协议对象,回调初始界面实现的协议具体方法。
protocal还有2个关键字,required 和 optional关键字。
如果你在定义协议的函数接口时,没有写上这两个关键字的话默认是required。
required意思是以后谁使用了这个协议,就必须要实现这个协议里面的方法,是强制的。
optional意思是可以实现协议里面的方法,也可以不实现协议里面的方法,是可选的。
至于protocal中区分具体的代理,协议。
代理就是把事情交给别人做。我只要保有那个人的电话就行了。
A类中保有一个B的代理对象引用P,B中使用了代理P, 并实现代理的方法是doSomeThing.
A类跟B类的绑定,只需要A.P = B;即可。以后有什么事,比如:
A类某天想要B做什么事,只要这样来[P doSomeThing]。B就会把事做好。
协议就是一种规范,大家必须都要按照协议说的去做。
说白了就是跟Java接口一样的功能,抽象成高层,屏蔽差异性。然后通过持有的对象引用去调用。
很好的表现对象的特性。