在ios中,协议的使用非常广泛,它定义了一系列的方法,这些方法可以是必须实现的也可以是可选性的。这个特性非常有利于我们将API中的细节隐藏起来,从而通过返回对象的方法设计出遵守协议的纯id类型。
一般,我们在定义“受委托者(delegate)”属性的时候,是这样写的:
@property(nonatomic,assign) id<ECProjectDelegate> delegate;
由于这个属性的类型是id<ECProjectDelegate>,所以实际上是任何类型的对象都能充当这个属性,及时这个类不继承NSObject也行,但必须遵循ECProjectDelegate协议。
使用广泛的NSDictionary就很好的说明了这个概念。在字典中,key的标准内存管理语义是“设置时copy”,而Value的语义则是“设置时保留”。因此在可变版本的字典中,设置Key—Value键值对所用的方法是:
-(void)setObject:(id)object forKey:(id<NSCopying>)key;
表示Key的那个参数其类型为id<NSCopying>,作为参数值的对象,它可以是任何的NSCopying协议就行了,这样的话,就可以向这个对象发送拷贝消息了。
这个key参数可以视作匿名对象,这个与delegate属性一样,字典也不关心key对象到底是什么类型。
举个栗子!!
在处理数据库的连接过程中,以匿名对象表示从另外一个库返回的对象。对于处理连接的那个类,由于想隐藏方法的名字,因为不同的数据库可能要用不同的类处理。如果没办法让这些方法都继承自同一个基类,那么就得返回id类型的方法了。但是我们还是可以吧所有的数据库连接都具备的那些方法放到协议中。使返回的对象遵从这个协议,协议可以这么写:
假设协议中的内容:
@protocol ECProjectConnection
-(void) connect;
-(void) disconnect;
-(BOOL) isConnected;
-(NSArray *) performQuery:(NSString *)query;
@end
然后可以用数据库处理器单例来提供数据库连接,这个单例的接口可以写成:
#import <Foundation/Foundation.h>
@protocol ECProjectConnection;
@interface ECDataBaseManager:NSObject
+(id)sharedInstance;
-(id<ECProjectConnection>)connectionWithIdentifier:(NSString *)identifier;
@end
如此一来,你处理数据库所用连接的类的名字就不会泄漏了,那些来自不同框架的类现在都可以通过这个方法来返回了,使用此API的开发者仅需要所返回的对象,能用来连接、断开、查询数据库就可以了。
在很多时候,我们写代码的时候为了快速开发,通常会使用别的很多第三方库来实现我们的功能,这时候,我们就可以创建匿名对象把这些类简单封装一下。使匿名对象成为其子类,并遵循拟定的协议,然后就可以同过类似于“connectionWithIdentifier:”方法来返回这些类的对象。
说了那么一大堆有什么用呢?
- 协议可以在某种程度上提供匿名类型,具体可以通过淡化了的对象类型:id类型,来实现。协议中定制好对象所应实现的方法即可!
- 使用匿名对象来隐藏类型名称。
- 如果具体类型不重要,重要的是对象能够响应特定方法,那么也可以使用匿名对象来表示。
此等高级技能来自《Objective-C 实用装逼52招》!