Swift - Controle de Acesso

Para restringir o acesso aos blocos de código, módulos e abstração é feito através do controle de acesso. Classes, estruturas e enumerações podem ser acessadas de acordo com suas propriedades, métodos, inicializadores e subscritos por mecanismos de controle de acesso. Constantes, variáveis ​​e funções em um protocolo são restritas e têm acesso permitido como global e local por meio do controle de acesso. O controle de acesso aplicado a propriedades, tipos e funções pode ser referido como 'entidades'.

O modelo de controle de acesso é baseado em módulos e arquivos fonte.

O módulo é definido como uma unidade única de distribuição de código e pode ser importado usando a palavra-chave 'importar'. Um arquivo de origem é definido como um único arquivo de código-fonte com um módulo para acessar vários tipos e funções.

Três níveis de acesso diferentes são fornecidos pela linguagem Swift 4. Eles são de acesso público, interno e privado.

S.No Níveis de acesso e definição
1

Public

Permite que as entidades sejam processadas em qualquer arquivo de origem de seu módulo de definição, um arquivo de origem de outro módulo que importa o módulo de definição.

2

Internal

Permite que entidades sejam usadas em qualquer arquivo de origem de seu módulo de definição, mas não em qualquer arquivo de origem fora desse módulo.

3

Private

Restringe o uso de uma entidade a seu próprio arquivo de definição de origem. O acesso privado desempenha o papel de ocultar os detalhes de implementação de uma funcionalidade de código específica.

Sintaxe

public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

Controle de acesso para tipos de função

Algumas funções podem ter argumentos declarados dentro da função sem nenhum valor de retorno. O programa a seguir declara aeb como argumentos para a função sum (). Dentro da própria função, os valores dos argumentos aeb são passados ​​invocando a chamada de função sum () e seus valores são impressos, eliminando assim os valores de retorno. Para tornar o tipo de retorno da função privado, declare o nível de acesso geral da função com o modificador privado.

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)

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

30 20
50 40
30 24

Controle de acesso para tipos de enumeração

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).")
   
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Student Marks are: 98,97,95

A enumeração na linguagem Swift 4 recebe automaticamente o mesmo nível de acesso para casos individuais de uma enumeração. Considere, por exemplo, acessar o nome do aluno e as marcas garantidas em três disciplinas. O nome da enumeração é declarado como aluno e os membros presentes na classe enum são o nome que pertence ao tipo de dados da string, as marcas são representadas como mark1, mark2 e mark3 do tipo de dados Inteiro. Para acessar o nome do aluno ou as notas que ele pontuou. Agora, o caso de troca imprimirá o nome do aluno se esse bloco de caso for executado, caso contrário, ele imprimirá as marcas garantidas pelo aluno. Se ambas as condições falharem, o bloco padrão será executado.

Controle de acesso para subclasses

O Swift 4 permite ao usuário criar uma subclasse de qualquer classe que possa ser acessada no contexto de acesso atual. Uma subclasse não pode ter um nível de acesso mais alto do que sua superclasse. O usuário não pode escrever uma subclasse pública de uma superclasse interna.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Welcome to Swift Super Class
Welcome to Swift Sub Class

Controle de acesso para constantes, variáveis, propriedades e subscritos

A constante, variável ou propriedade do Swift 4 não pode ser definida como pública do que seu tipo. Não é válido escrever uma propriedade pública com um tipo privado. Da mesma forma, um subscrito não pode ser mais público do que seu índice ou tipo de retorno.

Quando uma constante, variável, propriedade ou subscrito faz uso de um tipo privado, a constante, variável, propriedade ou subscrito também deve ser marcada como privada -

private var privateInstance = SomePrivateClass()

Getters e Setters

Os getters e setters de constantes, variáveis, propriedades e subscritos recebem automaticamente o mesmo nível de acesso da constante, variável, propriedade ou subscrito a que pertencem.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

Controle de acesso para inicializadores e inicializadores padrão

Os inicializadores personalizados podem receber um nível de acesso menor ou igual ao tipo que inicializam. Um inicializador necessário deve ter o mesmo nível de acesso que a classe a que pertence. Os tipos de parâmetros de um inicializador não podem ser mais privados do que o próprio nível de acesso do inicializador.

Para declarar toda e qualquer subclasse da palavra-chave initialize 'required' precisa ser definida antes da função init ().

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

10
30
10

Um inicializador padrão tem o mesmo nível de acesso que o tipo que ele inicializa, a menos que esse tipo seja definido como público. Quando a inicialização padrão é definida como pública, ela é considerada interna. Quando o usuário precisa que um tipo público seja inicializável com um inicializador sem argumento em outro módulo, forneça explicitamente um inicializador sem argumento público como parte da definição do tipo.

Controle de acesso para protocolos

Quando definimos um novo protocolo para herdar funcionalidades de um protocolo existente, ambos devem ser declarados com os mesmos níveis de acesso para herdar as propriedades um do outro. O controle de acesso do Swift 4 não permite que os usuários definam um protocolo 'público' que herda de um protocolo 'interno'.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

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

Controle de acesso para extensões

O Swift 4 não permite que os usuários forneçam um modificador de nível de acesso explícito para uma extensão quando o usuário usa essa extensão para adicionar conformidade de protocolo. O nível de acesso padrão para cada implementação de requisito de protocolo na extensão é fornecido com seu próprio nível de acesso de protocolo.

Controle de acesso para genéricos

Os genéricos permitem que o usuário especifique níveis mínimos de acesso para acessar as restrições de tipo em seus parâmetros de tipo.

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

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Controle de acesso para aliases de tipo

O usuário pode definir aliases de tipo para tratar tipos de controle de acesso distintos. O mesmo nível de acesso ou níveis de acesso diferentes podem ser definidos pelo usuário. Quando o alias do tipo é 'privado', seus membros associados podem ser declarados como 'privado, interno do tipo público'. Quando o alias do tipo é público, os membros não podem ser alias como um nome 'interno' ou 'privado'

Quaisquer apelidos de tipo que você definir são tratados como tipos distintos para fins de controle de acesso. Um alias de tipo pode ter um nível de acesso menor ou igual ao nível de acesso do tipo que ele atribui. Por exemplo, um alias de tipo privado pode ser um alias de um tipo privado, interno ou público, mas um alias de tipo público não pode ser um alias de um tipo interno ou privado.

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)

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]

Codificação e decodificação Swift

Swift 4 apresenta um novo Codable Protocolo, que permite serializar e desserializar tipos de dados personalizados sem escrever nenhum código especial - e sem ter que se preocupar em perder seus tipos de valor.

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

Observe que Langauage está em conformidade com o protocolo codificável. Agora vamos convertê-lo em uma representação de dados Json usando uma linha simples.

let encoder = JSONEncoder()
if let encoded = try? encoder.encode(java) {
   //Perform some operations on this value.
}

O Swift codificará automaticamente todos os valores dentro do seu tipo de dados.

Você pode decodificar os dados usando a função de decodificador como

let decoder = JSONDecoder()
if let decoded = try? decoder.decode(Language.self, from: encoded) {
   //Perform some operations on this value.
}

Ambos JSONEncoder e sua contraparte de lista de propriedades PropertyListEncoder têm muitas opções para personalizar a forma como funcionam.