Swift 访问控制
通过访问控制机制,可以限制对代码块、模块和抽象的访问。访问控制可以根据其属性、方法、初始化程序和下标来访问类、结构体和枚举。协议中的常量、变量和函数是受限的,并通过访问控制以全局和局部的形式进行访问。应用于属性、类型和函数的访问控制可以称为“实体”。
访问控制模型基于模块和源文件。
模块被定义为代码分发的单个单位,可以使用关键字“import”导入。源文件被定义为在模块中访问多个类型和函数的单个源代码文件。
Swift 4语言提供了三个不同的访问级别。它们是公共访问、内部访问和私有访问。
序号 | 访问级别和定义 |
---|---|
1 | 公共 使实体可以在定义模块中的任何源文件中进行处理,也可以在导入定义模块的其他模块的源文件中进行处理。 |
2 | 内部 使实体可以在其定义模块的任何源文件中使用,但不能在该模块之外的任何源文件中使用。 |
3 | 私有 将实体的使用限制在其自身的定义源文件中。私有访问在隐藏特定代码功能的实现细节方面发挥作用。 |
语法
public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}
public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}
功能类型的访问控制
有些函数可能在函数内部声明参数,但没有任何返回值。下面的程序将a和b声明为sum()函数的参数。在函数内部,通过调用sum()函数来传递参数a和b的值,并打印这些值,从而消除了返回值。为了将函数的返回类型设置为私有,使用private修饰符声明函数的总体访问级别。
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)
当我们在playground上运行上述程序时,我们会得到以下结果 –
30 20
50 40
30 24
枚举类型的访问控制
public enum Student {
case Name(String)
case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift 4")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
print("Student name is: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
}
当我们在playground上运行上面的程序时,我们会得到以下结果−
Student Marks are: 98,97,95
在Swift 4语言中,枚举的每个情况自动获得相同的访问级别。举个示例,要访问学生的姓名和在三个科目中取得的分数,枚举的名称被声明为student,枚举类中的成员是name(属于字符串数据类型),分数分别表示为mark1、mark2和mark3(属于整数数据类型)。要访问学生的姓名或分数,现在,switch case语句将打印学生的姓名(如果该case块被执行);否则,它将打印学生取得的分数。如果两个条件都不满足,则执行默认的代码块。
子类的访问控制
Swift 4允许用户对任何可以在当前访问上下文中访问的类进行子类化。子类的访问级别不能高于其父类的访问级别。用户被限制为不能编写一个对内部超类进行公开子类化的公共子类。
public class cricket {
internal func printIt() {
print("Welcome to Swift 4 Super Class")
}
}
internal class tennis: cricket {
override internal func printIt() {
print("Welcome to Swift 4 Sub Class")
}
}
let cricinstance = cricket()
cricinstance.printIt()
let tennisinstance = tennis()
tennisinstance.printIt()
当我们使用playground运行上面的程序时,我们得到以下结果−。
Welcome to Swift Super Class
Welcome to Swift Sub Class
常量、变量、属性和下标的访问控制
在Swift 4中,常量、变量或属性不能被定义为其类型所能达到的公开级别。不允许用私有类型来定义一个公开的属性。同样地,下标的访问级别不能高于其索引或返回类型。
当一个常量、变量、属性或下标使用了私有类型时,该常量、变量、属性或下标也必须标记为私有。
private var privateInstance = SomePrivateClass()
取值器和设置器
常量、变量、属性和下标的取值器和设置器将自动继承与它们所属的常量、变量、属性或下标相同的访问级别。
class Samplepgm {
var counter: Int = 0{
willSet(newTotal) {
print("Total Counter is: \(newTotal)")
}
didSet {
if counter > oldValue {
print("Newly Added Counter \(counter - oldValue)")
}
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
当我们使用playground运行上面的程序时,我们得到以下结果 –
Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700
访问控制的初始化和默认初始化
自定义的初始化器可以被分配一个小于或等于它们初始化的类型的访问级别。必须与所属类相同的访问级别要求初始化器。初始化器参数的类型不能比初始化器本身的访问级别更私密。
要声明每个子类的初始化器为 ‘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()
当我们使用playground运行上面的程序时,我们得到以下结果 –
10
30
10
默认初始化器的访问级别与其初始化的类型相同,除非该类型被定义为public。当公共初始化器被定义为public时,它被视为internal。当用户需要在另一个模块中使用无参数初始化器初始化公共类型时,需要在类型的定义中明确提供一个公共无参数初始化器。
访问控制协议
当我们定义一个新的协议来继承现有协议的功能时,两者必须声明相同的访问级别以继承彼此的属性。Swift 4的访问控制不允许用户定义一个从internal协议继承的public协议。
public protocol tcpprotocol {
init(no1: Int)
}
public class mainClass {
var no1: Int // local storage
init(no1: Int) {
self.no1 = no1 // initialization
}
}
class subClass: mainClass, tcpprotocol {
var no2: Int
init(no1: Int, no2 : Int) {
self.no2 = no2
super.init(no1:no1)
}
// Requires only one parameter for convenient method
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 is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")
当我们使用playground运行上面的程序时,我们得到以下的结果-
res is: 20
res is: 30
res is: 50
访问控制的扩展
Swift 4 不允许用户在使用扩展来添加协议遵循时为扩展 提供显式访问级别修饰符。在扩展内的每个协议要求实现都提供自己的协议访问级别。
访问控制的泛型
泛型允许用户指定访问类型参数上的最小访问级别约束。
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 4")
print(tos.items)
tos.push(item: "Generics")
print(tos.items)
tos.push(item: "Type Parameters")
print(tos.items)
tos.push(item: "Naming Type Parameters")
print(tos.items)
let deletetos = tos.pop()
当我们在playground上运行上述程序时,我们会得到以下结果 –
[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]
类型别名的访问控制
用户可以定义类型别名来处理不同的访问控制类型。用户可以定义相同访问级别或不同访问级别。当类型别名是’private’时,其关联成员可以声明为’private、internal或public’类型。当类型别名是public时,成员不能别名为’internal’或’private’名称。
任何你定义的类型别名都被视为访问控制目的的不同类型。类型别名的访问级别可以小于或等于它所别名的类型的访问级别。例如,私有的类型别名可以别名为私有、内部或公有类型,但公有的类型别名不能别名为内部或私有类型。
public protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
// original Stack<T> implementation
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
// conformance to the Container protocol
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 {
// check that both containers contain the same number of items
if someContainer.count != anotherContainer.count {
return false
}
// check each pair of items to see if they are equivalent
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// all items match, so return true
return true
}
var tos = Stack<String>()
tos.push(item: "Swift 4")
print(tos.items)
tos.push(item: "Generics")
print(tos.items)
tos.push(item: "Where Clause")
print(tos.items)
var eos = ["Swift 4", "Generics", "Where Clause"]
print(eos)
当我们在playground中运行上面的程序时,我们得到以下结果 –
[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]
Swift的编码和解码
Swift 4引入了一个新的 Codable 协议,它使您能够将自定义数据类型序列化和反序列化,而无需编写任何特殊代码-也不必担心丢失值。
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
注意到Language符合Codable协议。现在我们将使用一行简单的代码将其转换为Json数据表示形式。
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(java) {
//Perform some operations on this value.
}
Swift将自动编码数据类型中的所有值。
您可以使用解码器功能解码数据。
let decoder = JSONDecoder()
if let decoded = try? decoder.decode(Language.self, from: encoded) {
//Perform some operations on this value.
}
JSONEncoder和它的属性列表对应的PropertyListEncoder都有很多选项可以定制它们的工作方式。