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.