要限制對代碼塊的訪問,模組和抽象是通過訪問控制完成的。 可以根據訪問控制機制的屬性,方法,初始化程式和下標來訪問類,結構和枚舉。 協議中的常量,變數和函數受到限制,並允許通過訪問控制作為全局和局部訪問。 應用於屬性,類型和功能的訪問控制可稱為“實體”。
訪問控制模型基於模組和原始檔案。
模組被定義為單個代碼分發單元,使用關鍵字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
都有很多選項可用於自定義它們的工作方式。