Swift访问控制
要限制对代码块的访问,模块和抽象是通过访问控制完成的。 可以根据访问控制机制的属性,方法,初始化程序和下标来访问类,结构和枚举。 协议中的常量,变量和函数受到限制,并允许通过访问控制作为全局和局部访问。 应用于属性,类型和功能的访问控制可称为“实体”。
访问控制模型基于模块和源文件。
模块被定义为单个代码分发单元,使用关键字import
导入。源文件定义为单个源代码文件,在模块中用于访问多种类型和功能。
Swift 4语言提供了三种不同的访问级别。 它们是公共,内部和私有访问。
编号 | 访问级别 | 定义 |
---|---|---|
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()
函数的参数。 在函数本身内部,参数a
和b
的值通过调用函数sum()
来传递,并且将它的值打印。 要使函数的返回类型为private
,请使用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
块,则switch 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()
Setter和Getter
常量,变量,属性和下标的getter
和setter
自动获得与它们所属的常量,变量,属性或下标相同的访问级别。
示例代码
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
初始化器和默认初始化器的访问控制
自定义初始值设定项分配小于或等于它们初始化类型的访问级别。 必需的初始值设定项必须具有与所属类相同的访问级别。 初始化程序的参数类型不能比初始化程序自己的访问级别更私有。
要声明初始化的每个子类需要在init()
函数之前使用required
关键字定义。
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
时,则视为内部。 当用户需要使用另一个模块中的无参数初始化程序初始化public
类型时,请明确提供public
无参数初始化程序作为类型定义的一部分。
协议的访问控制
当定义一个新协议来从协议继承功能时,必须将它们声明为相同的访问级别以继承协议的属性。 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
都有很多选项可用于自定义它们的工作方式。