Conform to Protocol and Keep Property Private
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: 5let x = a.privateProps.x// error: 'x' is inaccessible due to 'fileprivate' protection level
There is no the exact solution for your question, by the reason stated in the @TheAppMentor's comment. But there some workarounds which may be helpful if you purpose is to make your code understandable for humans (not to trick the compiler).
Compiles in Swift 4.0.
Solution 1: Python-like __privacy
Fast and simple. This solution relies on the user who would agree that properties and functions starting from _
are private and shouldn't be accessed.
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}
Solution 2: Additional layer of abstration
Architecturally correct. You should split your protocol on the two parts: private and public.
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()