English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Swift базовый курс

Операторы Swift

Swift потоковый контроль

Swift Сборка

Swift Функция

Swift Уровень

Контроль доступа в Swift

Контроль доступа может ограничивать уровень доступа кода из других файлов или модулей к вашему коду.

Вы можете явно установить уровень доступа для отдельных типов (классы, структуры, энум) и для их свойств, функций, методов инициализации, базовых типов, индексов и т.д.

Протоколы также могут быть ограничены в использовании в определенном диапазоне, включая глобальные константы, переменные и функции в протоколе.

Контроль доступа основан на модуле и файле исходного кода.

Модуль - это независимый компонент, который можно构建 и 发布 в виде 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.

Если уровень доступа не указан, он по умолчанию 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()

Результат выполнения программы приведен выше:

Надкласс
Подкласс

Уровень доступа getter и setter констант, переменных и индексов

Константы, переменные и свойства не могут иметь уровень доступа выше уровня их типа.

Например, вы определяете свойство уровня доступа public, но его тип private, это запрещено компилятором.

Таким же образом, индекс не может иметь уровень доступа выше уровня типа индекса или типа возвращаемого значения.

Если тип константы, переменной, свойства или индекса определен на уровне private, то они должны явно объявляться с уровнем доступа private:

private var privateInstance = SomePrivateClass()

Уровень доступа getter и setter

Уровень доступа 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 предложение"]