swift4.1 系统学习二十五 访问控制与作用域

/*
访问控制与作用域

前言:本节内容容易验证,只要访问等级不对,那么编译器就会报错。

什么是访问控制?
就是控制我们在某一swift源文件中在文件作用域所写的函数、类型以及对象,或是类型中属性和方法对其他
源文件的可见性。就是那些文件可以访问这些函数、类型以及对象。

模块:
swift有模块这一概念,模块在swift中其实就是一个framework。我们平时在写代码时候用的import后面的名字
就是模块名,import则表示在当前上下文中导入指定的模块。
*/

// 1. 访问等级
/*
swift提供可五种不同的访问等级:
open > public > internal > fileprivate > private

(1) open:
只能应用于类类型以及类类型的成员。
注意:初始化器和析构器不能使用open修饰,final修饰的属性和方法也不能用open修饰。
被open修饰的类,说明该类在其他模块中能被子类化,也就是该类能够被继承。

注意: 一个类、枚举和结构体类型的初始化器方法最高只能使用public访问等级修饰。类的析构器方法不能
用任何访问等级进行修饰。因为析构器只是对当前类进行销毁释放的,只有当前类的所有属性和方法都被释放了,
当前类的引用等于零的时候,会自动调用该类的析构函数。

(2) public:
可以用于修饰所有文件作用域的函数、对象、协议、枚举、结构体、类以及各种类型中的属性和方法。
用public修饰的对象能被其他模块所使用。但是,其他模块不能继承当前所定义的类类型,也不能对当前
类类型中的属性和方法进行重写。所以public访问等级要比open要低一级,但是它的适用范围比open要广。

(3) internal:
internal访问等级能用于修饰的元素与public一样,只不过用internal所修饰的函数、对象、类型以及
类型中的方法和属性只能在当前模块内部访问,也就是说只能被当前模块中的各个swift源文件访问。
注意:
如果我们定义了一个函数、属性或方法没有使用任何访问控制符,那么默认等级就是internal。

(4) fileprivate:
fileprivate访问等级能用于修饰的元素实体与internal一样,不过fileprivate所修饰的元素实体只能
在当前源文件作用域内可见。

(5) private:
private访问等级一般用于修饰某个类型中的属性和方法,表示该属性或方法仅对当前类型或者该类型的对象可见。

注意:访问等级用于修饰一个元素实体的时候,往往都是写在声明的最前面。

*/

print("\n-------1. 访问等级----------\n")

/// 其他模块可以继承的类
open class OpenClass {
    
    /// 存储属性a,其他模块可以对该属性设置属性观察者。
    open var a = 0
    
    /// 其他模块可以重写该方法
    open func method() {
        print("这是一个open修饰的方法")
    }
    
    /// 一个类的初始化器最高只能使用public进行修饰
    public init() {
        
    }
    
    final func foo() {
        print("这是一个final修饰的foo,子类不能重写")
    }
    
    /// 最高只能使用public修饰,不能使用open
    public final func boo() {
        print("这是一个public final修饰的boo,子类不能重写")
    }
    
    deinit {
        print("OpenClass被释放了")
    }
    
}

/*

  1. 访问等级的指导原则

一个实体的访问等级必须小于等于它所关联的实体中的最小访问等级。
有点儿烧脑,看例子。
*/

/*
(1) 一个public的对象不能用具有internal、fileprivate以及private访问等级的类型来定义。
因为这些类型可能会一起随着该对象出现在它们不应该可见的地方。
*/

internal enum MyEnum {
    case one, two, three
}

/*
 报错:
 Constant cannot be declared public because its type 'MyEnum' uses an internal type
 */
//public let e = MyEnum.one

/*
(2) 一个open访问等级的类不能继承public、 internal、 fileprivate、private访问等级的类。
*/

public class MyClass {
    
}

/*
 报错:
 Superclass 'MyClass' of open class must be open
 */
//open class Child: MyClass {
//
//}

/*
(3) 一个函数的访问等级不能高于其返回类型以及形参类型的访问等级。
*/

internal enum YourEnum {
    
}

fileprivate struct YourStruct {
    
}

/*
 报错:
 Function cannot be declared public because its result uses a fileprivate type
 */
//public func foo(e: YourEnum) -> YourStruct {
//    return YourStruct()
//}

/*
(4) 对于我们自己定义的一个类型,
如果它具有open、public或internal访问等级,那么其成员具有默认的internal访问等级;
如果一个类型被声明为fileprivate,那么其成员默认具有fileprivate访问等级;
如果一个类型被声明为private访问等级,那么其成员默认具有private访问等级。

(5) 对于我们自己定义的类型,我们可以在它内部定义比该类型访问等级更高的成员,可以定义比该类型访问等级更低的成员。
*/

fileprivate struct Test {
    
    public func method() {
        
    }
    
    private func foo() {
        
    }
}

/*

  1. 元组的访问等级

一个元组类型的访问等级是它所有元素中访问等级最低的那个等级。
*/

struct TestStruct {
    
}

private struct PrivateStruct {
    
}

/// 在文件作用域内,fileprivate和private两者等同
fileprivate var tuple: (Int, TestStruct, PrivateStruct)

// 对于元组字面量,它不受各个元素对象的访问等级的影响。

private let s = "Hello"
public let f: Float = 0.5
let i = 100

public let tuplenew = (s, f, i)
print("tuplenew = \(tuplenew)")

/*

  1. 枚举类型的访问等级

一个枚举类型的每个枚举值都会默认具有该枚举类型所拥有的访问等级。
我们不能给某一个枚举值指定一个不同的访问等级。
*/

public enum TrafficLight {
    case red, green, yellow
}

public let e1 = TrafficLight.red

fileprivate enum Light {
    case red, green, blue
}

/// 这里只能用fileprivate来限定e2枚举对象,而不是public或internal
fileprivate let e2 = Light.blue

// 枚举类型的访问等级不能高于其原生值的访问等级
fileprivate struct MyInt {

}

/*
这里的LightNew必须是fileprivate或者是private,因为使用了MyInt是fileprivate的访问等级。
枚举类型的访问等级不得高于其原生类型的访问等级。
*/

fileprivate enum LightNew {
    case red(MyInt)
    case green(Int)
    case blue
}

/*
借着枚举类型,再说说嵌套类型的访问等级。在一个private访问等级中定义的嵌套类型默认具有private访问
等级;在一个filePrivate访问等级中定义的嵌套类型默认具有filePrivate的访问等级。
*/

/// 具有internal访问等级
struct HisStruct {
    
    // 具有private访问等级
    private enum HisEnum {
        
    }
    
    // 具有internal访问等级
    open class HisClass {
        
    }
    
    // 具有internal访问等级
    struct InnerStruct {
        
    }
    
}

/*
5.类继承的访问等级

子类的访问等级不得高于父类。
*/

public class Father {
    
    func method() {
        
    }
    
    func foo() {
        
    }
}

class Child: Father {
    
    /// 重写父类的method方法,并且提升了访问权限
    public override func method() {
        
    }
    
    /// 重写父类的方法,并且提升访问等级
    open override func foo() {
        
    }
}

// 6. 属性getter与setter方法的访问等级
/*
一个属性和下标的getter和setter方法的访问等级默认为该属性或虾兵自身所拥有的访问等级。
*/

struct TestA {
    
    /// 这里定义一个internal访问等级的存储式实例属性,但是写操作的等级是private
    private(set) var a = 10
    
    /// b的访问属性是public但是写操作的访问等级是internal
    public internal(set) var b = 20
    
    fileprivate(set) var p: Int {
        set {
            a = newValue
        }
        get {
            return a
        }
    }
    
    fileprivate private(set) subscript(index: Int) -> Int {
        set {
            b = index
        }
        get {
            return index
        }
    }
}

var t = TestA()
// 这里没有问题
t.b = t.a

/*
 报错:Cannot assign to property: 'a' setter is inaccessible
 */
//t.a = 100

class TestClass {
    
    open public(set) var prop: Int {
        
        set {}
        get {
            return 0
        }
    }
}

/*

  1. 初始化器的访问等级

结构体、枚举以及类的初始化器可以给予小于等于其类型访问等级的访问等级。对于类中的required初始化器,
其访问等级必须与类的访问等级保持一致。不过,当类的访问等级是open的时候,required初始化器的访问
等级则必须是public,因为初始化器的最高等级就是public。
*/

open class TestB {
    
    init(a: Int) {
        
    }
    
    public required init() {
        
    }
}

/*

  1. 协议相关的访问等级

一个协议中所声明的每个属性与方法自动跟协议本身的访问等级保持一致,并且我们不能对其中任一属性或
方法的访问等级进行修改。
*/

public protocol MyPort {
    // 访问等级也是public
    var p: Int { get set }
    // 访问等级也是public
    func method()
}

/*
如果有协议A继承了协议B,那么协议A的访问等级不得高于协议B。
*/

fileprivate protocol HisPort {
    // 这里的访问等级也是fileprivate
    func method()
}

public struct HerStruct: HisPort {
    
    internal func method() {
        
    }
}

/*

  1. 扩展相关的访问等级

我们可以对任一类型在其可见的上下文中对它进行扩展。如果我们扩展的是一个public的类型,那么新扩展的
成员将默认具有 internal访问等级。而对于扩展类型为小于 public访问等级的,那么所扩展的新成员将
默认具有与该类型相同的访问等级。
*/

public struct ThisStruct {
    
}

extension ThisStruct {
    
    /// internal访问等级
    func method() {
        
    }
    
    /// private访问等级
    private func foo() {
        
    }
}

fileprivate extension ThisStruct {
    
    /// fileprivate访问等级
    func method(a: Int) {
        
    }
    
    /// private的访问等级
    private func foo(a: Int) {
        
    }
}

/*
从swift4.0开始,如果一个扩展与它所扩展的类型处于同一个源文件中,那么扩展中能访问该类型的私有成员。
*/

struct StructA {
    
    private var a = 10
    private func method() {
        
    }
}

extension StructA {
    
    static var b = 1
    private func foo() {
        
        print("a = \(self.a)")
    }
}

extension StructA {
    
    private var p: Int {
        return StructA.b + 1
    }
}

/*
注意:
只有当他们处于同一个源文件的时候才会相互访问私有成员,不然是不能访问的。
*/

/*

  1. 类型定义的访问等级

我们所定义的任一类型定义都作为单独的类型,从而可以为他们指定不同的访问等级。
但是,我们要指定一个类型定义的访问等级时,它不能高于定义它的原始类型的访问等级。
*/

// 这里是internal访问等级
class ThatClass {
    
    
}

//这里只能使用低于internal的等级来修饰ThatType
fileprivate typealias ThatType = ThatClass

/*

  1. 作用域

swift 包含了以下几种作用域:
模块作用域,文件作用域,类型作用域以及函数、语句块作用域。
*/

// 我们自定义了一个String结构体,把swift标准库中的String给覆盖掉了。
struct String {
    
}

// 这里是自定义的String类型
let ss = String()

// 这里是swift标准库中的String类型
let str = Swift.String("abc")

do {
    
    // 在文件作用域定义了对象a
    var a = 100
    
    // 在文件作用域定义了函数 foo
    func foo() {
        
    }
    
    // 在文件作用域定了结构体MyType
    struct MyType {
        
    }
    
    struct MyStruct {
        
        // 这里的a属性直接覆盖了文件作用域的a
        static var a = 0
        
        func foo() {
            
            let value = MyStruct.a + MyType.one.rawValue
            print("value = \(value)")
        }
        
        // 覆盖了前面的MyType
        enum MyType: Int {
            case one, two, three
        }
    }
    
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容

  • 访问控制 可以限定其它源文件或模块中的代码对你的代码的访问级别。这个特性可以让我们隐藏代码的一些实现细节,并且可以...
    答案MK阅读 273评论 0 0
  • 访问控制能够限制你的代码从其他文件和模块中访问,这个特性能够让你隐藏你具体的实现,并且也可以让代码能够访问和使用。...
    China_ly阅读 344评论 0 1
  • SPG玻璃放电管是一种靠內部微间隙放电的一种保护器件,在电极微间隙之间充有稳定的隋性气体,并采用玻璃壳和杜镁丝头在...
    超然美好阅读 1,182评论 0 50
  • 还记得在凯文·杜兰特刚加盟的那阵子吗?关于史蒂芬·库里持球和无球的争执?在休斯敦和圣安东尼奥,当史蒂芬·库里增加些...
    ThuleWang阅读 272评论 0 0
  • Anna艳娜 2018年5月22日复盘 想法太多会限制行动,停止会影响前行~其实挺害怕闲下来的,没有压力就没有动力...
    Anna艳娜阅读 126评论 0 0