Reputation: 1203
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.
Upvotes: 12
Views: 11512
Reputation: 13838
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
Upvotes: 0
Reputation: 933
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
}
Upvotes: 6
Reputation: 12021
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.
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
}
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()
Upvotes: -2