关于Swift 4.1之前Array不支持Equatable协议的解决方法

因为App使用了Eureka,我自定义了一个Row,打算使用[Node]作为其Row的Value类型:

final class TreeTVCell: Cell<[Node]>,CellType{

}

大家知道Row的Value类型必须遵守Equatable协议。

我们先来看一下Node类。该类用Objc语言编写,十分简单:

#import "Node.h"

@implementation Node

- (instancetype)initWithParentId : (int)parentId nodeId : (int)nodeId name : (NSString *)name depth : (int)depth expand : (BOOL)expand{
    self = [self init];
    if (self) {
        self.parentId = parentId;
        self.nodeId = nodeId;
        self.name = name;
        self.depth = depth;
        self.expand = expand;
    }
    return self;
}
@end

问题是当我在Xcode 9.3.1里编译App时一切正常,但是放到Xcode 9.2编译时就会出错,提示:

Type ‘[Node]’ does not conform to protocol ‘Equatable’

我们知道前者Swift的版本是4.1,而后者使用的版本是4.0。所以这就是Swift语言版本的问题了。

Swift 4.1从语言层面上做了升级,其中包括条件一致性的提升,包括 Equatable 和 Hashable 协议的自动实现和条件一致性等。

条件一致性即,泛型类型只有在其类型参数满足特定要求的时候才会遵循某个协议。例如,一个 Array 只有当它的元素也遵循 Equatable协议的时候,才能实现Equatable协议。

这就是为什么Swift 4.1从语言层面上说编译可以通过的原因。

那么如何在Swift 4.0上编译通过呢?我们可以采取变通的方法,用一个Wrap类来包装实际的[Node]对象,这得用到Swift语言的版本选择宏来完成:

#if !swift(>=4.1)
struct EquatableArray<Element:Equatable>:Equatable{

    private let _array:[Element]
    var array:[Element]{
        return _array
    }

    init(_ array:[Element]){
        _array = array
    }

    static func ==(lhs: EquatableArray<Element>, rhs: EquatableArray<Element>) -> Bool {
        return lhs._array == rhs._array
    }
}
#endif

然后我们分别以两种情况定义类TreeTVCell:

#if swift(>=4.1)
    final class TreeTVCell: Cell<[Node]>,CellType {
        //...
    }
#else
    final class TreeTVCell: Cell<EquatableArray<Node>>,CellType {
        //...
    }
#endif

最后我们分别在代码流中处理以上两种情况:

#if swift(>=4.1)
    row.value = treeData
#else
    row.value = EquatableArray(treeData)
#endif

通过使用包装器类,我们得以在不同Swift版本中都可以完成使用Eureka代码App的编译,That’s Good!!! :)

相关文章
相关标签/搜索