52

I'm trying to declare an instance property in Swift so that it is only visible to its class and subclasses. I believe this would be referred to as a protected property in other languages. Is there a way to achieve this in Swift?

HangarRash
  • 7,314
  • 5
  • 5
  • 32
nwales
  • 3,521
  • 2
  • 25
  • 47
  • I would do it with a protocol. Specify which variables you want subclasses to have access to in the protocol. The subclasses then adopt the protocol. – Victor Engel Jun 19 '23 at 13:40

3 Answers3

53

Access control along inheritance lines doesn't really fit with the design philosophies behind Swift and Cocoa:

When designing access control levels in Swift, we considered two main use cases:

  • keep private details of a class hidden from the rest of the app
  • keep internal details of a framework hidden from the client app

These correspond to private and internal levels of access, respectively.

In contrast, protected conflates access with inheritance, adding an entirely new control axis to reason about. It doesn’t actually offer any real protection, since a subclass can always expose “protected” API through a new public method or property. It doesn’t offer additional optimization opportunities either, since new overrides can come from anywhere. And it’s unnecessarily restrictive — it allows subclasses, but not any of the subclass’s helpers, to access something.

There's further explanation on Apple's Swift blog.

Community
  • 1
  • 1
rickster
  • 124,678
  • 26
  • 272
  • 326
  • That's an interesting proposal, and there may be merit in it. (Personally, I'm not sure. It'd help to see a more concrete use case.) Regardless, it seems to be reusing the name `protected` for a different purpose than the one you're asking about (and also different from what that name means in other languages). – rickster Jan 15 '15 at 20:19
  • 80
    I think protected as it exists on other programming languages should exist on Swift. Basically if you want to share some private definition to your descendants you can't. That's annoying. – Gaston Sanchez Jan 30 '15 at 20:47
  • 9
    @GastónSánchez: If you have an opinion on how Swift should evolve, it's probably more productive to [tell Apple](http://bugreport.apple.com) than tell some random guy on SO. :) But note the bits in the blog post I quoted about `protected` not being very protective, and helper classes... Cocoa is both more dynamic than the libraries used with other languages and tends to favor different design patterns, too (like composition over inheritance), so solutions that work well for other toolkits might not belong in a language designed for Cocoa. – rickster Jan 30 '15 at 21:10
  • 2
    Well it was not my intention to sound like an angry creep. That said, I don't agree with Apple reasons but to be fair I'm not that experienced with Cocoa API so I will save that decision to the masters. – Gaston Sanchez Jan 30 '15 at 21:37
  • 5
    Wow. This seems really limiting. I just added this to my personal list of Swift "Gotcha's". – Chris Prince Oct 22 '15 at 21:33
  • 2
    There's another case: `fileprivate` - hiding details at file scope. While it likewise maintains the access/inheritance distinction, it's another useful level of scope to consider when reviewing your options. – wardw Jan 21 '18 at 15:38
20

One way to do it is define the function or property with fileprivate keyword and define the subclass in the same file like so:

class Parent {
    fileprivate var someProperty: Any?
}

class Child: Parent {
    func someFunction() {
        print(someProperty)
    }
}

Of course this is super annoying, since that file will be a huge mess. Not to mention why Swift allows this but not protected is just... argh.

funct7
  • 3,407
  • 2
  • 27
  • 33
0

I use a protocol to expose some functions to only other class. ..

protocol ViewModel {
    func open()
}

class Parent {
    func innerAction() {}
}
extension Parent: ViewModel {
    func open() {}
}

class Child: Parent {
    // it can access all functions of Parent
}

class SomeOther {
    var viewModel: ViewModel = Child()
    // it can't access all functions of Parent
}
Brownsoo Han
  • 4,549
  • 3
  • 20
  • 20