以forkingdog的PorotocolKit举例
举例
ProtocolKit
Protocol extension for Objective-C
Usage
Your protocol:
@protocol Forkable <NSObject>
@optional
- (void)fork;
@required
- (NSString *)github;
@end
Protocol extension, add default implementation, use @defs magic keyword
@defs(Forkable)
- (void)fork {
NSLog(@"Forkable protocol extension: I'm forking (%@).", self.github);
}
- (NSString *)github {
return @"This is a required method, concrete class must override me.";
}
@end
Your concrete class
@interface Forkingdog : NSObject <Forkable>
@end
@implementation Forkingdog
- (NSString *)github {
return @"https://github.com/forkingdog";
}
@end
Run test
[[Forkingdog new] fork];
Result
[Console] Forkable protocol extension: I'm forking (https://github.com/forkingdog).
实现
我们可以看到关键字是@def 查看其定义是
// For a magic reserved keyword color, use @defs(your_protocol_name)
#define defs _pk_extension
// Interface
#define _pk_extension($protocol) _pk_extension_imp($protocol, _pk_get_container_class($protocol))
// Implementation
#define _pk_extension_imp($protocol, $container_class) \
protocol $protocol; \
@interface $container_class : NSObject <$protocol> @end \
@implementation $container_class \
+ (void)load { \
_pk_extension_load(@protocol($protocol), $container_class.class); \
} \
// Get container class name by counter
#define _pk_get_container_class($protocol) _pk_get_container_class_imp($protocol, __COUNTER__)
#define _pk_get_container_class_imp($protocol, $counter) _pk_get_container_class_imp_concat(__PKContainer_, $protocol, $counter)
#define _pk_get_container_class_imp_concat($a, $b, $c) $a ## $b ## _ ## $c
转化为oc语言定义就是
@protocol Forkable; \ @interface __PKContainer_Forkable_0 : NSObject <Forkable> @end \ @implementation __PKContainer_Forkable_0 \ @synthesize title = _title; + (void)load { \ //add protocol class method? _pk_extension_load(@protocol(Forkable), __PKContainer_Forkable_0.class); } -(NSString *)title { if (!_title) { _title = @"default title!"; } return _title; } - (void)fork { NSLog(@"Forkable protocol extension: I'm forking (%@).", self.github); } - (NSString *)github { return @"This is a required method, concrete class must override me."; } @end
从这可以看出关键的代码 _pk_extension_load()
可以猜想其定义是
1 在load里注册自己包含那些扩展协议
2 在c方法里遍历所有的类 把有扩展的 方法的实现指过去
现在查看其函数实现 关键代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
__attribute__((constructor)) static void _pk_extension_inject_entry(void) { pthread_mutex_lock(&protocolsLoadingLock); unsigned classCount = 0; Class *allClasses = objc_copyClassList(&classCount); @autoreleasepool { for (unsigned protocolIndex = 0; protocolIndex < extendedProtcolCount; ++protocolIndex) { PKExtendedProtocol extendedProtcol = allExtendedProtocols[protocolIndex]; for (unsigned classIndex = 0; classIndex < classCount; ++classIndex) { Class class = allClasses[classIndex]; if (!class_conformsToProtocol(class, extendedProtcol.protocol)) { continue; } _pk_extension_inject_class(class, extendedProtcol); } } } pthread_mutex_unlock(&protocolsLoadingLock); free(allClasses); free(allExtendedProtocols); extendedProtcolCount = 0, extendedProtcolCapacity = 0; }
//将协议的方法添加到到类中(如果不存在就不添加了)//包括类方法和实例方法
static void _pk_extension_inject_class(Class targetClass, PKExtendedProtocol extendedProtocol) {
for (unsigned methodIndex = 0; methodIndex < extendedProtocol.instanceMethodCount; ++methodIndex) {
Method method = extendedProtocol.instanceMethods[methodIndex];
SEL selector = method_getName(method);
if (class_getInstanceMethod(targetClass, selector)) {
continue;
}
IMP imp = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
class_addMethod(targetClass, selector, imp, types);
}
Class targetMetaClass = object_getClass(targetClass);
for (unsigned methodIndex = 0; methodIndex < extendedProtocol.classMethodCount; ++methodIndex) {
Method method = extendedProtocol.classMethods[methodIndex];
SEL selector = method_getName(method);
if (selector == @selector(load) || selector == @selector(initialize)) {
continue;
}
if (class_getInstanceMethod(targetMetaClass, selector)) {
continue;
}
IMP imp = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
class_addMethod(targetMetaClass, selector, imp, types);
}
}
由此可知猜想是正确的,方法告诉我们对于某一个含有该协议的类,如果其含有了协议里面的函数,则跳过,如果没有该函数就添加。
这里是下载地址