[Swift 3.0] アクセス修飾子にopenとfileprivateが追加された話

2016.09.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Swift3.0からopenfileprivateという新たなアクセス修飾子(Access Control)が追加されました。
Swift Evolutionでいうところの下記の内容です。
0025-scoped-access-level
0117-non-public-subclassable-by-default

access control for swift3

open モジュール外からもアクセスできる。 一番ゆるいアクセスコントロール。 新規追加✨
public モジュール外からもアクセスできる。 サブクラス化されない。 overrideできない。
internal モジュール内ならアクセスできる。 何も書かないとコレになる。(デフォルト)
fileprivate 文字通りファイル内ならアクセスできる。 新規追加✨
private クラスなど宣言内でしかアクセスできない。

open

今回新しく追加された修飾子です。
以前、Public は他のモジュールがインスタンス化したクラスを使用することができ、サブクラスを定義することができました。また、メンバー(method, property, subscript) をOverrideすることができました。

Swift3.0 から新しくopenが追加され、これらの概念が区別されました。
open、publicともに他のモジュールからの使用は可能ですが、publicの方はサブクラス化されません。

以前   Swift3   
overrideできない
サブクラス化されない
final public → public
overrideできる
サブクラス化される
public → open

また、現時点でのSwift3の仕様では、openを利用するには、スーパークラスもopenでないといけません。

SuperClassOpen

モジュール(module)とは?

ライブラリなどimportを使って取り込むまとまりです。
UIKit、MapKit、CoreData、CoreImageなどが該当します。

Swift2.x(今までの例)

UIViewController

public class UIViewController : UIResponder, NSCoding, UIAppearanceContainer, UITraitEnvironment, UIContentContainer, UIFocusEnvironment {
    // 一部抜粋
    public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)
    public init?(coder aDecoder: NSCoder)
    public var view: UIView!
    public func loadView()
    public func viewDidLoad()
    ・
    ・
    ・

Swift3.0

UIViewController

open class UIViewController : UIResponder, NSCoding, UIAppearanceContainer, UITraitEnvironment, UIContentContainer, UIFocusEnvironment {
    // 一部抜粋
    public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
    public init?(coder aDecoder: NSCoder)
    open var view: UIView!
    open func loadView()
    open func viewDidLoad() 
    ・
    ・
    ・

fileprivate

同じファイル内であればアクセスできるようにしたのがfileprivateです。

fileprivate

Swift2.x(今までの例)

Animal.swift

class Cat {
  private let name = "cat"
}
class Dog {
  func callCat() {
     let cat = Cat()
     print(cat.name)
  }
}

Swift3.0

Animal.swift

class Cat {
  fileprivate let name = "cat"
}
class Dog {
  func callCat() {
     let cat = Cat()
     print(cat.name)
  }
}

Swift2.xまでは同じファイル内であればprivateでもアクセス出来ていたようですが、Swift3.0からは明示的にfileprivateとしなければアクセス出来ないようになりました。

さいごに

今回増えたことによって、アクセスレベルがより明確化されました
ライブラリを作っている人とprivateで同じファイル内で参照していた人以外は特に大きな影響は無さそうに思います。

参考

#22 Swift 3 Access Control (Xcode 8 Beta 6)

[iOS 8][Swift] アクセス修飾子を理解する