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

Controle de Acesso Swift

Access control can limit the access level of code in other source files or modules to your code.

You can explicitly set the access level for a single type (class, structure, enumeration), as well as for properties, functions, initialization methods, basic types, and indexers of these types.

Protocols can also be limited to a certain range of use, including global constants, variables, and functions within the protocol.

Access control is based on modules and source files.

A module refers to a Framework or Application built and released as an independent unit. In Swift, a module can use the import keyword to import another module.

A source file is a single source code file, which usually belongs to a module. A source file can contain multiple class and function definitions.

Swift provides four different access levels for entities in code: public, internal, fileprivate, and private.

Access levelDefinition
publicCan access any entity in the source files of its own module, and others can also access all entities in the source files by importing the module.
internalCan access any entity in the source files of its own module, but others cannot access the entities in the source files of the module.
fileprivatePrivate within the file, can only be used in the current source file.
privateOnly accessible within the class, and cannot be accessed outside the scope of the class or structure.

public é o nível de acesso mais alto, e private é o nível de acesso mais baixo.

Sintaxe

Declare o nível de acesso da entidade usando modificador public, internal, fileprivate, private:

exemplo online

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() {}

A menos que haja uma especificação especial, todas as entidades usam o nível de acesso padrão internal.

Por padrão, o nível de acesso não especificado é internal

class SomeInternalClass {}              // Nível de acesso internal
let someInternalConstant = 0            // Nível de acesso internal

Permissão de tipo de função

O nível de acesso da função deve ser determinado com base no nível de acesso do tipo do parâmetro e do tipo de retorno da função.

O exemplo a seguir define uma função global chamada someFunction e não declara explicitamente seu nível de acesso.

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // Implementação da função
{}

Um dos tipos da classe SomeInternalClass dentro da função tem nível de acesso internal, e o outro SomePrivateClass tem nível de acesso private. Portanto, de acordo com o princípio de nível de acesso do tupla, o nível de acesso do tupla é private (o nível de acesso do tupla é o mesmo que o tipo com nível de acesso mais baixo dentro do tupla).

Como o nível de acesso do tipo de retorno da função é private, você deve usar o modificador private para declarar explicitamente a função:

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // Implementação da função
{}

É errado declarar a função como public ou internal, ou usar o nível de acesso padrão internal, porque assim você não poderá acessar o valor de retorno de nível private.

Permissão de acesso do tipo enum

O nível de acesso dos membros do enum herda do enum, você não pode declarar níveis de acesso diferentes para membros do enum.

exemplo online

Por exemplo, no seguinte exemplo, o enum Student é explicitamente declarado como nível public, então o nível de acesso dos membros Name, Mark também é public:

exemplo online

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("Nome do aluno: (studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
    print("Notas dos alunos: (Mark1),(Mark2),(Mark3)")
{}

O resultado de execução do programa acima é:

Notas dos alunos: 98,97,95

Permissão de acesso da subclasse

O nível de acesso da subclasse não pode ser superior ao do pai. Por exemplo, se o nível de acesso do pai for internal, o nível de acesso da subclasse não pode ser declarado como public.

exemplo online

 public class SuperClass {
    fileprivate func show() {
        print("Superclasse")
    {}
{}
 
// O nível de acesso não pode ser superior ao da superclasse internal > public
internal class SubClass: SuperClass {
    override internal func show() {
        print("Subclasse")
    {}
{}
 
let sup = SuperClass()
sup.show()
 
let sub = SubClass()
sub.show()

O resultado de execução do programa acima é:

Superclasse
Subclasse

Permissão de acesso de constante, variável, propriedade, subscrito

Constantes, variáveis e propriedades não podem ter um nível de acesso superior ao de seus tipos.

Por exemplo, se você definir uma propriedade de nível public, mas seu tipo for de nível private, isso não é permitido pelo compilador.

Da mesma forma, o índice não pode ter um nível de acesso superior ao do tipo de índice ou ao tipo de retorno.

Se o tipo de definição de constante, variável, propriedade, índice de subscrito for de nível private, então elas devem declarar explicitamente o nível de acesso como private:

private var privateInstance = SomePrivateClass()

Permissão de acesso do getter e setter

Os níveis de acesso dos getters e setters de constantes, variáveis, propriedades e índices de subscrito herdam o nível de acesso dos membros aos quais pertencem.

O nível de acesso do setter pode ser inferior ao nível de acesso do getter correspondente, permitindo assim controlar as permissões de leitura e escrita de variáveis, propriedades ou índices de subscrito.

exemplo online

class Samplepgm {
    fileprivate var counter: Int = 0{
        willSet(newTotal){
            print("Contador: \(newTotal)")
        {}
        didSet{
            if counter > oldValue {
                print("Quantidade adicionada (counter - oldValue")
            {}
        {}
    {}
{}
 
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

O nível de acesso do counter é fileprivate, acessível dentro do arquivo.

O resultado de execução do programa acima é:

Contador: 100
Quantidade adicionada 100
Contador: 800
Quantidade adicionada 700

Permissão de acesso do construtor e do construtor padrão

Inicialização

Podemos declarar um nível de acesso para o método de inicialização personalizado, mas não pode ser superior ao nível de acesso da classe a que pertence. Exceto para o construtor necessário, cujo nível de acesso deve ser o mesmo que o nível de acesso da classe.

Como os parâmetros de função ou método, o nível de acesso dos parâmetros do método de inicialização não pode ser inferior ao nível de acesso do método de inicialização.

Método de inicialização padrão

O Swift fornece um método de inicialização padrão sem parâmetros para estruturas e classes, usado para fornecer operações de atribuição para todas as propriedades, mas não fornece valores específicos.

O nível de acesso do método de inicialização padrão é o mesmo que o nível de acesso do tipo ao qual pertence.

exemplo online

Use a palavra-chave required antes do método init() de cada subclasse para declarar o nível de acesso.

exemplo online

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()

O resultado de execução do programa acima é:

10
30
10

Permissão de acesso do protocolo

Se você quiser declarar explicitamente o nível de acesso de um protocolo, note que você deve garantir que o protocolo seja usado apenas no escopo de nível de acesso declarado.

Se você definiu um nível de acesso public para um protocolo, então as funções necessárias fornecidas pelo protocolo também serão de nível de acesso public. Isso é diferente de outros tipos, por exemplo, outros tipos de nível de acesso public, seus membros têm nível de acesso internal.

exemplo online

public protocol TcpProtocol {}}
    init(no1: Int)
{}
 
public class MainClass {
    var no1: Int // storage local
    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)
    {}
    
    // Requer apenas um parâmetro para o método conveniente
    Required only one parameter for convenient method1: Int) {
        self.init(no1:no1, no2:0)
    {}
{}
 
let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)
 
print("res is: \(res.no"1)")
print("res is: \(show.no"1)")
print("res is: \(show.no"2)")

O resultado de execução do programa acima é:

res is: 20
res is: 30
res is: 50

Permissões de Acesso de Extensão

Você pode estender classes, estruturas e enums sob condições permitidas. Os membros da extensão devem ter o mesmo nível de acesso que os membros originais. Por exemplo, se você estender um tipo público, os novos membros devem ter o mesmo nível de acesso padrão internal que os membros originais.

Ou, você pode explicitamente declarar o nível de acesso da extensão (por exemplo, usando private extension) para todos os membros da extensão declarar um novo nível de acesso padrão. Este novo nível de acesso padrão ainda pode ser coberto por níveis de acesso declarados individualmente por membros.

Permissões de Acesso Genérico

O nível de acesso de um tipo genérico ou função genérica é o mais baixo entre o tipo genérico, a função em si e os parâmetros de tipo genérico.

exemplo online

public struct TOS<T> {
    var items = [T]()
    private mutating func push(item: T) {
        items.append(item)
    {}
    
    mutável func pop() -> T {
        return items.removeLast()
    {}
{}
 
var tos = TOS<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("Generics")
print(tos.items)
 
tos.push("Parâmetros de Tipo")
print(tos.items)
 
tos.push("Nome do Parâmetro de Tipo")
print(tos.items)
let deletetos = tos.pop()

O resultado de execução do programa acima é:

["Swift"]
["Swift", "Generics"]
["Swift", "Generics", "Parâmetros de Tipo"]
["Swift", "Generics", "Parâmetros de Tipo", "Nome do Parâmetro de Tipo"]

Tipo alias

Qualquer tipo alias definido será tratado como um tipo diferente, facilitando o controle de acesso. O nível de acesso de um tipo alias não pode ser superior ao nível de acesso do tipo original.

por exemplo, um alias de tipo de nível private pode ser atribuído a um tipo public, internal ou private, mas um alias de tipo public pode ser atribuído apenas a um tipo public, não a um tipo internal ou private.

atenção: esta regra também se aplica a situações onde se nomeia um alias de tipo relacionado para atender a consistência do protocolo.

exemplo online

public protocol Container {
    typealias ItemType
    mutável func append(item: ItemType)
    var count: Int { get }
    subscrito(i: Int) -> ItemType { get }
{}
 
struct Stack<T>: Container {
    // implementação original Stack<T>
    var items = [T]()
    mutável func push(item: T) {
        items.append(item)
    {}
    
    mutável func pop() -> T {
        return items.removeLast()
    {}
    
    // conformidade com o protocolo Container
    mutável func append(item: T) {
        self.push(item)
    {}
    
    var count: Int {
        return items.count
    {}
    
    subscrito(i: Int) -> T {
        return items[i]
    {}
{}
 
func allItemsMatch<
    C1: Container, C2: Container
    onde C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, anotherContainer: C2) -> Bool {
        // verifique se ambos os contêineres contêm o mesmo número de itens
        se someContainer.count != anotherContainer.count {
            return false
        {}
        
        // verifique cada par de itens para ver se eles são equivalentes
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            {}
        {}
        
        // Todos os itens coincidem, então retorne true
        return true
{}
 
var tos = Stack<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("Generics")
print(tos.items)
 
tos.push("Where Statement")
print(tos.items)
 
var eos = ["Swift", "Generics", "Where Statement"]
print(eos)

O resultado de execução do programa acima é:

["Swift"]
["Swift", "Generics"]
["Swift", "Generics", "Where Statement"]
["Swift", "Generics", "Where Statement"]