通常我们在声明一个协议时,代码如下:
@protocol TestProtocol <NSObject>
@optional
- (void)methodA;
- (void)methodB;
- (void)methodC;
@end
对于这种optional的方法,我们在进行调用的时候通常都要判断代理对象是否已经实现该方法,代码如下:
- (void)methodA_CallBack {
if (_delegate && [_delegate respondsToSelector:@selector(methodA)]) {
[_delegate performSelector:@selector(methodA)];
}
}
不过这样会存在一个性能问题,就是每次都要通过消息机制去确认delegate是否已经实现该方法,虽然OC的消息机制中会将方法实现缓存到类对象的方法缓存中,但如果调用的比较频繁的时候,还是会影响性能。
所以我们可以通过位域进行改进。位域是一项比较乏人问津的C语言特性,不过在这里使用刚好合适。我们可以把结构体重的某个字段锁占用的二进制位个数设为特定的值,比如:
struct data {
unsigned int fieldA : 8;
unsigned int fieldB : 1;
unsigned int fieldC : 2;
unsigned int fieldD : 4;
}
在结构体中,fieldA占8个二进制位,fieldB占1个二进制位,fieldA可以表示0-255之间的值,而fieldB可以表示0和1两个值,刚好在这里可以作为一个判断 delegate是否实现了某个方法。
改进的代码如下:
@interface TestClass ()
{
struct {
unsigned int methodAFlag : 1;
unsigned int methodBFlag : 1;
unsigned int methodCFlag : 1;
} _delegateFlags;
}
@end
@implementation TestClass
- (void)setDelegate:(id<TestProtocol>)delegate {
_delegate = delegate;
_delegateFlags.methodAFlag = [_delegate respondsToSelector:@selector(methodA)];
_delegateFlags.methodBFlag = [_delegate respondsToSelector:@selector(methodB)];
_delegateFlags.methodCFlag = [_delegate respondsToSelector:@selector(methodC)];
}
- (void)methodA_CallBack {
if (_delegateFlags.methodAFlag) {
[_delegate performSelector:@selector(methodA)];
}
}
- (void)methodB_CallBack {
if (_delegateFlags.methodBFlag) {
[_delegate performSelector:@selector(methodB)];
}
}
- (void)methodC_CallBack {
if (_delegateFlags.methodCFlag) {
[_delegate performSelector:@selector(methodC)];
}
}
@end
这样的话,方法判断只会在设置代理的时候进行一次,并将值保存在了缓存(位域)中,省去了很多次的方法查询,提高了效率。在一些比较频繁使用协议或者block的地方,都可以使用这种方式进行优化,以提升程序的执行效率。