Swift:具有私有成员的抽象基类/协议

时间:2017-05-10 08:40:48

标签: swift access-control

我根据this answer使用协议扩展在Swift中创建了一个类似抽象的基类类结构。这是一个简化的例子:

protocol AbstractBase {
    var _constant: Int { get }
    func _operation(_ val: Int) -> Int
}

public class ConcreteSub: AbstractBase {
    let _constant: Int = 42
    func _operation(_ val: Int) -> Int {
        return val + 2
    }
}

extension AbstractBase {
    func mainOperation(_ val: Int) -> Int {
        return _operation(val + _constant)
    }
}

基本上,ConcreteSub提供了AbstractBase所需的实施细节,即_constant_operation

我想隐藏客户端的详细信息,只展示mainOperation。但是,Swift不允许我让成员fileprivate在协议上 - 如果我做以下

protocol AbstractBase {
    fileprivate var _constant: Int { get }
    // etc

我得到“错误:'fileprivate'修饰符不能用于协议”。

我也不能在子类上应用修饰符 - 当我尝试

public class ConcreteSub: AbstractBase {
    fileprivate let _constant: Int = 42
    // etc

我得到“错误:属性'_constant'必须在内部声明,因为它符合内部协议'AbstractBase'中的要求。”

最后,当我制作整个协议文件时,我没有编译错误,但我一直遇到链接错误,我想这是因为协议是私有的,但是子类是公共的。

我还有另一种方法吗?

2 个答案:

答案 0 :(得分:1)

当我需要一个隐藏了一些属性/函数的抽象基础时,只要有人试图使用Base而不是实现,我就会使用带有一些额外fatalErrorsasserts的类崩溃。

public class AbstractBase {
    init() {
        assert(type(of: self) != AbstractBase.self, "Abstract class")
    }

    fileprivate var _constant: Int {
        fatalError("Abstract class")
    }
    fileprivate func _operation(_ val: Int) -> Int {
        fatalError("Abstract class")
    }

    func mainOperation(_ val: Int) -> Int {
        return _operation(val + _constant)
    }
}

public class ConcreteSub: AbstractBase {

    fileprivate override var _constant: Int {
        return 42
    }
    fileprivate override func _operation(_ val: Int) -> Int {
        return val + 2
    }
}

答案 1 :(得分:0)

我实际上刚刚遇到了这个问题。从 Swift 5.1 开始,您可以改为这样做:

protocol MyProtocol {
    var someVisibleVar: String { get }
    func someVisibleFunc()
}

fileprivate extension MyProtocol {
    var someFilePrivateVar: String {
        "whatever"
    }

    func someFilePrivateFunc() {
        print("someFilePrivateFunc() was called with \(someVisibleVar)")
    }
}

class SomeClass: MyProtocol {
    var someVisibleVar: String { "whatever" }

    func someVisibleFunc() {
        if someFilePrivateVar == someVisibleVar {
            someFilePrivateFunc()
        }
    }
}

class SomeOtherClass: MyProtocol {
    var someVisibleVar: String { "something else" }

    func someVisibleFunc() {
        if someFilePrivateVar == someVisibleVar {
            someFilePrivateFunc()
        }
    }
}