从Swift中的Protocol特性聊到的面试题
有一次面试上,和面试官讨论起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的灵魂拷问
这个问题是确实是问到我了,OC的中Protocol可以用@request和@optional在遵循的类中的去做强制实现和可选实现,但是要想要一个类去调用遵守协议的默认实现,这个该怎么办呢?
想了很久,在偶然的一次编码中,发现了。
我们先来创建一个协议,创建文件ClassNameConvertible.h
@protocol ClassNameConvertible <NSObject>
+ (NSString *)className;
- (NSString *)className;
@end
明眼人一眼就看出来这个协议想干嘛,无非就是获取类名的字符串嘛,我不是经常写OC了,所以总会忽略掉一些OC很重要的细节。
问:OC中什么类型可以遵守协议?
答:对象!
看看定义一个OC协议的格式
@protocol 协议名 <NSObject>
一些方法......
@end
创建的时候已经了然。
也就是说,遵守协议的类型必然都是对象,而对象的基类是什么?
是NSObject!
如果NSObject去遵守定义的协议A,并实现协议的默认方法,其他的任何类都会遵守协议A,一旦调用协议A的方法,其他类如果不重写协议A的方法,那么就会调用NSObject中协议A的默认方法。
如何让NSObject去遵守定义的协议A?
可以创建一个NSObject的分类去遵守协议A!
这就是解决了上述的问题。
OC中Protocol中实现默认Extension的方式
来,代码创建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"
@implementation NSObject (ClassName)
+ (NSString *)className {
return NSStringFromClass(self);
}
- (NSString *)className {
return [[self class] className];
}
@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中类泛型的思路也就更加明朗了。
嗯,这也许是一个伪命题。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看活动详情