最近一直在写 Swift 代码,闲来总结下使用 Swift 的一些经验。在使用第三方 SDK 的时候,我们为了方便使用,会针对某些特殊场景对 SDK 的方法进行 extension,但是随着各种 extension 的增加,就很难和 SDK 原生方法区别起来,造成后期维护成本增加,比如说:
原生方法
sdk.method()
扩展方法
sdk.extensionMethod()
在调用方的代码中,你是无法区别 method() 和 extensionMethod() 这两个方法是来自原生 SDK 的,还是 extension SDK 的。如果该 SDK 是闭源的,你执行 extensionMethod() 方法出现 bug 时,你的第一反应不是去检查是否是自己写的代码有问题,而是去怀疑是否是 SDK 的 bug,所以有必要对其进行统一管理。
实现
这里以极光 IM JMessage SDK 为例,实现一个 ExJMessage 泛型:
public final class ExJMessage<Base> {
public let base: Base
public init(_ base: Base) {
self.base = base
}
}
为了兼容 SDK 的各种类,这里实现了 ExJMessageCompatible 协议,并通过 extension ExJMessageCompatible 生成一个 ex 标识。
/**
A type that has ExJMessage extensions.
*/
public protocol ExJMessageCompatible { }
public extension ExJMessageCompatible {
public static var ex: ExJMessage<Self>.Type {
get { return ExJMessage.self }
}
public var ex: ExJMessage<Self> {
get { return ExJMessage(self) }
}
}
SDK 里面的类实现 ExJMessageCompatible 协议时就可以实现 ex 标识:
extension JMSGConversation: ExJMessageCompatible { }
extension JMSGMessage: ExJMessageCompatible { }
extension JMSGOptionalContent: ExJMessageCompatible { }
然后就可以对相应的类进行 extension:
extension ExJMessage where Base: JMSGOptionalContent {
/**
default optional content
*/
static var `default`: JMSGOptionalContent {
let optionalContent = JMSGOptionalContent()
#if READ_VERSION
optionalContent.needReadReceipt = true
#else
optionalContent.needReadReceipt = false
#endif
return optionalContent
}
}
extension ExJMessage where Base: JMSGConversation {
/**
conversation target type is group
*/
var isGroup: Bool {
return base.conversationType == .group
}
}
使用方法:
// instance mothed or property
conversation.ex.isGroup
// static mothed or property
JMSGOptionalContent.ex.default
这样就可以通过 ex 来调用 extensions 的 mothed 或 property,从而与 SDK 原方法区分开来,并且方便 extensions 的管理。
目录结构大体是这样:

网友评论