Conform to Protocol and Keep Property Private

Viewed 8802

I need to use a protocol property in the conforming class as a private. But the compiler refuses that. How can I implement that?

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
}

Thanks.

3 Answers

As @TheAppMentor mentioned, there seems to be no exact solution to this problem as of Swift 4.

There are, however, two approximate solutions:

1.)

Since a protocol in Swift has the access level of internal by default, make the variable also internal. In order for internal to be enforced by the compiler, move the protocol, the class and all of their consumers (users) to a separate module (framework).

/* 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.)

Give the protocol the access level of private and the variable the access level of fileprivate. In order for the private protocol to be accessible, move the protocol, the class and all of their consumers to the same source file.

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

    func performAnyActionOnX()
}

extension ProtocolX {
    func performAnyActionOnX() {}
}

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

Since protocol's properties always have the same access level as your protocol has you can create a separate class where you can apply fileprivate level to them e.g.:

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
    }
}

As you can see x has fileprivate access level so it can be accessible in ProtocolX extention and A class implementation only so it behaves as private and you can't change privateProps variable of class A and access to x outside:

let a = A()
a.performAnyActionOnX()
// Prints: 5

let x = a.privateProps.x
// error: 'x' is inaccessible due to 'fileprivate' protection level
Related