37

I can't use private property in extension. My extension is in another file.

How can I use private property in extension?

pkamb
  • 33,281
  • 23
  • 160
  • 191
Oniikal3
  • 567
  • 1
  • 6
  • 14

3 Answers3

41

Update Starting with Swift 4, extensions can access the private properties of a type declared in the same file. See Access Levels.

If a property is declared private, its access is restricted to the enclosing declaration, and to extensions of that declaration that are in the same file.

If the property is declared fileprivate, it can only be used within the file it is declared (and by anything in that file).

If the property is declared internal (the default), it can only be used within the module it is declared (and by anything in that file).

If the property is declared public or open, it can be used by anything within the module as well as outside of the module by files that import the module it is declared in.

Karoly Nyisztor
  • 3,505
  • 1
  • 26
  • 21
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • 1
    Thanks for your answer, This's really clear for me. but I just need to clean up my code. I just want to make it clearer. so that why I separate extension out of main file. and yes you understand exactly. I don't want any class touch on this property. which one do you prefer between make it to be an internal property (I can separate file) and make it fileprivate (keep them back in to main file) – Oniikal3 Sep 28 '16 at 13:02
  • Different situations call for different use cases. – nhgrif Sep 28 '16 at 13:26
  • My extension using for setting styles in an object. I decided to use fileprivate for now. I'll keep them back to main file. – Oniikal3 Sep 28 '16 at 13:33
7

While @nhgrif is correct about how painful is that protected is missing in Swift, There is a way around.

Wrap your object with protocol, and declare only about the methods and properties that you wish to expose.

For Example

MyUtiltyClass.swift

protocol IMyUtiltyClass {
    func doSomething()
}

class MyUtiltyClass : IMyUtiltyClass {

    static let shared : IMyUtiltyClass = MyUtiltyClass()

    /*private*/
    func doSomethingPrivately() {

    }
}

MyUtiltyClass+DoSomething.swift

extension MyUtiltyClass {
    func doSomething() {
        self.doSomethingPrivately()
        print("doing something")
    }
}

And then you treat the object as the interface type and not the class/struct type directly.

MyViewController.swift

class MyViewController : UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        MyUtiltyClass.shared.doSomething()
        /*
         //⚠️ compiler error
         MyUtiltyClass.shared.doSomethingPrivately()
         */
    }
}

Happy Coding ‍

Benny Davidovitz
  • 1,152
  • 15
  • 18
  • 1
    I find this answer very useful. Specially now that I'm creating an App Clip and quite often I have a shared file (target both app and clip) with a class and an extension of the class for the main app only, for example. Thanks! – Elena Oct 09 '20 at 09:14
  • This trick would not work if you have variables. In this example you can see the compiler gives an error when trying to set the property ```protocol Protocol { var example: Bool { get set } } class Test: Protocol { var example: Bool = true static let shared: Protocol = Test() private init() { } } Test.shared.example Test.shared.example = false // Throws error "Cannot assign to property: 'shared' is a 'let' constant" ``` – Elena Oct 14 '20 at 13:24
  • @Elena. If you intend to use the protocol for reference variables. Then mention it in the protocol definition, as follow `protocol Protocol: AnyObject {` or `protocol Protocol: class {` – Benny Davidovitz Jan 05 '21 at 09:10
  • I just found "Jump to Definition" will go to protocol after refactored my class (1000+ lines). Then, I reverted all the changes. – joshmori Oct 17 '22 at 18:11
2

It's not a good practice to write a private variable in extensions (even if we can). It will introduce unexpected bugs.

If you want to access the variable, you can use private(set) for that variable to make it read only for outside world.

Ex.

private(set) var myPrivateVariable:Int
infiniteLoop
  • 2,135
  • 1
  • 25
  • 29
  • Not sure way this answer was unvoted, it solves the issue. – Joule87 Sep 02 '21 at 13:16
  • 2
    It did not, if the extension is in another file you only have read access, not write access. – Hamza Jadid Mar 17 '22 at 22:58
  • 2
    Ya this is for accessing only, the point is, if we are able to have write access then over the time as code grows it will introduce bugs as any one can write it and 'private' wont make any sense. – infiniteLoop Mar 21 '22 at 11:54
  • 1
    This is not about accessing property from multiple classes (where you indeed should use `private(set)`. This is about asymmetry where extension defined in the same class has access to private vars and the extension in different file cannot. This answer has nothing to do with original question. – timbre timbre Oct 17 '22 at 16:22