
Oi Meu nome é Renat, estou desenvolvendo um serviço de análise de assinaturas no iOS - Apphud.
Como você sabe, a Apple na WWDC 2019 apresentou sua nova estrutura SwiftUI, projetada no futuro para substituir (ou não?) O familiar UIKit. SwiftUI permite que você descreva a interface do aplicativo em um estilo declarativo e reduz bastante a quantidade de código.
A Apple já introduziu alguns tutoriais de inglês interessantes com muitos exemplos. Vou tentar falar sobre a nova estrutura na forma de perguntas e respostas. Então vamos lá.
Antes de começar
Para trabalhar com o SwiftUI, você precisa fazer o download do Xcode 11 Beta . Você também deve ser um desenvolvedor Apple registrado. Ter o mais recente macOS Catalina é desejável, mas não necessário. Sem ele, o Canvas não estará disponível.
Portanto, no Xcode 11 Beta, crie um novo projeto e verifique se “Use SwiftUI” está marcado.
Perguntas e Respostas
Para onde foi o Interface Builder?
O SwiftUI não precisa mais do Interface Builder - ele foi substituído pelo Canvas , um editor de interface interativo que está intimamente relacionado ao código. Ao escrever um código, sua parte visual na tela é gerada automaticamente e vice-versa. Muito conveniente e, o mais importante, seguro. Agora, seu aplicativo não @IBOutlet
devido ao fato de você ter esquecido de atualizar a @IBOutlet
com a variável Neste artigo, não tocaremos na tela , consideraremos apenas o código.
O lançamento do aplicativo mudou?
Sim, agora o objeto inicial na interface do aplicativo não é UIWindow
, mas a nova classe UIScene
(ou seu UIWindowScene
descendente). E uma janela é adicionada à cena. Essas alterações afetam não apenas o SwiftUI, mas o iOS 13 como um todo.
Ao criar um projeto, você verá os arquivos AppDelegate , SceneDelegate e ContentView . SceneDelegate - um delegado da classe UIWindowScene
, usado para controlar cenas no aplicativo. Remanescente do AppDelegate .

A classe SceneDelegate é especificada em Info.plist
Na scene: willConnectTo: options:
método delegado scene: willConnectTo: options:
cria uma janela e um UIHostingController
raiz, que contém um ContentView
. ContentView
é a nossa página inicial. Todo o desenvolvimento será realizado nesta classe.
Qual a diferença entre o View e o UIView?
ContentView.swift
abrir o ContentView.swift
, você verá uma declaração de contêiner do ContentView. Como você já entendeu, não existem métodos viewDidLoad
ou viewDidAppear
familiares viewDidLoad
viewDidAppear
. A base das telas aqui não é o UIViewController
, mas a View . A primeira coisa a notar é que o ContentView
é uma struct
que aceita o protocolo View
. Sim, o View
agora se tornou um protocolo e muito simples. O único método que você precisa implementar no ContentView
é descrever o body
da variável. Todas as suas subvisões e visualizações personalizadas devem aceitar o protocolo View
, ou seja, devem ter uma variável de body
.
O que é corpo?
Body
é diretamente nosso contêiner, onde todas as outras subvisões são adicionadas. Isso é um pouco semelhante ao corpo em uma página html , onde a página html é um ContentView
. Body
sempre deve ter exatamente um descendente e qualquer classe que aceite o protocolo View
.
struct ContentView: View { var body: some View { Text("Hello, world!") } }
Tipos de retorno opacos ou o que é algum?
A construção de some TypeName
é uma inovação do Swift 5.1 chamada tipo de retorno opaco . É usado para casos em que não é importante para nós qual objeto retornar, o principal é que ele suporta o tipo especificado, neste caso, o protocolo View
.
Se simplesmente escrevemos var body: View
, isso significa que devemos retornar a View
. A classe Any
também não funciona, pois teríamos que executar uma operação de conversão de tipo ( usando o as!
Operator ). Portanto, eles criaram a palavra especial some
na frente do nome do protocolo para indicar o tipo de retorno opaco . Em vez de View
podemos retornar Text
, Image
, VStack
- qualquer coisa, pois todos eles suportam o protocolo View
. Mas deve haver exatamente um elemento: ao tentar retornar mais de uma View
compilador lançará um erro.

Erro de compilação ao tentar retornar mais de um elemento ao corpo
Qual é a sintaxe dentro dos colchetes e onde está o addSubview?
O Swift 5.1 introduziu a capacidade de agrupar objetos em um único todo em um estilo declarativo. Isso é semelhante a uma matriz dentro de um bloco de fechamento , mas os elementos são enumerados de uma nova linha sem vírgulas e retorno . Esse mecanismo foi chamado de Construtor de Funções .
Isso é amplamente usado no SwiftUI. Com base no Function Builder, eles criaram o ViewBuilder
- um designer de interface declarativo. Usando o ViewBuilder
, não precisamos mais escrever addSubview
para cada elemento - basta listar todos os View
de uma nova linha dentro do bloco de fechamento . O SwiftUI adicionará e agrupará elementos em um contêiner pai mais complexo.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) @_functionBuilder public struct ViewBuilder {
Anúncio do ViewBuilder na estrutura SwiftUI
Como adicionar UILabel, UIImageView e outros elementos?
Os elementos são criados de maneira muito simples: cada View
precisa ser gravada a partir de uma nova linha e alterar a aparência usando as funções de modificador ( modificadores de exibição ). A diferença entre modificadores e funções familiares para nós é que eles sempre retornam um objeto contêiner em vez de void
. Portanto, podemos criar cadeias inteiras de modificadores através do ponto.
var body: some View { VStack{ Text("World Time").font(.system(size: 30)) Text("Yet another subtitle").font(.system(size: 20)) } }
No entanto, nem todos os controles e o View têm seus análogos no SwiftUI. Aqui está uma lista parcial de classes do UIKit e seus análogos:
UITableView
-> List
UICollectionView
não tem analógico
UILabel
-> Text
UITextField
-> TextField
UIImageView
-> Image
UINavigationController
-> NavigationView
UIButton
-> Button
UIStackView
-> HStack
/ VStack
UISwitch
-> Toggle
UISlider
-> Slider
UITextView
não tem analógico
UIAlertController
-> Alert
/ ActionSheet
UISegmentedControl
-> SegmentedControl
UIStepper
-> Stepper
UIDatePicker
-> DatePicker
Como é a navegação entre as telas?
O controlador de navegação assume o papel de um NavigationView
especial. Apenas envolva seu código no NavigationView{}
. E a própria ação de transição pode ser adicionada a um botão NavigationLink
especial, que pressiona a tela DetailView
condicional.
var body: some View { NavigationView { Text("World Time").font(.system(size: 30)) NavigationLink(destination: DetailView() { Text("Go Detail") } } }
Como apresentar novas visões modalmente? Isso é feito, por exemplo, usando a construção de planilha :
Button(action: { print("Button Pushed") self.show_modal = true }) { Text("Present Modal") }.sheet(isPresented: self.$show_modal) { ModalView() }
Como mencionado acima, o body
pode retornar não apenas uma instância do View
, mas também qualquer outra classe que aceite este protocolo. Isso nos dá a oportunidade de DetailView
não o DetailView
, mas também o Text
ou a Image
!
Como organizar elementos na tela?
Os elementos são organizados independentemente um do outro e podem ser localizados verticalmente dentro do VStack
, horizontalmente no HStack
e um acima do outro ZStack
. ScrollView
e ListView
também estão disponíveis para nós. Você pode alternar e compartilhar esses contêineres para obter qualquer malha de elementos.
Ao combinar contêineres, você pode obter uma árvore bastante grande com um grande número de anexos. No entanto, o SwiftUI é otimizado especificamente para isso, portanto, o aninhamento profundo de contêineres não afeta o desempenho. Isso é afirmado no vídeo com wwdc (a partir das 15:32 ).
var body: some View { NavigationView { VStack { NavigationLink(destination: LargeView(timeString: subtitle)) { Text("See Fullscreen") } Text("World Time").font(.system(size: 30)) } } }
Como mostrar a barra de navegação?
Declarar um NavigationView
não NavigationView
suficiente; você deve especificar um título e estilo de navegação para a barra de navegação .
NavigationView { VStack{}.navigationBarTitle(Text("World Time"), displayMode: .inline) }
Observe que a função navigationBarTitle
não é chamada no NavigationView
, mas em sua View
interna. DisplayMode é um parâmetro que indica o estilo da barra de navegação : grande ou padrão.
Existe um análogo do método viewDidLoad?
Se você deseja executar o código ao inicializar o View
, pode fazê-lo adicionando a função onAppear {}. O OnAppear pode ser adicionado a qualquer View
, por exemplo, ao VStack
. Neste exemplo, quando o contêiner aparece na tela, uma solicitação http é feita para o servidor.
struct ContentView : View { @State var statusString : String = "World Time" var body: some View { NavigationView { VStack { NavigationLink(destination:DetailView()) { Text("Go Detail") } Text(statusString).font(.system(size: 30)) }.onAppear { self.loadTime() } } } func loadTime(){ NetworkService().getTime { (time) in if let aTime = time { self.statusString = "\(aTime.date())" } } } }
Chamamos a função loadTime
, que solicita a hora atual do servidor e retorna o modelo WorldTime
. Não entraremos em ciclos na classe NetworkService
; você pode ver todo o código, tendo baixado os códigos-fonte. Link no final do artigo.
A variável var statusString
foi renderizada para atribuir o horário atual posteriormente. A variável tem um atributo especial @State
. O que ele quer dizer
Wrappers de propriedades ou o que é @State
?
O Swift 5.1 introduziu os chamados wrappers de propriedade (ou delegados de propriedade ). No SwiftUI, os wrappers de propriedades são usados para atualizar ou vincular um dos parâmetros de exibição com nossa própria variável, por exemplo, o valor da opção Toggle .
O atributo @State
é um atributo especial que é colocado antes de uma declaração de variável. Isso nos permite rastrear automaticamente alterações de propriedade sem código adicional. No exemplo acima, o texto "Hora mundial" mudará para a data atual assim que atualizarmos o valor statusString.
Para vincular valores ( Vinculação de propriedades ), podemos especificar um caractere especial $
antes do nome da variável no próprio código:
struct DetailsView: View { @State var changeToggle: Bool var body: some View { Toggle(isOn: $changeToggle) { Text("Change Toggle") } } }
Alterando a posição do comutador, o valor da variável também será alterado.
Os invólucros de propriedades são um componente muito importante do SwiftUI, acabei de mencioná-los de passagem. Para um conhecimento mais detalhado dos wrappers de propriedades, assista ao vídeo do wwdc aqui (a partir do 37º minuto), aqui (a partir do 12º minuto) e aqui (a partir do 19º minuto).
Como adicionar view ao tempo de execução?
É importante notar imediatamente que você não pode adicionar visualização a qualquer momento no sentido literal da palavra. SwiftUI é uma estrutura declarativa que renderiza a exibição inteira. No entanto, você pode definir várias condições dentro do corpo e atualizar o estado da exibição quando elas mudarem. Neste exemplo, usamos o grupo mais simples de @State – if
com a variável isTimeLoaded
.
struct ContentView : View { @State var statusString : String = "World Time" @State var isTimeLoaded : Bool = false var body: some View { NavigationView { VStack { if isTimeLoaded { addNavigationLink() } Text(statusString).font(.system(size: 30)).lineLimit(nil) }.navigationBarTitle(Text("World Time"), displayMode: .inline) }.onAppear { self.loadTime() } } func addNavigationLink() -> some View { NavigationLink(destination: Text("124!!!")) { Text("Go Detail") } } func loadTime(){ NetworkService().getTime { (time) in if let aTime = time { self.statusString = "\(aTime.date().description(with: Locale.current))" self.isTimeLoaded = true } } } } struct DetailView : View { var timeString : String var body : some View { Text(timeString).font(.system(size: 40)).lineLimit(nil) } }
A propósito, você notou que a função addNavigationLink()
não tem a palavra return
? Essa é outra inovação do Swift 5.1 - para funções com uma única expressão, agora é opcional escrever return
. Mas você pode escrever.
Conclusão
Isso é apenas parte das perguntas e respostas do SwiftUI. Examinei questões gerais, espero que este artigo ajude os iniciantes a entender os principais pontos dessa estrutura. O SwiftUI ainda é bruto, mas sem dúvida será aprimorado.
A questão lógica é: vale a pena aprender o UIKit? Claro que sim . O UIKit é a base da programação no iOS e se desenvolverá ainda mais. Além disso, muitos componentes SwiftUI são um invólucro sobre o UIKit. Bem, até o momento não existem bibliotecas, estruturas, pods para o SwiftUI. Tudo terá que ser escrito por você. Portanto, é melhor estudar as duas abordagens do desenvolvimento - para que você seja um desenvolvedor mais valioso.
Você pode baixar as fontes do projeto aqui .
Obrigado por ler o artigo até o fim. Espero que você ache útil.
O que ler?