一、前言
相信有一些初学Swift的开发者,对private和fileprivate这两个访问控制关键字的使用会有些迷糊,So,今天咱们就来捋一捋。
Swift 中由低至高提供了 private,fileprivate,internal,public 和 open 五种访问控制的权限。默认的 internal 在绝大部分时候是适用的,另外由于它是 Swift 中的默认的控制级,因此它也是最为方便的。
对于一个严格的项目来说,精确的最小化访问控制级别对于代码的维护来说还是相当重要的。我们想让同一 module (或者说是 target) 中的其他代码访问的话,保持默认的 internal 就可以了。如果我们在为其他开发者开发库的话,可能会希望用一些 public 甚至 open,因为在 target 外只能调用到 public 和 open 的代码。public 和 open 的区别在于,只有被 open 标记的内容才能在别的框架中被继承或者重写。因此,如果你只希望框架的用户使用某个类型和方法,而不希望他们继承或者重写的话,应该将其限定为 public 而非 open。
二、进入主题: private和fileprivate的区别
Swift3及之前的区别可以看这里 本篇文章只介绍Swift4
1. private 和 fileprivate 修饰属性
//ViewController.swift
class Person: NSObject {
fileprivate var name:String = "man"
private var age:Int = 1
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let p = Person()
print(p.name)
//编译器不会提示age属性 如果强行写p.age
//会报错'age' is inaccessible due to 'private' protection level
//print(p.age)
}
}
log: man
在swift4.0中 fileprivate修饰的属性,能在当前文件内访问到,不管是否在本类的作用域;
private 只能在本类的作用域且在当前文件内能访问
//ViewController.swift
extension Person {
func printAge() {
print(self.age)
//在 当前文件的 extension 中,调用private 修饰的属性没问题
}
func prinName() {
//在 当前文件的 extension 中,调用fileprivate 修饰的属性没问题
print(self.name)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let p = Person()
p.printAge()
p.prinName()
}
在extension中需要用到类的属性时,只要保证实在同一个文件内,无论是用private或fileprivate修饰,都是可以被正常访问的。
2、private 和 fileprivate 修饰方法时
//ViewController.swift
class Person: NSObject {
fileprivate var name:String = "man"
private var age:Int = 1
fileprivate func printNameAndAge(){
print("name:\(name) age:\(age)")
}
private func setNameAndAge(name:String,age:Int){
//xxx
}
}
override func viewDidLoad() {
super.viewDidLoad()
let p = Person()
p.printNameAndAge()
//用private修饰的方法不能够被调用到
//'setNameAndAge' is inaccessible due to 'private' protection level
// p.setNameAndAge("superMan",100)
}
3.子类是否能使用到private和fileprivate修饰的代码
3.1在当前文件内新加一个Peson的子类
//ViewController.swift 跟父类Person在同一个文件内
class Student: Person {
//依然可访问到父类中 fileprivate 修饰的方法或属性
func test() {
print("来自Student: \(name) ")
//print("来自Student: \(age) ") //此时age也是不可访问的
printNameAndAge() //fileprivate 可正常调用
//setNameAndAge("daming",13) //private无法调用
}
}
3.2在不同文件内新加一个Peson的子类
//Teacher.swift
class Teacher: Person {
func testPrint() {
//可以访问extension 中的方法,没加修饰默认为 internal
prinName();
printAge();
//此时 private和fileprivate 修饰的属性或方法都无法访问到
//printNameAndAge()
//setNameAndAge(name: "SuperMan", age: 100)
// let a = self.age
//let b = self.name
}
//但不可以被重写
//Declarations from extensions cannot be overridden yet
// override func prinName() {
// print("子类重写 prinName")
// }
// override func printAge() {
// print("子类重写 printAge")
// }
}
在Swift4中,如果子类跟父类不再同一个文件下是不能够使用fileprivate修饰的方法或属性的;且private修饰的方法和属性无论是否跟父类在同一个文件文件内,都无法使用。
三、总结
private 表示代码只能在当前作用域或者同一文件中同一类型的作用域中被使用,
fileprivate 表示代码可以在当前文件中被访问,而不做类型限定。
再过几天就是元旦了,祝大家元旦快乐啦~觉得写得还可以,就点个赞吧