OC中Protocol实现默认Extension的方式

2019-12-20  本文已影响0人  seasonZhu

这是一个困扰我很久的一个问题.起初是在一次面试上,和面试官讨论起Swift的特性的时候,我们聊到了Swift的Protocol

Swift的中的Protocol可以写其Extension方法.
如果遵守该Protocol的类或者结构体针对协议方法的不重写的话,那么就会调用Protocol中Extension的默认方法.

上面这段话用代码写非常容易理解

protocol Chef {
    func makeFood()
}

extension Chef {
    func makeFood() {
        print("make food")
    }
}

class A: Chef {
    func makeFood() {
        print("A food")
    }
}

class B: Chef {
    
}

let a = A()
let b = B()

a.makeFood()
b.makeFood()

打印的日志如下

A food
make food

如果我想OC中的Protocol也能够有类似Swift的Protocol中Extension的特性,该如何实现呢?这个就是当时面试官提给我的问题.
这个问题是确实是问到我了,OC的中Protocol可以用@request和@optional在遵循的类中的去做强制实现和可选实现,但是要想要一个类去调用遵守协议的默认实现,这个该怎么办呢?

这个问题困扰了我很久,就在最近一次洗澡的时候,我突然顿悟了.
没办法,洗澡的时候想些莫名其妙的问题,我也很无奈.

我们先来创建一个协议,创建文件ClassNameConvertible.h

@protocol ClassNameConvertible <NSObject>

+ (NSString *)className;

- (NSString *)className;

@end

明眼人一眼就看出来这个协议想干嘛,无非就是获取类名的字符串嘛,我不是经常写OC了,所以总会忽略掉一些OC很重要的细节.


OC中什么可以遵守协议?
对象!
看看定一个OC协议的格式
@protocol 协议名 <NSObject>
已经了然.

也就是说,遵守协议的必然都是对象,而对象的基类是什么?
是NSObject
那么如果NSObject去遵守定义的协议A,并实现协议的默认方法,其他的任何类都会遵守协议A,该一旦调用协议A的方法,其他类如果不重写协议A的方法,那边就会调用NSObject中协议A的默认方法.
如何让NSObject去遵守定义的协议A?
可以创建一个NSObject的分类去遵守协议A
这就是解决了上述的问题.

来上代码创建NSObject+ClassName的分类

.h文件

#import <Foundation/Foundation.h>

#import "ClassNameConvertible.h"

NS_ASSUME_NONNULL_BEGIN

@interface NSObject (ClassName)<ClassNameConvertible>

@end

NS_ASSUME_NONNULL_END

.m文件

#import "NSObject+ClassName.h"

#import <objc/objc.h>
#import <objc/runtime.h>

@implementation NSObject (ClassName)

+ (NSString *)className {
    return NSStringFromClass(self);
}

- (NSString *)className {
    return [NSString stringWithUTF8String:class_getName([self class])];
}

@end

然后我们任意创建了一个SomeView类继承自UIView
.h和.m文件

NS_ASSUME_NONNULL_BEGIN

@interface SomeView : UIView

@end

NS_ASSUME_NONNULL_END
@implementation SomeView

@end

最后我们来一段测试代码

    SomeView *someView = [SomeView new];
    
    // 调用函数
    NSString *instaceName = [someView className];
    NSString *className = [SomeView className];
    
    NSLog(@"instaceName:%@", instaceName);
    NSLog(@"className:%@", className);
    
    // 是否遵循协议
    if ([someView conformsToProtocol:@protocol(ClassNameConvertible)]) {
        NSLog(@"someView 遵守ClassNameConvertible 协议");
    }

打印

instaceName:SomeView
className:SomeView
someView 遵守ClassNameConvertible 协议

有人会说,你对NSObject的分类添加了一个ClassNameConvertible协议,实质上是扩展了整个系统的方法,这样代价也太大了吧.
我又没说一定要在NSObject的分类去遵守协议A,你可以在你定义的专用类的分类中去遵守协议A
这样的话就即实现了Protocol的Extension的默认实现,也将影响力度控制在自己手里.并且你拥有了一个遵守协议的类.
一旦将这个思路扩展下去,其实OC中类泛型的思路也就更加明朗了.

OC_Protocol_Extension

上一篇下一篇

猜你喜欢

热点阅读