English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Контроль доступа может ограничивать уровень доступа кода из других файлов или модулей к вашему коду.
Вы можете явно установить уровень доступа для отдельных типов (классы, структуры, энум) и для их свойств, функций, методов инициализации, базовых типов, индексов и т.д.
Протоколы также могут быть ограничены в использовании в определенном диапазоне, включая глобальные константы, переменные и функции в протоколе.
Контроль доступа основан на модуле и файле исходного кода.
Модуль - это независимый компонент, который можно构建 и 发布 в виде Framework или Application. В Swift модуль можно использовать с помощью ключевого слова import для включения другого модуля.
Файл исходного кода - это единичный файл исходного кода, который обычно принадлежит модулю. Файл исходного кода может содержать несколько определений классов и функций.
Swift предоставляет четыре различных уровня доступа для сущностей в коде: public, internal, fileprivate, private.
Уровень доступа | Определение |
---|---|
public | Может доступ к любым实体 в файлах своего модуля, и другие могут получить доступ к всем实体 в файлах через импорт этого модуля. |
internal | Может доступ к любым实体 в файлах своего модуля, но другие не могут получить доступ к实体 в файлах другого модуля. |
fileprivate | Частный в файле, может использоваться только в текущем исходном файле. |
private | Доступен только в классе, за пределами области действия класса или структуры его использовать нельзя. |
public - наивысший уровень доступа, private - наименьший уровень доступа.
Уровень доступа сущности объявляется с помощью модификаторов public, internal, fileprivate, private:
public class SomePublicClass {} internal class SomeInternalClass {} fileprivate class SomeFilePrivateClass {} private class SomePrivateClass {} public var somePublicVariable = 0 internal let someInternalConstant = 0 fileprivate func someFilePrivateFunction() {} private func somePrivateFunction() {}
Если не указано иное, все сущности используют по умолчанию уровень доступа internal.
class (\._SomeInternalClass) {} // уровень доступа internal let (\._someInternalConstant) = 0 // уровень доступа internal
Уровень доступа функции необходимо определять на основе типа параметров и уровня доступа возвращаемого значения.
В следующем примере определена глобальная функция (\._someFunction), и ее уровень доступа не явно объявлен.
func (\._someFunction() -> (SomeInternalClass, SomePrivateClass)) { // Реализация функции }
Уровень доступа одного из классов в функции (\._someFunction() -> (SomeInternalClass, SomePrivateClass)) SomeInternalClass internal, а другой SomePrivateClass private. Таким образом, в соответствии с принципами уровня доступа группы, уровень доступа группы private (уровень доступа группы совпадает с наименьшим уровнем доступа типа в группе).
Поскольку уровень доступа возвращаемого типа функции private, вам необходимо использовать модификатор private, чтобы явно声明 функцию:
private func (\._someFunction() -> (SomeInternalClass, SomePrivateClass)) { // Реализация функции }
Некорректно объявлять функцию в качестве public или internal, или использовать по умолчанию internal, потому что в этом случае вы не сможете получить доступ к возвращаемому значению уровня доступа private.
Уровень доступа членов枚ерации наследуется от этой энумерации, вы не можете объявить разные уровни доступа для членов энумерации в отдельности.
Например, в следующем примере,枚举 (\._Student) явно объявлена на уровне public, поэтому уровень доступа его членов Name, Mark также public:
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("Имя студента: \(studName).") case .Mark(let Mark1, let Mark2, let Mark3): print("Оценки студентов: \(Mark1), \(Mark2), \(Mark3)") }
Результат выполнения программы приведен выше:
Оценки студентов: 98, 97, 95
Уровень доступа подкласса не может быть выше уровня доступа родительского класса. Например, если уровень доступа родительского класса internal, то уровень доступа подкласса не может быть объявлен как public.
public class SuperClass { fileprivate func show() { print("Надкласс") } } // Уровень доступа не может быть выше уровня доступа надкласса internal > public internal class SubClass: SuperClass { override internal func show() { print("Подкласс") } } let sup = SuperClass() sup.show() let sub = SubClass() sub.show()
Результат выполнения программы приведен выше:
Надкласс Подкласс
Константы, переменные и свойства не могут иметь уровень доступа выше уровня их типа.
Например, вы определяете свойство уровня доступа public, но его тип private, это запрещено компилятором.
Таким же образом, индекс не может иметь уровень доступа выше уровня типа индекса или типа возвращаемого значения.
Если тип константы, переменной, свойства или индекса определен на уровне private, то они должны явно объявляться с уровнем доступа private:
private var privateInstance = SomePrivateClass()
Уровень доступа getters и setters констант, переменных, свойств и индексов наследуется от уровня доступа их 所属 член.
Уровень доступа setter может быть ниже уровня доступа getter, что позволяет контролировать права чтения и записи переменных, свойств или индексов.
class Samplepgm { fileprivate var counter: Int = 0{ willSet(newTotal){ print("Счетчик: \(newTotal)") } didSet{ if counter > oldValue { print("Новая количество \(counter - oldValue)") } } } } let NewCounter = Samplepgm() NewCounter.counter = 100 NewCounter.counter = 800
Уровень доступа переменной counter составляет fileprivate, и к ней можно получить доступ в файле.
Результат выполнения программы приведен выше:
Счетчик: 100 Добавлено количество 100 Счетчик: 800 Добавлено количество 700
Мы можем определить уровень доступа для пользовательских методов инициализации, но он не может быть выше уровня доступа класса, к которому они относятся. Но это не относится к необходимым конструкторам, уровень доступа которых должен быть таким же, как и уровень доступа класса.
Как и параметры функции или метода, уровень доступа параметров метода инициализации не может быть ниже уровня доступа метода инициализации.
Swift предоставляет структурам и классам по умолчанию пустой метод инициализации без параметров, который предоставляет возможность присваивания значений всем свойствам, но не устанавливает конкретные значения.
Уровень доступа по умолчанию для метода инициализации соответствует уровню доступа типа.
Используйте ключевое слово required перед методом init() каждого подкласса для объявления уровня доступа.
class classA { required init() { var a = 10 print(a) } } class classB: classA { required init() { var b = 30 print(b) } } let res = classA() let show = classB()
Результат выполнения программы приведен выше:
10 30 10
Если вы хотите明确规定 уровня доступа для протокола, то обратите внимание, что вам нужно убедиться, что протокол используется только в области доступа, которая была определена.
Если вы определили протокол с уровнем доступа public, то необходимые функции для реализации этого протокола также будут иметь уровень доступа public. Это отличается от других типов, например, других типов с уровнем доступа public, члены которых имеют уровень доступа internal.
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) } // Требуется только один параметр для удобного метода required override convenience init(no1: Int) { self.init(no1: no1, no2: 0) } } let res = MainClass(no1: 20) let show = SubClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(show.no1)") print("res is: \(show.no2)")
Результат выполнения программы приведен выше:
res is: 20 res is: 30 res is: 50
Вы можете расширять классы, структуры и энумеры при условии, что это разрешено. Члены расширения должны иметь уровень доступа,一致的 с уровнем доступа исходных членов. Например, если вы расширяете общедоступный тип, то новые члены должны иметь уровень доступа по умолчанию,一致的 с исходными членами, то есть internal.
Или, вы можете явно указать уровень доступа расширения (например, using private extension) для всех членов расширения, чтобы определить новый уровень доступа по умолчанию. Этот новый уровень доступа по умолчанию может быть overridden отдельными членами.
Уровень доступа генерического типа или генерической функции выбирается из минимального уровня доступа генерического типа, функции и параметра генерического типа.
public struct TOS<T> { var items = [T]() private mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push("Swift") print(tos.items) tos.push("Генериков") print(tos.items) tos.push("Генерик") print(tos.items) tos.push("Параметр типа") print(tos.items) let deletetos = tos.pop()
Результат выполнения программы приведен выше:
["Swift"] ["Swift", "Генериков"] ["Swift", "Генерик", "Параметр типа"] ["Swift", "Генерик", "Параметр типа", "Имя параметра типа"]
Любой тип别名, который вы определяете, будет считаться отдельным типом, чтобы можно было выполнять управление доступом. Уровень доступа типа别名 не может быть выше уровня доступа исходного типа.
Например, тип别名 уровня private можно определить для типов public, internal или private, но тип别名 уровня public можно определить только для типов уровня public, и он не может быть определен для типов уровня internal или private.
Внимание: это правило также применяется к случаям, когда для удовлетворения требований протокола一致性 даются имена синонимов для связанных типов.
public protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct Stack<T>: Container { // Оригинальная реализация Stack<T> var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // Соответствие протоколу Container mutating func append(item: T) { self.push(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 } } // все элементы совпадают, поэтому возвращает true return true } var tos = Stack<String>() tos.push("Swift") print(tos.items) tos.push("Генериков") print(tos.items) tos.push("Where предложение") print(tos.items) var eos = ["Swift", "Генериков", "Where предложение"] print(eos)
Результат выполнения программы приведен выше:
["Swift"] ["Swift", "Генериков"] ["Swift", "Генериков", "Where предложение"] ["Swift", "Генериков", "Where предложение"]