上一章Swift教程请查看:swift泛型
通过访问控制来限制对代码块、模块和抽象的访问。通过访问控制机制,可以根据类、结构和枚举的属性、方法、初始化器和下标来访问它们。协议中的常量、变量和函数受到限制,允许通过访问控制进行全局和局部访问,用于属性、类型和函数的访问控制可以称为“实体”。
访问控制模型基于模块和源文件。
模块定义为代码分发的单个单元,可以使用关键字“import”导入。源文件被定义为一个包含在模块中的单个源代码文件,用于访问多个类型和函数。
三种不同的访问级别由Swift语言提供,它们是公共的、内部的和私有的访问。
编号 | 访问级别和定义 |
1 |
Public 允许在其定义模块的任何源文件中处理实体,该源文件来自导入定义模块的另一个模块。 |
2 |
Internal 允许实体在其定义模块的任何源文件中使用,但不能在该模块之外的任何源文件中使用。 |
3 |
Private 将实体的使用限制为其自己的定义源文件,私有访问的作用是隐藏特定代码功能的实现细节。 |
语法
public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}
public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}
函数类型的访问控制
有些函数可能在函数内部声明了参数而没有任何返回值,下面的程序将a和b声明为sum()函数的参数。在函数本身内部,通过调用函数call sum()传递参数a和b的值,并打印其值,从而消除返回值。若要使函数的返回类型为私有类型,请使用私有修饰符声明函数的总体访问级别。
private func sum(a: Int, b: Int) {
let a = a + b
let b = a - b
print(a, b)
}
sum(a: 20, b: 10)
sum(a: 40, b: 10)
sum(a: 24, b: 6)
枚举类型的访问控制
public enum Student {
case Name(String)
case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
print("name: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
print("marks: \(Mark1),\(Mark2),\(Mark3).")
}
在Swift语言的枚举自动接收相同的访问级别为个别情况的枚举。例如,考虑访问三个subject中受保护的学生名和标记,枚举名声明为student, enum类中出现的成员名称属于字符串数据类型,标记表示为数据类型为Integer的mark1、mark2和mark3。获取学生姓名或他们的分数。现在,如果执行了case块,switch case将打印学生名,否则它将打印学生保护的标记。如果两个条件都失败,则执行默认块。
子类的访问控制
Swift允许用户子类化任何可以在当前访问上下文中访问的类,子类不能具有高于其超类的访问级别,用户不能编写内部超类的公共子类。
public class cricket {
internal func printIt() {
print("基类")
}
}
internal class tennis: cricket {
override internal func printIt() {
print("子类")
}
}
let cricinstance = cricket()
cricinstance.printIt()
let tennisinstance = tennis()
tennisinstance.printIt()
常量、变量、属性和下标的访问控制
常量、变量或属性不能定义为其类型以外的公共类型。使用私有类型写入公共属性无效。类似地,下标不能比其索引或返回类型更公开。
当常量、变量、性质或下标使用私有类型时,也必须将常量、变量、性质或下标标记为私有
private var privateInstance = SomePrivateClass()
getter和setter
常量、变量、属性和下标的getter和setter自动接收与它们所属的常量、变量、属性或下标相同的访问级别。
class Samplepgm {
var counter: Int = 0{
willSet(newTotal) {
print("Total: \(newTotal)")
}
didSet {
if counter > oldValue {
print("New: \(counter - oldValue)")
}
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
初始化程序和默认初始化程序的访问控制
可以为自定义初始化器分配一个小于或等于其初始化的类型的访问级别,所需的初始化程序必须具有与其所属类相同的访问级别,初始化器参数的类型不能比初始化器自己的访问级别更私有。
要声明initialize
‘required’关键字的每个子类,需要在init()函数之前定义。
class classA {
required init() {
let a = 10
print(a)
}
}
class classB: classA {
required init() {
let b = 30
print(b)
}
}
let res = classA()
let print = classB()
默认初始化程序的访问级别与它初始化的类型相同,除非该类型被定义为public。当default initialize被定义为public时,它被认为是内部的。当用户需要在另一个模块中使用无参数初始化器使公共类型可初始化时,请显式提供一个公共无参数初始化器作为类型定义的一部分。
协议的访问控制
当我们定义一个新协议来继承现有协议的功能时,必须将两者声明为相同的访问级别,以继承彼此的属性,Swift访问控制不允许用户定义继承自“内部”协议的“公共”协议。
public protocol tcpprotocol {
init(no1: Int)
}
public class mainClass {
var no1: Int
init(no1: Int) {
self.no1 = no1
}
}
class subClass: mainClass, tcpprotocol {
var no2: Int
init(no1: Int, no2 : Int) {
self.no2 = no2
super.init(no1:no1)
}
required override convenience init(no1: Int) {
self.init(no1:no1, no2:0)
}
}
let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)
print("res: \(res.no1)")
print("res: \(print.no1)")
print("res: \(print.no2)")
扩展的访问控制
当用户使用扩展来添加协议一致性时,Swift不允许用户为扩展提供显式访问级别修改器,扩展中的每个协议需求实现的默认访问级别都提供了自己的协议访问级别。
对泛型的访问控制
泛型允许用户指定最小访问级别来访问类型参数上的类型约束。
public struct TOS<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
var tos = TOS<String>()
tos.push(item: "Swift")
print(tos.items)
tos.push(item: "泛型")
print(tos.items)
tos.push(item: "参数")
print(tos.items)
tos.push(item: "OOP")
print(tos.items)
let deletetos = tos.pop()
类型别名的访问控制
用户可以定义类型别名来处理不同的访问控制类型。用户可以定义相同的访问级别或不同的访问级别,当类型别名为“private”时,其关联成员可以声明为“private, internal of
public type”。当类型别名为公有时,成员不能别名为“内部”或“私有”名称
出于访问控制的目的,你定义的任何类型别名都被视为不同的类型。类型别名的访问级别可以小于或等于其别名类型的访问级别,例如,私有类型别名可以为私有、内部或公共类型提供别名,但公共类型别名不能为内部或私有类型提供别名。
public protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
mutating func append(item: T) {
self.push(item: item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
var tos = Stack<String>()
tos.push(item: "Swift")
print(tos.items)
tos.push(item: "泛型")
print(tos.items)
tos.push(item: "Where子句")
print(tos.items)
var eos = ["Swift", "泛型", "Where子句"]
print(eos)
Swift编码与解码
Swift引入了一种新的可编码协议,它允许你序列化和反序列化自定义数据类型,而不需要编写任何特殊的代码——也不需要担心丢失你的值类型。
struct Language: Codable {
var name: String
var version: Int
}
let swift = Language(name: "Swift", version: 4)
let java = Language(name: "java", version: 8)
let R = Language(name: "R", version: 3
请注意,语言符合可编程协议。现在,我们将使用一行简单的代码将其转换为Json数据表示。
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(java) {
// 对这个值执行一些操作。
}
Swift将自动对数据类型中的所有值进行编码。
你可以使用解码器功能解码数据
let decoder = JSONDecoder()
if let decoded = try? decoder.decode(Language.self, from: encoded) {
// 对这个值执行一些操作。
}
JSONEncoder和它的属性列表对应的PropertyListEncoder都有很多选项来定制它们的工作方式。