符合协议并保持私有财产

时间:2017-05-17 08:58:13

标签: swift architecture protocols private

我需要在一致的类中使用协议属性作为私有。但是编译器拒绝这样做。我该如何实现呢?

protocol ProtocolX: class {
    var x: Int { get set }

    func performAnyActionOnX()
}

extension ProtocolX {
    func performAnyActionOnX() {
        x = 5
        print(x)
    }
}

class A: ProtocolX {
    private var x:Int = 7
}

感谢。

3 个答案:

答案 0 :(得分:0)

由于协议的属性始终与您的协议具有相同的访问级别,因此您可以创建一个单独的类,您可以在其中对它们应用 fileprivate 级别,例如:

public class Props {
    fileprivate var x: Int = 0
}

public protocol ProtocolX: class {
    var privateProps: Props { get }
}

extension ProtocolX {
    public func performAnyActionOnX() {
        privateProps.x = 5
        print(privateProps.x)
    }
}

public class A: ProtocolX {
    public let privateProps = Props()
    
    public init() {
        privateProps.x = 7
    }
}

如您所见,x 具有 fileprivate 访问级别,因此只能在 ProtocolX 扩展和 A 类实现中访问它,因此它的行为与 private 相同,您无法更改 {{ 1}} 类变量 privateProps 和对外部 A 的访问:

x

答案 1 :(得分:-1)

根据@ TheAppMentor评论中所述的原因,您的问题没有确切的解决方案。但是,如果您的目的是使您的代码可以理解为人类(而不是欺骗编译器),那么可能会有一些解决方法。

在Swift 4.0中编译。

解决方案1:类似Python的__privacy

快速而简单。此解决方案依赖于同意从_开始的属性和函数是私有且不应被访问的用户。

protocol ProtocolX: class {
    // Public x
    var x: Int { get }

    // It's private!
    var _x: Int { get set }

    func performAnyActionOnX()
}

extension ProtocolX {
    var x: Int { return _x }

    func performAnyActionOnX(){
        _x = 5
        print(x)
    }
}

class A: ProtocolX {
    var _x: Int = 7
}

解决方案2:附加的abstration层

架构正确。您应该将协议分为两部分:私有和公共。

protocol ProtocolX: class {
    var x: Int { get }

    func performAnyActionOnX()
}

protocol ProtocolXImplementation: class {
    var _x: Int { get set }
}

extension ProtocolXImplementation {    
    var x: Int { return _x }

    func performAnyActionOnX(){
        _x = 5
        print(x)
    }
}

class A: ProtocolX, ProtocolXImplementation {
    var _x: Int = 7
}

// ... somewhere later ...
// Hide the implementation when use `A`:
let item: ProtocolX = A()

答案 2 :(得分:-1)

正如@TheAppMentor所提到的,从Swift 4开始,似乎没有确切的解决方案。

但是,有两种近似的解决方案:

1。)

由于默认情况下,Swift中的协议的访问级别为internal,因此将变量也设为internal。为了使internal由编译器强制执行,请将协议,类及其所有使用者(用户)移动到单独的模块(框架)。

/* internal */ protocol ProtocolX: class {
    var x: Any { get set }

    func performAnyActionOnX()
}

extension ProtocolX {
    func performAnyActionOnX() {}
}

/* internal */ class A: ProtocolX {
    internal var x: Any = 0
}

2。)

为协议提供private的访问级别,为变量提供fileprivate的访问级别。为了使private协议可访问,请将协议,类及其所有使用方移动到同一源文件中。

private protocol ProtocolX: class {
    var x: Any { get set }

    func performAnyActionOnX()
}

extension ProtocolX {
    func performAnyActionOnX() {}
}

class A: ProtocolX {
    fileprivate var x: Any = 0
}