Swift / SwiftUI

Inicializador Membro em Swift explicado com Exemplos de Código

O texto explica como os inicializadores membro em Swift facilitam a criação de instâncias de structs sem necessidade de escrever um inicializador manual. A partir do Swift 6.4, foram implementadas melhorias que permitem excluir propriedades privadas com valores padrão dos inicializadores gerados automaticamente, tornando o uso mais conveniente e reduzindo a necessidade de boilerplate.

Compartilhar
Memberwise Initializer in Swift explained with Code Examples

Inicializadores membro em Swift permitem criar instâncias de estruturas sem escrever manualmente um inicializador. O compilador examina as propriedades armazenadas da sua estrutura e automaticamente gera um inicializador que aceita valores para elas.

Esta é uma das razões pelas quais as estruturas são tão leves de usar em Swift. No entanto, existem alguns detalhes sobre controle de acesso e propriedades privadas que podem surpreender você. O Swift 6.4 melhora o comportamento padrão, tornando os inicializadores membro mais úteis quando sua estrutura contém detalhes de implementação privada.

O que é um inicializador membro?

Um inicializador membro é um inicializador gerado automaticamente pelo Swift para estruturas. Ele permite que você inicie cada propriedade armazenada diretamente:

struct Article {
    let title: String
    let url: URL
    var readCount: Int
}

let article = Article( title: "Inicializadores Membro em Swift", url: URL(string: "https://www.avanderlee.com")!, readCount: 0 )

Você não precisou escrever este inicializador por conta própria:

init(title: String, url: URL, readCount: Int) {
    self.title = title
    self.url = url
    self.readCount = readCount
}

O compilador gera isso para você. Isso mantém tipos de modelo simples curtos e legíveis, que é uma das razões pelas quais eu geralmente começo com uma estrutura por padrão.

Valores padrão de propriedade

Inicializadores membro também suportam valores padrão de propriedades. Se uma propriedade armazenada tiver um valor padrão, o Swift usará esse valor como argumento padrão no inicializador gerado:

struct Article {
    let title: String
    let url: URL
    var readCount: Int = 0
}

let article = Article( title: "Inicializadores Membro em Swift", url: URL(string: "https://www.avanderlee.com")! )

Neste caso, o Swift ainda gera um parâmetro para readCount , mas ele recebe um valor padrão:

// Gerado automaticamente:
init(title: String, url: URL, readCount: Int = 0)

Este comportamento foi melhorado no Swift 5.1 através de SE-0242: Synthesize default values for the memberwise initializer . Já toquei brevemente nisso em meu artigo sobre estruturas vs classes em Swift , mas o Swift 6.4 adiciona outra melhoria útil.

Propriedades privadas antes do Swift 6.4

Antes do Swift 6.4, propriedades armazenadas privadas com valores padrão poderiam tornar o inicializador membro gerado muito menos útil:

struct Article {
    let title: String
    let url: URL
    private var readCount: Int = 0
}

// Você esperaria que isso funcionasse, mas não funciona antes do Swift 6.4: let article = Article( title: "Inicializadores Membro em Swift", url: URL(string: "https://www.avanderlee.com")! )

Você pode esperar que isso funcione. Depois de tudo, readCount é privado e já tem um valor padrão, então os chamadores não precisam saber sobre ele.

No entanto, antes do Swift 6.4, o compilador ainda incluía readCount no inicializador membro:

// Antes do Swift 6.4, readCount ainda está incluso apesar de ser privado:
private init(title: String, url: URL, readCount: Int = 0)

Como o inicializador incluía uma propriedade privada, o próprio inicializador se tornava privado. Como resultado, criar a Article ora da estrutura falharia:

Inicializadores membro antes do Swift 6.4 poderiam resultar em um erro: “inicializer is inaccessible due to ‘private’ protection level”

Isso frequentemente o forçava a escrever um inicializador manual apenas para esconder um detalhe de implementação privada:

struct Article {
    let title: String
    let url: URL
    private var readCount: Int = 0

    init(title: String, url: URL) {
        self.title = title
        self.url = url
    }
}

O inicializador manual funciona, mas remove parte da conveniência que tornava a estrutura fácil de usar no primeiro lugar.

Propriedades privadas em Swift 6.4

O Swift 6.4 implementa SE-0502: Exclude private initialized properties from memberwise initializer . O inicializador membro gerado agora exclui propriedades menos acessíveis que já tenham um valor inicial.

Na prática, o exemplo anterior se torna válido:

struct Article {
    let title: String
    let url: URL
    private var readCount: Int = 0
}

let article = Article( title: "Inicializadores Membro em Swift", url: URL(string: "https://www.avanderlee.com")! )

O Swift agora gera o inicializador que você provavelmente esperava:

// Começando no Swift 6.4, readCount não é mais necessário:
init(title: String, url: URL)

A propriedade privada readCount também existe e ainda começa em 0 , mas já não força o inicializador membro a se tornar privado. Esta é uma pequena melhoria na linguagem que remove uma fonte comum de boilerplate.

Gosto dessa mudança porque ela corresponde melhor à forma como penso sobre propriedades armazenadas privadas. Se uma propriedade é privada e já inicializada, geralmente parece um detalhe de implementação. Os chamadores não devem ter que passá-la para o inicializador.

Quais propriedades são excluídas?

O Swift 6.4 não simplesmente remove todas as propriedades privadas dos inicializadores membro. A regra é mais precisa: uma propriedade é excluída quando é menos acessível que o inicializador gerado e já tem um valor inicial.

Um valor inicial pode ser explícito:

struct Article {
    let title: String
    private var readCount = 0
}

Ela também pode ser um valor inicializado, como uma opcional que começa como nil :

struct Article {
    let title: String
    private var cachedSummary: String?
}

No Swift 6.4, readCount e cachedSummary devem ser excluídos do inicializador membro quando existirem propriedades mais acessíveis como title .

No entanto, uma propriedade privada sem valor inicial ainda precisa ser inicializada de alguma forma:

struct Article {
    let title: String
    private let identifier: UUID
}

Neste caso, o Swift ainda inclui identifier no inicializador membro. Como identifier é privado,

Fonte original

Conteúdo traduzido e adaptado pela redação do Notícias Mobile. Confira também a matéria na fonte original.

Leia a matéria completa