Learning SwiftUI, when you already know UIKit – The Basics of SwiftUI 📱 (free iOS tutorial)
Estimated read time: 1:20
Learn to use AI like a Pro
Get the latest AI workflows to boost your productivity and business performance, delivered weekly by expert consultants. Enjoy step-by-step guides, weekly Q&A sessions, and full access to our AI workflow archive.
Summary
In this engaging and comprehensive tutorial, Vincent Pradeilles introduces SwiftUI to developers familiar with UIKit, covering the basics of setting up a SwiftUI project, understanding its components, and delving into its data flow mechanisms. Vincent explains how SwiftUI utilizes cornerstones like the View, Scene, and App protocols, and highlights the importance of features such as opaque return types and result builders in creating efficient and elegant user interfaces. With a focus on practicality, Vincent guides viewers through manipulating text and text fields, state management using property wrappers, and previews utilizing Xcode's live preview feature.
Highlights
Vincent tackles introductory SwiftUI concepts with a UIKit perspective. 📱
The video outlines setting up SwiftUI structures efficiently. ⚙️
Detailed explanations are given on the use of property wrappers for managing state. 💡
Vincent demonstrates the importance of SwiftUI's live preview function. 👀
Guidance is provided on transitioning between UIKit and SwiftUI seamlessly. 🔄
Key Takeaways
SwiftUI offers a refreshing approach to building iOS interfaces for those familiar with UIKit. 🆕
The app structure revolves around protocols like View, Scene, and App. 🌐
Utilizing Swift features such as opaque return types and property wrappers enhances performance. 🚀
The live preview in Xcode streamlines developing and testing views. 📺
Vincent encourages embracing SwiftUI's flexibility while recognizing its integration with UIKit. 🤝
Overview
Vincent Pradeilles passionately introduces SwiftUI basics tailored for those experienced in UIKit. He navigates the essentials, from app setup to understanding SwiftUI's core protocols. His insights bridge the gap between traditional UIKit development and the modern SwiftUI approach, making the initial transition smoother for viewers.
A standout feature of the tutorial is the exploration of key SwiftUI features like the result builders and opaque return types. Vincent clarifies their roles in ensuring Swift apps are both efficient and easy to maintain. Furthermore, he showcases the utility of Xcode's live preview—a tool that many may overlook but proves essential in SwiftUI design iterations.
Vincent's tutorial isn't just about learning SwiftUI in isolation. It's about understanding how it complements UIKit. Through various coding examples, he eloquently demonstrates how developers can leverage both to create seamless, modern, and user-friendly applications. His approach encourages developers to integrate SwiftUI into their existing toolkit effectively.
Chapters
00:00 - 02:00: Introduction The chapter serves as an introduction to a live streaming training course focusing on learning Swift UI for those who are already familiar with UI kit. It initially addresses an audio feedback issue experienced by the speaker, assuring the audience that it was resolved quickly. The chapter sets the stage for the educational content to follow.
02:00 - 10:00: Creating a SwiftUI Project The chapter introduces the series of live streams aimed at teaching Swift UI to those already familiar with UI Kit. The host acknowledges a mistake with the timing of the stream and clarifies the session's objective. It's emphasized that the entire Swift UI won't be covered in a single session, positioning it as the first in a series. The chapter sets the context for learning Swift UI incrementally through upcoming sessions.
10:00 - 20:00: Understanding the SwiftUI Entry Point The chapter prepares the reader to proficiently use SwiftUI, whether it's within a new app or integrated into an existing application. It encourages live viewers to ask questions in the chat to enhance the learning experience and make the session feel more dynamic and interactive for future replays.
20:00 - 30:00: Understanding the View Protocol This chapter introduces the importance of asking questions during live training sessions and emphasizes how doing so can benefit not just the individual but also others who view the replay later. It also mentions that the complete training course will be available for free on YouTube, with an option for viewers to leave a tip if they wish to support the creator.
30:00 - 40:00: Exploring the App Protocol The chapter titled 'Exploring the App Protocol' covers the basics of the UI kit, providing an overview of a Swift UI app's structure. The chapter aims to familiarize viewers with how a Swift UI app looks and functions, starting with fundamental concepts.
40:00 - 50:00: Understanding the Some Keyword The chapter titled 'Understanding the Some Keyword' begins by discussing the main building blocks of a Swift UI. It aims to provide a comprehensive overview of everything within this landscape. The chapter warns against the 'tutorial effect,' where learning is confined to specific scenarios presented in a tutorial, leaving learners unprepared for other contexts. The chapter promises to delve deeper into more advanced topics after establishing a foundational understanding.
50:00 - 60:00: Exploring ViewBuilder The chapter titled 'Exploring ViewBuilder' focuses on the creation of a Swift UI app using Xcode. While primarily concentrating on iOS, it highlights the versatility of Swift UI, which can also be utilized for watchOS and macOS applications. The chapter underscores the significance of Swift UI as a key feature in developing diverse application interfaces across different Apple platforms. The chapter begins with creating a new iOS app, indicating steps and considerations for initial setup.
60:00 - 70:00: Using Text and Modifiers The chapter titled 'Using Text and Modifiers' focuses on the initial steps to create a Swift UI project. It emphasizes the importance of choosing Swift UI over Storyboard for the interface configuration. Despite having no flexibility in language choice, as Swift must be used due to the nature of Swift UI, the guide thoroughly explains setting up the project, which includes unchecking options for using codeata and including tests, and defining a simple organization name.
70:00 - 80:00: Understanding State and Binding The chapter titled 'Understanding State and Binding' begins with a practical setup where the speaker sets up a project on their desktop and deals with initial technical warnings. The speaker is prepared with a script on their iPad, ensuring they cover all the planned points thoroughly. This introduction sets the stage for a structured exploration of state and binding concepts.
80:00 - 90:00: TextField in SwiftUI This chapter focuses on TextField in SwiftUI. As you begin a Swift UI project, you might notice a preview appearing, but the emphasis here isn't on the preview. The text references interactive engagement with a chat message that appreciates the content about SwiftUI. There is also a query regarding strategies for understanding various property wrappers such as app, storage, and environment. The chapter acknowledges this question and mentions that these property wrappers will be explored as the material progresses, though it will not be the starting point.
90:00 - 100:00: SecureField and TextEditor The chapter discusses the foundational aspects of setting up a Swift UI application. It begins by mentioning that before delving into property wrappers, there are preliminary details to cover. Specifically, when initiating a Swift UI app, two significant files are generated: one named after the app, analogous to the app delegate or main file in a UIKit app, and the 'ContentView', which serves as the initial view.
100:00 - 110:00: Recap and Conclusion In the 'Recap and Conclusion' chapter, the focus is on understanding the basic structure of your app with an analogy to the UI view controller in a UI kit app. The chapter quickly dives into Swift UI's content view file and highlights one of its significant features, the live preview functionality. It provides keyboard shortcuts for showing and hiding this preview in Xcode, emphasizing efficient navigation and editing.
Learning SwiftUI, when you already know UIKit – The Basics of SwiftUI 📱 (free iOS tutorial) Transcription
00:00 - 00:30 It's. Hey, what's up, everyone? Welcome to this live stream, which is the first part of a free training course to learn Swift UI when you are already experienced with UI kit. So first thing, if you were I have a weird feedback audio. Oh, I had a window with the live playing, which is a bad ID. Okay. So I wanted to say first thing if you were waiting at 06:00 p.m..
00:30 - 01:00 French time sorry, I put the wrong time for the live, but at least here I am. So let's get started. So before we start so I've told you this is a live stream that will the goal of teaching Swift UI to people who already know UI Kit. Of course, as you can imagine, I will not teach you all Swift UI in this single live stream. So this is the first live stream of a series. And my goal is that by the end of this series,
01:00 - 01:30 you will be proficient enough with Swift UI to start using it either in a new app or inside an existing app. If you are watching Live, please ask all and any question that you could have in the chat. This way I can answer it and help you. But also because for people who will watch the replay, it will make it feel like much more alive.
01:30 - 02:00 And there is a good chance that the question that you had, well, they will also have them when watching the replay. So by asking your question, you are also helping the people who will be watching the replay. And last thing before we get started so this training course will be available entirely for free on YouTube. The replay will be available after the live stream. But if you enjoy this training course and you want to support me in creating it, you have a link in the description to leave a tip.
02:00 - 02:30 The link is also here in the corner of the screen. And if you leave a tip during the live, normally your name should be displayed on the live stream if I've set up everything correctly. And with that being said, let's get started. So for this first chapter, we are going to cover the basics of UI kit. So what's my goal here is to basically give you, we could say, a lay of the land. Like, how does a Swift UI app look like?
02:30 - 03:00 What are the main building blocks of a Swift UI? Try to give you really a good idea of everything that's on the landscape. And then after that, we will start diving deeper into some more advanced context. What I really want to avoid is what I kind of call the tutorial effect. Where you start a tutorial, it shows you a lot of stuff in a very specific direction, but outside that direction, you basically don't know all the
03:00 - 03:30 context, and I want to avoid that. So to get started, we are going to create a Swift UI app so you can see I've opened Xcode. I'm creating an iOS app. I will mostly focus on iOS for this training course. But of course, you can also use Swift UI for watchOS and for macOS. It's even one of the big features of Swift UI. So we're going to create a new iOS app. So for the product name, let's
03:30 - 04:00 call it Discovering Swift UI. And for the interface, you definitely don't want to use Swift UI, not Storyboard. And for the language, you don't have a choice. You have to use Swift, as the name Swift UI heavily implies. I'm going to uncheck both using codeata and including tests, and for the organization, just going to put my name all right, need to put it somewhere.
04:00 - 04:30 I'm going to put it on my desktop. And so we have a project that's been created. Okay, I'm going to ignore this warning. No, I think I'm going to need that. Force of habit. All right, so let me have a look. On the left, I have my iPad with a script, with everything I want to tell you. And since I don't want to forget anything, I'm going to regularly check that I'm indeed telling you everything I want to say.
04:30 - 05:00 So, first thing you're going to remark when you create a Swift UI project, except for the preview that started showing. But I don't want to show you the preview for now. I see a message in the chat. Let me show you the message. Hey, Vincent, I appreciate the stream. Do you have any good strategy for quickly wrapping my head about all the property wrappers, like app, storage environment and so on? So we will see these property wrappers, the main one, as it goes on. We're not going to start with them because
05:00 - 05:30 there are still things I want to speak about before we go into these property wrappers. But we will definitely talk about them at some point. But first, just for the very basics, I want you to notice that when you create a Swift UI app, you have two files are being created. A file with the name of your app that is in some way maybe kind of the same as the app delegate, or both the app delegate and the main file that you would find in the UI kit app. And then you have the content view, which is the first
05:30 - 06:00 view of your app, which is, once again, if we make an analogy, kind of like the UI view controller would be created by default in a UI kit app. So first, let's go into this content view file. So I hide it. But of course, one of the big features of Swift UI is the live preview. So to show it and to hide it into Xcode, you do Alt, command, Alt and Enter, or Command option enter.
06:00 - 06:30 You can call it Alt option. And so this is how you can show and hide the live preview. The big feature of the Live preview is that the Live Preview, as the name heavily suggests, shows you a live preview of your code. And we're going to see how we can leverage that. One thing I want you to notice, if you were accustomed to UI kit, is that in all the files that were created with the project, there is no trace
06:30 - 07:00 of exe of a storyboard or any of these interface interface files, these files that were specifically made to design interfaces, they are only Swift files. And our UI will be implemented entirely in code. Meaning that the UI you see in the Live preview, this here, this view is the entire source of truth for this UI. It's all defined in the code. There is no Storyball XML file, nothing like that. Now, it's entirely Swift, as the
07:00 - 07:30 name Swift UI suggested it. So if you look at this view, the first thing you might notice if you are accustomed to using UI kit is how there has been a big of a shift between the fact that in UI kit all the UI objects like UI view, UI view controller, they were classes, they were instance with their own lifecycles. But here the content view is abstract. I see Jarris saying you just arrived, so
07:30 - 08:00 you're on time, we are just getting started. And yes, the video will be available after the live using the same link. The replay will be available for free. Don't worry, if you need to leave, you will be able to catch up later. So content view is a struct. And this has a very important implication that is a big part of the field of your Swift UI, which is that the content view is a description of the view. By description of the view I mean that the content view describes what the view should look like,
08:00 - 08:30 but it is not the instance that actually has the side effect of displaying the view. Analogy you can make is with HTML, if you've done some web development. HTML is a language to describe what your web page looks like, but it's just a string. It's not the living object, the object that live in memory in your browser and that draws text, that draws images. It's not the HTML string.
08:30 - 09:00 And here is kind of the same ID. The struct that you define, that implements the view protocol is a description of your view. And then it is Swift UI's job with its private implementation to take this description of what your view looks like and to translate it into a visual representation. So to translate it into side effects that will ultimately write into the video memory of your iPhone, of your iPad. But what's interesting here is the world ultimately,
09:00 - 09:30 because the idea is to push these side effects as far as possible and to push them into the private implementation of Swift UI. This way, all the views that we define, they are only the description of what the view looks like. They are in functional term, pure functions, and we'll see that it will make it much easier to rezone about them, to test them, et cetera. Okay, you can also notice the keyword sum right here,
09:30 - 10:00 and we will go into detail about how it works a bit later, even though these days sum is much more used throughout Swift since the changes of Swift 5.7. So it's possible that you are actually more familiar with the keyword sum today than it would have been the case when Swift UI was released almost four years ago. Actually, Swift UI is four years is four years old, almost. Okay, first I want us to focus on this
10:00 - 10:30 protocol view that is implemented by our content view. First, I want to emphasize the word protocol because it's not a super class that you would subclass like you would with a subclass of UI view controller. Here view is a protocol that is implemented by a struct. So let's do a jump to definition to see what is inside the protocol. What's pretty good is that the entire initial
10:30 - 11:00 definition of the protocol fits inside my screen. So it's a rather short one, meaning that it will be hopefully easy to understand. And we can see, if we take a look, that a view is implemented by or implemented through recursive definition, meaning that what does it mean to be a view? It means to have a body. And what's the type of a body? It's another view.
11:00 - 11:30 So it kind of makes sense. If you've seen some Swift UI code, you have a body that contains maybe a V stack and the text, which are other views. So it's all based on this? It's all based on this. Basically it's a tree. Basically it's a tree. Swift UI views are described as a tree. And we will see that it has a big importance on how Swift UI works and how it manages to be performance.
11:30 - 12:00 So to understand what's a view, you just need to understand a view is something that provides a body and that body returns another view. Of course, it begs the question of when does the recursion end? And I plan to show you that as the last thing for today. So we'll go back to it a little bit later. Then you can see some other interesting not keywords, but annotations. So for instance, at viewbuilder, at main actor, so at
12:00 - 12:30 viewbuilder we will go into details about it a bit later because it's a topic that is specific to secure and that deserves a topic, an extension of its own. But at main Actor, I will cover it right now, maybe you're already familiar with it because actually if you've used asynco weight with UI kit, you might have used at main actor and admin actor means basically that this is a property that must be manipulated on the main thread.
12:30 - 13:00 So just like with UI kits, you can only touch swift UI stuff on the main thread. And so this annotation makes sure that if you call a body from a swift concurrency task, it will automatically switch to the main actor. All right, I'm checking, as I've told you everything I want regarding the view protocol. Yes, I have. All right, so I see some people are
13:00 - 13:30 struggling a little bit to understand me. So if it's a sun problem, I apologize. But since other people don't seem to have a sound problem, one thing I just want to say is that the live subtitles, if there are any on YouTube, are pretty bad. But for the replay, I will put good subtitles like I do for all my videos. So hopefully it might help if you are struggling a bit.
13:30 - 14:00 Okay, I went back to my content view, and I want to focus on the second strike that's been defined in this file. So content view underscore previews. So this is what implements the preview that you see on the right. So if I were to comment this line, the preview would no longer work. That makes sense because I'm not returning a view. But if I were to replace the content view with, for instance, an empty view, there would be nothing on the preview
14:00 - 14:30 because this is the thing that drives the preview. And so why is the preview a different truck than the view itself? It's basically so that we have a way to insert to inject initial data. Here we have a content view. That's very simple. There is no argument for the initializer of the content view, but when there are one, you need to provide them somehow for the preview. And so this is why the preview is a separate part.
14:30 - 15:00 Let's take a look at the protocol preview provider so we can see it's kind of similar to the view protocol because we have a previews property where we add a body and the previews as a type called previews, which is something that conforms to a view. The reason why it's plural is because you can have more than one preview being displayed. And so it hints to that fact.
15:00 - 15:30 The only big difference I want to highlight here between the body of a view and the previews of a preview is that the previews are static. That makes sense, because since the goal of a preview is to show your app, you can kind of see it as a side entry point into a part into a part of your app. And by definition, the entry point of your app has to be static because you need to be able to
15:30 - 16:00 call it just from when your app is launched without being in the context of your app. So that's the only difference between a view and the preview. We can see that there is this similarity and there is this pattern of you are a type that returns a body of something of the same type, and we will see that pattern happen a lot inside Swift UI. Did I say everything I wanted about preview provider?
16:00 - 16:30 Yes. So at this point, if you have any questions, once again, please feel free to ask them on the chat. As they come to mind. I will try to answer them as best as possible. Now I want us to move on to the second file that was created. So disco. It was supposed to be Discovering Swift UI app, but I mistyped and I wrote Discovering, which doesn't mean anything, but we notice if I try to change it, I will break the Excel project. So I will bear with it, and we will all bear with it.
16:30 - 17:00 So this is kind of the equivalent of both Jab delegates and the Main. Oh, I see, someone left a tip. So let me just see the name of the person so that I can say thank you. So, thank you, eness for the five coffee. That's super nice of you. Thanks a lot. And I'm super glad to see that this integration works, because it's super cool. Okay, so this is the main entry point of your app, kind of like going to your App delegate.
17:00 - 17:30 We'll see that it doesn't offer all the possibility of your App delegate, but you can also inject an app delegate. So that's the main entry point of your app. And I see another coffee being offered, so I want to francisco, I don't have time to see it, but thank you. And anyway, I will leave you a thank you note on Buy Me a Coffee. And you also got an automated shout out on my Twitter account once again, if I have configured everything correctly. So, what do I want to tell you about this file?
17:30 - 18:00 So, entry point of the app. You can see it with the annotation at Main. Interestingly, this annotation at Main was added with iOS 14. So Swift UI has been available since iOS 13. My advice is, if you need to support iOS 13, you will suffer a bit with Swift UI, because I personally consider it more as a public beta. Swift UI for iOS. 13. With 14, it starts to get better. And for instance, this admin was introduced only on iOS
18:00 - 18:30 14, which means that if you had created Swift UI project with Xcode back in the days of iOS 13, there would still have been a bit of UI kit code in order to initialize your app, because you couldn't have an entry point that was purely in Swift UI. Now it's the case. And so this is what allows iOS to know that. How do you launch the app? You launch it with this struct. All right.
18:30 - 19:00 We can see that there are a lot of similarities with the view we saw before, because we have a body also, except that this body is not some view, it is some scene. And scene here is used in a way that is very similar to what the scene delegates in UI kits also uses the world. So you can see the scene, for instance. I mean, for an iOS app, you will almost most of the time you will have only like one scene. But for instance, if you were to make a macOS
19:00 - 19:30 app, I think you would have a window group and maybe like another scene for the settings of your app, or for a side window, that kind of thing. But since we're going to talk mostly about iOS, you will see that scenes will be mostly a window group. Maybe on the iPad you could have more than one scene. Like if on the iPad you want to support external screens, for instance. But most of the time for simple apps, you will have only one scene. Just like for iOS apps, most of the time you have also only one scene.
19:30 - 20:00 So I'm looking at the questions. So you're saying why is the best place to make Star View with logo, et cetera? So if you want to customize the content, it will be in the content view. And we're going to do it just after. So let me see what I wanted to tell you more. So we have a window group, and in the window group, what's important is to see that we have our content view. So this is where our content view is created. And if we were to launch the app on the simulator, on an iPhone, the content view would
20:00 - 20:30 display, because it's being created right here. I want us to take a look at the window group type. So jump to definition. Let's take a look at it. So, window group, you can kind of see it as the equivalent of the UI window in the UI kit world, meaning that it's the window. So what displays the views of your app? I know it can feel a bit weird to talk about Windows on iOS because when you're on macOS, the windows are
20:30 - 21:00 very obvious because you can move them on the screen. On iOS, there are also Windows, but in most apps, there is only one window that is full screen. So that's why as a user, it feels a bit weird to talk about Windows. But still, your views needs to live somewhere and they live inside the window. So this is what makes the link between, like we could say the screen, the physical screen, and the views you define in your app. So what can we see in this window group?
21:00 - 21:30 We can see that it implements a protocol called scene. We're going to take a look at this protocol. It's the same scene that we saw in the fact that in our file, the body of the app would return some scene. And what's the scene we can see? It's kind of similar to let me rephrase it. It's kind of similar to the View protocol in the sense that a scene has a body and that body is also a scene.
21:30 - 22:00 So we also have a recursive definition which allows us to compose scenes together, even though for simple or like normal complexity iOS apps, it's not that needed. We are not going to use it anywhere in this live stream, but it was also in the whole series of live streams. What else do I want to show you?
22:00 - 22:30 If we scroll a little bit, we will see how Scene is similar to the scene delegate in UI kit. So I'm scrolling and here we are in an extension of scene. So not that one, I want another one. Which one do I want? Yes, that one. So it's an extension on scene introduced in iOS 14, and it introduces a method on change of unchanged of something called the scene phase. And the scene phase is whether you
22:30 - 23:00 are in foreground or in background. So if you want to react to your app going to the background or to the foreground in pure Swift UI, you would do it by adding this thing, which is called a modifier. We'll go into details of it a little bit later by adding this modifier on the scene window group. And the reason why I show you that is because it shows how the scene in Swift UI is kind of similar to the scene delegate in UI kit. Because in UI kit, this is in the scene delegate that you would respond to the
23:00 - 23:30 change of background to foreground before Syndrogate would have been in the app delegate. But if your app supports syndrogate, you would handle this in the scene delegate. Okay, that's all I wanted to tell you about the scene. Of course, you can go in much deeper if you look at the full documentation. That's not my goal here. My goal is just to give you like a layer of the land that you should know what every single keyword Identifier present on this file means.
23:30 - 24:00 But I don't want to go into the deep down details of them. And finally, we have one last protocol to go over. It's the protocol app. So what's an app? It's something that returns a scene. So it has a body, which is a scene. So once again, there is this similarity in the definition, with one big difference, is that for a view, the body was a view. For a scene, the body was a scene. But for an app, the body is a scene and not
24:00 - 24:30 an app itself, which means that you cannot compose apps together. Which kind of makes sense because that's not the goal. And the reason why we see this is because the app is really the top of the hierarchy in the eyes of Swift UI. I told you that you can represent Swift UI app as a tree. Well, the app is the root of that tree. And so that's why this protocol doesn't have a recursive definition. That's because the app is the top of the tree, and we'll see at the end of today's
24:30 - 25:00 livestream what the leaves of the tree are. One other thing interesting is that we can see that there is a second thing in that protocol, which is an init with no argument. So to define an app, you need to provide an init with no argument. It is mandatory and it makes sense because that in it is exactly what iOS will call to start your app. So at this point, there cannot be any arguments because iOS don't know anything about your app.
25:00 - 25:30 You just need to start it and it will do. So by calling this in, it that you could implement your own version if you need to, even though I haven't made the situation where I had to do it, but I'm sure there are some cases where it makes sense. But what I wanted to highlight is read the fact that you need to provide an init with no argument and the type of the body is not app itself. And so these two things they show you that read like, this is the entry point of your app in the eyes of iOS.
25:30 - 26:00 All right, I want to go back to this keyword sum that we saw here. So some scene in the case of the body of the app, or some view in the case of the body of a view. Why is this keyword important? So, a little bit of history. If you were using Swift in when was it, in 2019, you might remember that the keyword sum was introduced with Swift Five, I think, in February or March of 2019.
26:00 - 26:30 Back then, Swift UI still hadn't been announced. And this keyword felt a bit weird because the use case was not like, obvious. And I remember when people were trying to write articles, they would try to find use cases that kind of made sense. But to me, back then, I was like, this feels a bit weird. This feels that you don't have a really clear use case. But the use case became obvious when Swift UI was released because this keyword was probably created by having in mind the problems that Swift UI would need to be
26:30 - 27:00 solved in Swift in order to work. So why do we need the keyword sum? Let's remove it and see what happens. We get some errors. So I'm going to mask the preview so that we can see the errors a little bit better. So we see type content view does not count. Protocol view, right? And use of protocol view as a type must be written using any view. So back then, any didn't exist. So actually, if I were to use any, it
27:00 - 27:30 wouldn't work because the protocol requires some view. But the fact is that you cannot write view by itself here, you just can't. And the reason is that view has an associated type. So the rules have changed with Swift 5.7 about this, but before it used to be that a type that protocol that had associated types could not be used to type a return value. It just wasn't possible.
27:30 - 28:00 Now we can do it with any, but back then it wasn't possible. And anyway, any wouldn't be right in terms of performance. So basically Swift UI needs to know the return type of the view and it also needs to know that it returns a view. But Swift UI kind of like doesn't care about the exact type, it just needs to know that there is only one possible type that will be returned and that's what the keyword sum does. Sum.
28:00 - 28:30 You can kind of see it actually, if I were to write this so body view and then here return the body, this is kind of the same thing than using some view. Some view you can see it as like of course it doesn't build because the protocol expects some view, but conceptually this is kind of the same thing. And some view you can see it as how
28:30 - 29:00 should I call it, an anonymous generic argument, meaning that the compiler knows about it, but you cannot reuse it anywhere else in your code. And it works very well in the case of the body because we will see that the type of this is actually a bit complex, we'll see it just after, but we don't need to know about it. All we need to know is that the body returns some view. So when you see some view, it means that there is an actual type behind this, the compiler knows about
29:00 - 29:30 it, the compiler can reason about it, but we don't need to care about it as the developer, we just put it into an opaque thing, into an opaque container and we manipulate it through that opaque container. And that's why the feature that introduced the sum keyword to Swift was actually called opaque types. That's because we don't know the type that is inside some view, we just know that this type does exist and that
29:30 - 30:00 it is always the same every time we call the body. So I think I have some experiments with the code to make this feel a little bit clearer. So let's see, first, let's see the consequences of having some view. Like I said, having some view. It means that there is one type that will always be the same for the body, even though we don't need to worry about what is this actual type and spoiler, it's a
30:00 - 30:30 big type with a lot of generic arguments. And to show you that, I'm going to make a little experiment. So I'm going to draw a random boolean and I'm going to say, all right, if this boolean is true, then I'm going to return as my view a text with Hello World. So just like we had before. And if that boolean is false, then I will just return a spinner. For instance.
30:30 - 31:00 A loading spinner, which is a progress view in Swift UI. The reason why I do bool random is that is because the compiler cannot, by the very definition of bull random, know what the value will be at compile time. The result of this if is purely at runtime. And we see we have an error that says function declares an opaque return type some view. So that's the name of the feature opaque return type. But the return statements in this body
31:00 - 31:30 do not have matching underlying types. What does that last part mean? It means that not all branches of the if statements return the same thing. Here I return a text, which is a type of view. Here a progress view, which is another type of view, but they are not the same type. And so the compiler is not happy about it, because for the compiler there is not a single type that is known at compile time. Of course, it might feel that this lacks a bit
31:30 - 32:00 of flexibility, we see that there are ways around it. But what is really important here is that the fact that the type is always the same and is always known at computation is really one of the things that Swift UI uses to build its performance. Because remember I told you earlier that our Swift UI apps can be seen as trees with first at the top, the app, then the scenes, and then the views. And the way Swift UI knows that something changed
32:00 - 32:30 in the UI is by comparing the new version of that tree with the previous one. When you change a variable that is marked with at state, for instance, and we'll see what it is just after in detail, the tree has changed and Swift UI compares the previous tree with the new tree and it knows which view to update. That way, if you've studied some tree algorithms, you might know that comparing two trees is actually quite a costly process. And it's not something that would work very well to update a UI, especially when the tree is very big.
32:30 - 33:00 Because the Swift UI app can be very big, we'll see that the types grow very fast. However, there is one situation where comparing two trees can be quite efficient. It's when the two trees always have the same structure. And this is what some view actually enforces. It enforces the fact that the types that compose the tree that is a Swift UI app are always the same.
33:00 - 33:30 Once the app has been compiled, they never change at runtime. And so this kind of limitation, but I don't want the limitation, I would rather say trade off is one of the key things, the key ideas behind the performance of Swift UI. And that's why if we were to use the any keyword that was added later, first, once again, it wouldn't work because the protocol expects some view and the reason why they didn't
33:30 - 34:00 make it work with any view is because if you have any view, then you lose that file. The compiler knows at compile time what is the actual type with any view, you can see that that's very interesting. You can see that with any view, the body now builds. So I am allowed to return two different types. However, since there is no longer a single type at compile time, the compiler cannot reason about it. And so the optimization that Swift UI relies on wouldn't work. And that's why it only works with the keyword sum.
34:00 - 34:30 So I think I'm going to stop there for the keyword sum. If you want to learn about it in more details, you can read about opaque return types and then more generally, the way generics the way modern generics works work with the changes in Swift 5.7. Safe to say that some view is one of the key cornerstone of Swift UI.
34:30 - 35:00 All right, so I've shown you this example, all right? Oh, yes. Something very interesting is that if I go back to the code I had, so I showed you that here we have a computation error. What will be super weird is that if I remove the return keyword, you will see that the error disappears. That's super weird, isn't it? And the reason is that this is caused by the annotation at view builder that we saw before.
35:00 - 35:30 And I will tell you a little bit more about it. The reason why I'm mentioning it now is because if you are following along, it's possible that you haven't written the written keywords and you are wondering why does it work for me? It doesn't work for him. That's because this code is actually very different. It goes through a very different path than the one with the return keywords. But I will tell you a bit more about it just after. Before, I want to show you one last thing around the type system and Swift UI.
35:30 - 36:00 And I want to show you what is actually the type of the body of the content view. So what I'm going to do is go here in this code right here. So here I have my view window being created. I'm going to add an on appear so. No, on my view, I'm going to add on appear so. This is a closure that will be
36:00 - 36:30 called when the view is displayed. I'm just using it because I want a place where I can write color that will be executed. So what I'm doing is not a good practice at all. It's just like when you write a print statement in Europe. Delegate in application did finish launching with option. I'm doing the same thing. What I want to do is to print the type of content view body. So I'm creating another I don't want to
36:30 - 37:00 see the word instance, I'm creating another value that is of type content view. The reason why I'm not using the reason why I'm not using the word instance is because it's not an instance, it's a struct, not a class. And I can create it actually just about anywhere. You could absolutely create a content view somewhere, store it and do nothing with it. It wouldn't have any side effect because remember, content view is only the description of the view and it has an effect when you feed it to Swift UI so it can display it on the screen.
37:00 - 37:30 But here in this context, content view is just another Swift struct. And it's not that different than a struct you would define. That could, for instance, represent a user, an address, an int. Actually, an int is also a struct, so it's not that different in that context. The content view has no side effect on the UI. And so I'm using typeoff which returns the type of something in Swift, and I'm printing that to the console. So I'm going to run the app in the simulator for it to be executed, and we'll see
37:30 - 38:00 what is the type of the body. So the simulator is starting, you can see it's. All right, let me put it behind because I'm interested only in this. So I'm going to go here. So this right here is the type
38:00 - 38:30 that corresponds to this body right here. So everything you see here, everything I have selected, is the type that is hidden behind some view. So you understand why some view is important. It's because if there wasn't some view, if it didn't exist, you would quite literally need to write this and you would need to change it every time you change something inside your body.
38:30 - 39:00 So of course it wouldn't scale at all. Swift UI wouldn't be usable. You might see it doesn't build it's because it's using things that are internal, that are private to Swift UI. And so of course it doesn't build. And so this is the complexity that some view hides from you. And the way it works is that since all of this is known at compile time, swift UI knows that Swift UI, and even the Swift compiler knows this type at compile time, and it hides it behind some view.
39:00 - 39:30 So when I was telling you that some view is a cornerstone of Swift UI, it wasn't just a figure of speech, is that if you remove some view, swift UI becomes unusable. Like you end up with this kind of crazy syntax that maybe reminds you of things like templates in C plus plus, the kind of thing that you definitely don't want to have to deal with unless you are forced to. And yeah, while you were saying it makes sense that content view, like I said, you can use it. And since it is a value type, you can use it like you
39:30 - 40:00 want, as long as it's not in the context of Swift UI. It's just a value like any other. And so let's just try to match things. So at the top level, we have modified content. So it's the result actually of calling this Padding method, because you can see modified content. There is everything inside here and then a Padding layout which corresponds to this. So when we call these kind of methods, which are called modifiers by Swift UI, these methods, you call them
40:00 - 40:30 on a view and they return another view. You can see here, Padding, you call it on a view and it returns some view. And what it does is that it actually creates types, generic types, that are more and more and more complex. However, in their complexity, they encode the entire description of what the body is. And this statching, this encapsulation of types, is actually
40:30 - 41:00 the tree structure I was referring to because all of these types, they refer to one each other. And when you draw it out, it defines a tree hierarchy. And so this is the actual tree that represents your Swift UI view. When you hear people talking about that, this is what they mean. And so you can see we have the Vstack, then we have a Tuple view that contains our two views. So these two views, image on the one hand and text on the other hand, they are put together in Tuple View.
41:00 - 41:30 How are they put together in the Tuple view? This is where View Builder comes into play, and we'll talk about it just a little bit after. Then we have two modified content. That's because we call two modifiers on the image, image scale and foreground color. We have something called environment keywriting modifier. That's because of the way the accent color works. And then we have the text here. And since we don't call any modifier on the text, it's
41:30 - 42:00 just a type text, there is nothing else attached to it. So this really shows you the importance and the power of some view. And I really like showing this because it shows also that there is no magic in Swift UI. When you use Swift UI for the first time, it might feel a little bit like magic, which is both a good thing because it makes you want to use it, but a bad thing because when something feels like magic, it's also because you don't fully understand it. And that's one of the goals for this first part of
42:00 - 42:30 the training course, is to really explain what is behind the magic of Swift UI so that you feel much more capable of debugging around it when you need it. It's not magic, it's just computer science. And we can understand it if we just focus on the problem. All right, what else do I want? I think I told you everything I wanted. So it's time to talk about View Builder.
42:30 - 43:00 What is view builder? So Viewbuilder is an instance of what Swift calls result builders. At the very beginning, they were even called function builders. So if you watch the very original sessions about Swift UI ADWD, you might hear about function builders, but the final name is a View Builder is a Result Builder. Sorry, and what are result Builders? They are a tool that was added to Swift to build what is called a DSL.
43:00 - 43:30 So domain specific language. So kind of like a small language defined in Swift and that is very focused on solving a specific problem. Here View Builder is focused on solving the problem of how do you easily compose views together. Because now these days, we are kind of used Swift UI. So like this feels kind of normal. But the first time Swift UI was announced and actually I was lucky enough to be in the room at
43:30 - 44:00 WC when it was announced in 2019, when they showed the first Swift UI goal, which kind of looked like this, my first thinking was here we have two things. So we have a collection in a way, but it's not put inside of an array, it's not put inside of Tuple either. So how do these two separate views, the image and the text, how are they put together into
44:00 - 44:30 a structure that basically allows you to reason about them like some kind of collection? And this is what view builder does. So that's why you don't need to worry about writing arrays, writing Tuples. When you define the body of a view, it feels like everything is put together by magic. But remember, there is no magic. And this is actually what the ad View Builder annotation does. So if you want to take a look at what View Builder is, you can take a look at it. It's just a type. So I did command shift O and then
44:30 - 45:00 typed in View Builder so we can see it's a struct annotated with add Result Builder. And I'm trying to find the best way to explain what Result Builder is. I'm going to first explain how it works and then I will try to make a definition. But I think it'd be better if first I explain how it works. So you can see there are some methods defined inside our View Builder and they are all static. This is important because View Builder, it
45:00 - 45:30 is kind of called by the compiler to understand how to organize our code. So just like the previews had to be static because they were called by Xcode, same thing, everything must be static in the View Builder because it's being called at compile time and it's not part of any lifecycle. So we have a first thing called build block. So the name of the method is the convention in the View Builder and it returns an empty view. And it means that if here I were to put nothing in
45:30 - 46:00 the Vstack, or even better, if I were to put nothing in my body, let's see in the body, I need to iterate on something for one reason, which I will go about after. But let's take a look at the Vstack, the Vstack, you can see the Vstack has an initializer which takes a closure annotated with add View Builder and it returns a Tuple view.
46:00 - 46:30 If I put nothing in my V stack, it builds even though that closure is supposed to return something. So remember, there is no magic. Something is returned somewhere and what is returned is that actually since the closure that we pass in to the V stack, to the init of the V stack, let me show it back again. I want to show it back again, the initial V stack. Okay, since it takes a closure, that closure is not a two with Adubuilder and you can see
46:30 - 47:00 Adju Builder as kind of like a small processor, a small compiler that will take the content of the closure and that will organize it. That's the best way to define it. It's a preprocessor, a small compiler that will organize the content of the closure. And so here, since the closure is empty, the compiler will call the method build block with nothing because there are no blocks inside the closure and
47:00 - 47:30 it will return an empty view. And this is why if you put nothing here, it's the same thing as if you had put an empty view because viewbuilder will take care of returning that empty view. Now what happens when there are actual views? In that case, you can see that here there is a method that says okay, if there is some content I will return something. And this was being called when there is only one view. So that's not super useful. But if we scroll a bit we can see that there is a build block with queue views and it takes the
47:30 - 48:00 queue views and puts them into a Tuple view. Remember we saw that when we did the print typeoff. Actually it's still here in the console. We do have a Tuple view, our image and our text are inside view and we were wondering how were they put inside the top of you? Even though we didn't use Tuple view anywhere, this is where it happened. The build block method that takes two arguments, two views as arguments was called by the compiler and
48:00 - 48:30 that's how the two views redefined the image and the text were put in the Tuple view. We can see that there are overloads being defined of build block up to, I think it's ten generic arguments. So this means that actually if you take your Vstack, so for now there are two views, now there are four, it still builds six, eight, okay, still builds.
48:30 - 49:00 Now there are ten still bills. But if I were to put an 11th view bill failed, interesting. First I will put a string just so there is no like false positive. So it fails. And if you're new to Swift UI and you put a lot of views in your V stack and you get this error, it's going to be really confusing because the error says extra argument in call. It feels so weird because it's not an extra argument
49:00 - 49:30 to the call of the initial text because here we have one that works perfectly fine and it's actually an extra argument to the call of this method. Or right here it's trying to call the overload with ten arguments, but since there are eleven, it cannot find anywhere to pass in the last one. And so it gives you this error message, which is a terrible error message because if you don't already know what the root cause is, it doesn't help you understanding the root cause. But now you know that the root cause for such an
49:30 - 50:00 error message is that you cannot pass in more than eleven views to a closure annotated with Ad View Builder. It would be the same thing for a body annotated with Ad View Builder. So yeah, you definitely don't expect it and it can be so confusing. So that's why I really want it is something I want to talk about in the first live stream and you understand why I figured it was so important to focus on these aspects before we dive in into Swift UI.
50:00 - 50:30 So you might be thinking, but that's very limiting if we cannot put more than ten elements inside of a Swift UI view. And of course there is a trick around it and it's the fact that we are allowed to group our elements. So we just need to put our elements into a bigger like group and it works. So for instance, we could put our elements here in a Vstack, so we put the ten first inside a Vstack and it works.
50:30 - 51:00 Now it builds. Of course this change wasn't neutral because V stack has an impact in terms of the plantation logic, but we could just put them in a group and the group, it's a container that has absolutely no side effect or nothing, no impact on the layout, nothing. It's just a purely logical container. And by using group you are able to overcome this limit of ten arguments that you can pass in to this limit
51:00 - 51:30 of ten sub views inside a Swift UI view. And yeah, like you said, Joe, it's a terrible error message. Like the error message you get around result builders, they are kind of terrible. But there is a reason why. It's like I told you, you can kind of see a result builder as a small compiler and so you basically have a small compiler that's not working well. And when you understand the complexity behind the result builder, it kind of helps you understand why the error message is bad.
51:30 - 52:00 But it's not an excuse. Honestly, every time I do this training, because I already did session with this training material in France last year, every time I hope the message will get better, but every time it doesn't get better, unfortunately. Okay, I'm going to put the code back to how it was before I started tinkering with adding a lot of views. What else do I want to show you? Oh yes, before we go see what Scene Builder looks like, I
52:00 - 52:30 want to show you a few methods that we are above. You can see here above all the build block. We have build if. And this is what will allow us to write if statements inside the closures annotated with view builders. Because we can write if statements and they are somehow translated into a type, which is called a conditional view. If I remember or control content. And it works because actually it's not an if that is
52:30 - 53:00 fed into Swift UI, the if is transformed and if the if is true, then that content will be returned swift UI. So it's even better when you look at build easier. So build is there. It's when you write if else if the condition in if is true, then you have the true content. So it's the content that is inside the if close and then you have the build is a false content
53:00 - 53:30 and is the content that is in the else close. And so this is thanks to these two methods that an if else statement written inside the body of a view, for instance, get translated into a view that encapsulate this logic of we need to do a test and switch one view for another. And if you remember, when I was doing my little tests at the beginning, I was telling you that if we do if bull random, so let me write it
53:30 - 54:00 correctly and we use the return keyword. So like that here we have an error, the error we saw last time. However, when we removed the return keyword, it worked. And the reason was that when we used the return keyword, we specifically opted out from using the view builder, but without the return
54:00 - 54:30 keyword, it uses the view builder. And so this if else here gets translated into calls to the build either first content and build either second content. And so this is why in that case, it works. It's because now there is actually a single return type for my body. It's because this if else has been translated into a view that encapsulates the fact that there is
54:30 - 55:00 a condition that must be evaluated at runtime and that could result in either a view being rendered or another view being rendered. So Swift UI can still make a single type from the fact that we still have curator types. Of course, this comes with some performance implications, but this is the explanation to this weird behavior that we saw earlier. And so one last thing I wanted to show you here
55:00 - 55:30 is the fact that when we saw the protocol view, we saw that the body was outdated with at view builder. And if we go back to the protocol scene, maybe I didn't emphasize it a lot actually, but here the body is notated with at scene builder and not at view builder. And the reason is that, as you can imagine, there is a difference, otherwise there wouldn't be two separate result builders. And so if we look at scene
55:30 - 56:00 builder, so it's another result builder, but we can notice a few interesting things. For instance, we don't have the build block with no argument. That means that if we try in our app to put nothing in the window group, so here actually it works here because when we are in a scene, oh yes, it's because the window group here actually it's a view.
56:00 - 56:30 So the scene return is at this level here. So if I put nothing here, I get an error. And the reason is that whereas we had the build block with no argument that return an empty view, for view builder, we have no equivalent for scene builder and so there is nothing to magically introduce a result value, so we get an error as it should be. And the reason why there is this difference is that whereas it kind of makes sense to have an empty
56:30 - 57:00 view because maybe you have an if inside of it. And when the if is false, you just don't want to provide an else closed, you just want to provide nothing. So it can make sense to have an empty view. However, having an empty scene kind of don't make sense a scene you've seen, that is things like a window, a system, a preference settings panel, so having it be empty doesn't make sense. The compiler and the Swift UI team don't want us to mistakenly create an empty scene and so
57:00 - 57:30 the way they do it is by not providing the build block with no argument inside the method inside the result builder, scene builder. Let me go back to it and one last thing I want to show you is that you can see we have build block with one argument, so then with all the arguments up to ten. But you might notice there is one thing that isn't here, it's the build easier that
57:30 - 58:00 allowed us to implement an if else. And that means that if else are also forbidden at the scene level. The reason for it, and it's only me inferring it, I'm not sure what is the actual reason, but it's because I told you that if else has an impact in the performance, actually. And so Swift UI don't want to allow if else at the scene level. Swift UI wants to have the tree of available scenes be always the same, there is no way to switch it at runtime.
58:00 - 58:30 And so that's why you don't have a way to use an if else. When you're defining the body of a scene, that means that for instance, you would need to still define a second window and then if it's not used, you use a modifier to hide it, but you wouldn't have a window appear out of nowhere without Swift UI knowing knowing about it. It's a bit of a detail. I don't think that to write like, iOS apps you will use it a lot.
58:30 - 59:00 But I feel like it's interesting to have this knowledge of how these things work together, how they are defined, what are their edge cases, what are the trade offs that have been made by Swift UI team in order to have a framework like Swiftly that is both very easy to use but also very performance? I'm going to stop here for this first part. It's not the end of the live. There is a second part for this live, so don't leave. I'm going to stop here for this first part that
59:00 - 59:30 was based around just going over what's the content of a Swift UI project when you create it. What I really want you to take away from this is that the key parts, the cornerstones of Swift UI, they are the protocols View, Scene and App. And when you develop an US app, you will mostly focus on View. Actually, that these three protocols, they
59:30 - 60:00 actually define a tree structure. That is how Swift UI can track the state of our app and we will see how it works in better details after. We've also seen that there are some features of Swift that are actually like key to Swift UI working correctly and working as we know it. And these two features are first, the Opaque return types. So with the sum view here, that allows us to hide
60:00 - 60:30 the complexity of a very big and ugly generic type. And finally the result. Builders with view builder and scene builder. Once again, when you make iOS apps, you will mostly work with View Builder that allow us to write a syntax to use a domain specific language to compose views together. And so it allows us to define views in a way where we don't need to write the
60:30 - 61:00 syntax on how the views will be composed. You see, here we have no array. We have no tuple. The result builder takes care of taking the individual building blocks and grouping them into some structure that makes sense for Swift UI. I'm putting the project back to like it was when I created it. This way everything is clean and I will not fall into a mistake where I don't understand what is happening. And we can move on to the second chapter, which
61:00 - 61:30 will be to discover the components of Swift UI. For this first hour, I focus more on the structure of a Swift UI app. Now we're going to talk about the actual components that we can use in Swift UI views. This would last for about an hour, I think between 1 hour and 1 hour and a half. And after that, I think you will have gotten a good understanding of how a Swift UI app works and you will
61:30 - 62:00 be ready for the next live streams where we will go. Into more details. Okay, for me, in front, it's the end of the day and sometimes maybe you can notice that I get a bit tired when I start to lose my way around the sentence. So let's go on the view that we have here and let's try to focus on what we show in this view
62:00 - 62:30 and first I want to show the live preview but we can see the result of the changes I'm going to make. I'm going to move it a bit because if I'm over the live preview, it's not super useful and so for the modifier, going to do it that way yes, much better. We can call modifiers on our text. So like I told you just before, modifiers, they are these methods we can call on a view and it return a
62:30 - 63:00 new view but that in the process of doing that, I've added a new not behavior, but a new attribute. We could say to the view that attributes being everything from the font of a text or a closure that must be executed when the view gets displayed. So what kind of modifier can we call on a text? For instance, we can call a modifier like foreground
63:00 - 63:30 color to change the foreground color you can see that the view yes, because text is a view, the text has become now red. But we could also change other things. For instance, we could change maybe the alignment. So let's put it like trading, it doesn't change anything. That's because it's the multiline text alignment. You need to have at least two lines for it to work.
63:30 - 64:00 That's not a problem, can just add a second line, says it's me. You can see with the modifier now the text is aligned in a straddling manner I can change it to leading. What else can we do? We could also change, for instance, the font of the text but for that we don't necessarily need to write code. We can also use the inspector on the right in Xcode because you can see that we have here some possible modifiers.
64:00 - 64:30 So this kind of looks like what you would have with a storyboard, except that there is a big difference is that when you change something so for instance, if you change the font to title, you can see that it added a line in the code. So like I told you, there is no hidden interface file like a storyboard or exe. The only source of proof for the UI is the code right here. And so this inspector is just a shortcut to create modifiers to add them or to remove them
64:30 - 65:00 through a UI rather than writing them. So when you are used to writing suspicion code, most of the time you don't actually use this inspector. However, when you're working either with a new component or like you haven't used a component in some time, it can be actually quite useful to use it. Just like if you don't remember the name of a modifier, it can be quite useful. It can also have an interest in the sense that it can help non developer person experiment with
65:00 - 65:30 the UI or try to change a few things. And it can be useful. Like for instance, if you have designers that want to try a few things to see what works the best on the actual view on the device, they can use it. Same thing for Project Manager that could give it a try. So there is some value in it, even though I can tell you that as a developer that uses Swift UI daily at some period of time at work, I never really used it a lot,
65:30 - 66:00 but it's kind of nice for it to be there. And I really wanted to show it to you to show you that there is nothing hidden. Everything is in the code and it's just a shortcut for writing the modifier yourself. What else do I want to show you? By default, text supports dynamic types, the fact that the user can set in the preferences what should be the size of the text, and you can actually simulate dynamic type in the preview you see like that in the
66:00 - 66:30 live preview, you can change it. So it's kind of nice to be able to test that everything is working well. You can also force a color scheme like the dark mode, and I will do so because this way I will take less light in my eyes. You can also force an orientation, even though landscape orientation is less popular these days on iOS. But if your app supports it, you can test it quite easily that way. So previews are really like one of the super useful tools when you make Swift choice.
66:30 - 67:00 I'm seeing a few messages in the chat that I hadn't seen. So you were saying yes, somebody could spend some time figuring out that error. So yeah, we are seeing that some errors are terrible and you're saying Yamun, I hope I'm saying it correctly. You find amazing for building details such as a gauge, but for doing database drill downs, you must admit you prefer UI kits. Great thing is that we will see in few livestream that it's very easy to put the two together. And I did that a lot at work and it worked very well.
67:00 - 67:30 I was quite happily surprised about it. But what you say hint to a point that I want to make across this training course and that Swift UI is a tool and you should use it when it makes sense. But it's not because you know about Swift UI that you should go and do everything in Swift UI. It's a tool, it makes sense to use it when it helps and when it doesn't help, or when it brings more complexity than anything else.
67:30 - 68:00 You can still use UI kit. UI kit still works very well and UI kit still isn't going anywhere for the near future. So that's a very good remark, thank you for making it. What else do I want to show you? I want to show you the fact that also the text that you provide here is localized. You don't need to explicitly call something for it to be localized. So what I'm going to do is I'm going to add a strings file.
68:00 - 68:30 So I call it actually, I shouldn't have removed the default name because localizable is what I wanted. And so in this file if for instance, I write so key like hello title, and then for the value, I put in this value right here and I don't forget the semicolon, then if I use the key.
68:30 - 69:00 So here I use hello title. As you can see, the key gets automatically localized. So when you pass in a string to text, text will automatically look into your localizable string to see if there isn't a localized version of the key that's ready to be used. And if you want to opt out of this behavior,
69:00 - 69:30 you can by calling an init that has an external name for the argument that name is verbatim. And as the name suggests, it will print that string verbatim without going through the process of trying to localize it. That can be useful sometime if you know that you absolutely don't want the string to be localized. But most of the time you're going to use that pattern of you just pass in the key. That might be generated by some typesafe
69:30 - 70:00 wrappers like Swift Gen for instance. And then Swift UI takes care of localizing it. So you don't need to do like you would do in Uiki to call Nslocalized string. Before you set the text of a UI level here, it's being made automatically for you. I want to show you also some cool APIs that you can use. For instance, you have formatters that are embedded into text. So for instance, if I want to display a
70:00 - 70:30 text that will say what is the current time? So like that I can create a text, I pass it a date object, so the current time. And then I pass it a style which will be time. And you can see it automatically formatted the time according to the local that's set in the preview. And here the preview must be us because it's showing it in AMPM format.
70:30 - 71:00 What's great is that when it's actually like what you need and you don't need more control, you can use this. And it's much easier than introducing a date formatter. Just remember, this API here was introduced in iOS 14. So if you have to support iOS 13, you can't use it. That's one of the reason why I was telling you that doing Swift UI on iOS 13, there are a lot of nice things that are not there, plus a few bugs.
71:00 - 71:30 So that's one of the reason why I was saying I would advise to consider using swiftly in production from iOS 14 and up. If it's 15, it's even better, but from 14, it can be done. Like last year, I worked on an app that had supported iOS 14 and Swift UI. I mean, we were able to leverage it in an efficient way, but with iOS 13, you miss out on a lot of things, including this kind of nice APIs.
71:30 - 72:00 And you're saying so far I enjoyed a more in depth look than what is usually available on YouTube. Great content. Thank you. That was definitely like my goal with this live stream series. And I also did another live Stream in August, so you can find the replay on the channel where I was just doing one of the tutorials by Apple. That is an intro to Swift UI made by Apple. But that also does a good job at going in depth. So if you want to check it out after maybe a few things, I will have already said them, but a few, I think it would be kind of complementary.
72:00 - 72:30 So it might be useful if you like this approach. But I'm glad to see that you're enjoying this approach. Okay, what else I want to show you? Oh, yes, another nice modifier is the redacted modifier. So, like that because it allows, you see now we have like a square over the text and it allows you to easily turn a text into a placeholder. So if you want to make like a loading view, you do that with some example, with some
72:30 - 73:00 mocks, and then you add a nice shimmering effect over it and you can make some beautiful loading view quite easily with just like this redacted modifier. And once again, it's something that was introduced with iOS 14. Okay, let's try and see another viewing Swift UI. So there are lots of views, but I had to make a choice and I chose to focus on text field. Actually.
73:00 - 73:30 Yeah, on text field because text field, it start to introduce a data flow because text field, the user is going to input some text into it. You need to store it somewhere. That's why I wanted to focus on text field. So I'm going to put it just after. So I'm going to create a text field. So you will see we have a lot already, a lot of initializers that's because there are a lot of situations and combination you might want to use.
73:30 - 74:00 I'm going to go with the most simple one. So just a title and a text. So title is pretty self explanatory. It's what will be the title of the text field. So here it will be, for instance, what's your name? The go with text field being to write for the user to write his or her name. And for the text we see we have a binding of a string.
74:00 - 74:30 And this is when we start to talk about data flow in Swift UI. So let's think about how this text field works. This text field. And you're saying the amount of work you have to do for placeholders. Yeah, that's one of the nice features of Swift UI. That's one of the things that we are kind of annoying to do in UI kit. And it became like super easy in Swift UI just because they added this one modifier. So the text field, the text field
74:30 - 75:00 is going to update a value. That value will be stored inside the view because for now, we don't have another place to store it. So it could be like VAR, for instance. We can declare VAR. We can declare a property because we are in a stripe. So I could call it username. It would be a string. It would have a default value of the empty string. But then how do I do the link between the two? This binding here means that a binding
75:00 - 75:30 is just a gator and a setter. So the text field wants to be able to read the Q and value of the username, but it also wants to be able to write back to it. So we could imagine something like just passing the username or maybe passing a keypath to the username. It could work the keypath in theory. But we want one extra thing. We want Swift UI to redraw the UI whenever the username has changed and to tell Swift UI that when the value
75:30 - 76:00 of a property changes, the UI needs to be redrawn. We use a property wrapper called at state. So if you've seen some situation code, you've probably seen at state because it's usually what is shown in the first examples. And at state it's a property wrapper. So one of the features introduced with Swift 5.1 and one of the missing cornerstones of
76:00 - 76:30 Swiftweight I hadn't mentioned, the last one I hadn't mentioned is property wrapper. And the property wrapper, as the name suggests, it wraps a property and it wraps it around a layer of logic. If you have the time, I would encourage you to read the Swift Evolution proposal about property wrappers because they describe what was the motivation for introducing property wrappers to Swift. And I think they do a very great job of explaining it. They do a better job than what I could ever
76:30 - 77:00 do during a live stream where I kind of improvise my explanation and I will answer the question just after because we have a very interesting question. But here the atstate property wrapper. It basically wraps the property in a piece of logic that says whenever a new value is set, I will let Swift UI know that the UI needs to be redrawn. You can understand it like that for now.
77:00 - 77:30 And indeed, from what has been shared, this is backed by Combine as one of the reason why Combine was released at the same time then Swift UI was released. But we have a state. How do we get a binding. First, let's focus on the relationship between state and binding state. When you have add state, it means this
77:30 - 78:00 is the source of truth for this value. So this value has to be stored somewhere, it is stored here and this is the source of truth. A binding. You can kind of see it as a view on that state. I don't want to say a pointer because it's not a pointer. It's a view to that state that allows you to read and write to that state in a way that will still trigger all of the lifecycle of Wind to read all the UI. However, the view that owns the binding doesn't
78:00 - 78:30 own the value, it's the view that has the ad state that owns the value. So at state will be owned by a parent view and the parent view will pass a binding to a child view that will allow it to interact with the view. And so this at state binding system allows us to implement a parent child data flow. And how do you get a binding from an atstate property?
78:30 - 79:00 You do it by prefixing it with dollar. It might feel a bit magical to see that. And it's because it's a convention actually of I'm going to put it back in light mode because I feel like it will be more readable for people watching the video. Why this dollar sign? It's because it's a convention that a property wrapper implements two things. The wrapped value that implements the logic and the
79:00 - 79:30 convention is that whenever you use property username you actually use the wrapped value of the property wrapper. And it can also implement a projected value that you access by prefixing it with the dollar sign. So this dollar sign, it's purely a convention. Don't try to wonder like what does it mean, what's the meaning of it? There is no real meaning. It's just that they needed a character to give a shortcut to accessing the projected value.
79:30 - 80:00 Because if you were to do like every time dot projected value, it wouldn't be that great. So they put a dollar sign and that's just a shortcut, nothing more to it. It's just like wondering why do we do like command s and not another combination to save that's? Because it's the shortcut, it's the same kind of ID. And so this returns a binding. And by doing that we have implemented a data flow between a parent view, which is our content view, and the child view which is a text view. And data can communicate both ways because through
80:00 - 80:30 the binding the text field can get the QN value when there is a new value. So when you write, you start writing. Then for each character, a new string is set in the estate property once again through the binding. Since the property is at state, Swift UI notices swift UI notices the change and updates DUI. And that's how after I have typed every character DUI
80:30 - 81:00 has been redone to reflect the fact that I have typed a new character into my text field. And so that's why I wanted to show you the text field because even though it feels very simple, even though it's very simple, it actually lays the ground for all the more complex data flow we will see after. And when you think about it, it's still a complete data flow in the sense that we have the full
81:00 - 81:30 circle of the child view, reads the current value, then updates it in the parent, the parent redoes the UI, et cetera, et cetera, et cetera. So here you have in a nutshell the way that basic data flow works in Swift UI. I wanted to show you a few more things about binding. So just like before, we're going to see how it is implemented. So this is the property wrapper binding.
81:30 - 82:00 That's not the one I want. I want another yes, I want that one. So it's still a property wrapper, but since it's a struct, you can also create it like another type. So we've seen that when we used binding it was just an argument like that. It was not add binding. We see that we can also annotate a value with add binding. But here that was not the case for the unit. We are just passing a binding. And so a binding, it has an init
82:00 - 82:30 that takes a getter and a setter. So the getter returns the current value. The setter lets you set a new value when you generate a binding by doing dollar username like I did, these gator and setters are automatically generated for you by Swift UI. But you could actually create a binding from nothing just by creating your own gator and setter. I think we'll do that at some point later in one of the upcoming live streams.
82:30 - 83:00 And really I want to demystify what a binding is. It's nothing more than what you see a getter and a setter. And there is a notion of a transaction when there is animations involved but you can just abstract that for now, a binding is just this, it's something to which you give a gator and a setter and nothing more. And you can see here an interesting static function which is called constant returns a binding. And this function has actually, if you are like watching the replay, maybe it's a good
83:00 - 83:30 time to make a little pause and try to wonder what this function constant is about. Because normally you should have all the knowledge to try and make the answer for yourself. So just try to reason about it for 1 minute to see if you can make sense of it. But the answer is that this is a way to create a binding that will return a constant value, meaning that the getter will always return the constant value we provide and the setter will just do nothing.
83:30 - 84:00 Why could this be useful this can be useful. For instance, if we want to create a preview, a preview of a view that expects a binding, how can we do that? Let's imagine we are the person at Apple creating a text field that person wants to show. So the text field in the preview, okay, well, what's your name? All right, but then for the text, what do I provide? How do I provide a binding? This is when I can provide
84:00 - 84:30 a constant binding that says Vincent. And you can see here my text field has this constant binding. Of course, there will be no interaction. So here you don't see it, but I'm typing and typing on backspace a lot. And you can see that it goes back, then it goes back, then up again, then back, then up again. And it's because the text field kind of like anticipates the animation, but actually nothing changes in the binding. And so the next time it calls the gator, it still gets the same value.
84:30 - 85:00 So it's a way to use this constant static function. It's a way to create a simple binding for a simple preview. It's possible to also create a binding that actually holds some state in a preview, but we will see that a little bit later because it's a little bit more complex. Let me put it back the way it was and I'm checking that I haven't forgotten to tell you anything.
85:00 - 85:30 Okay, then I want to talk a bit about the kind of modifiers you can call on a text field. So, for instance, you can set a style to the text field. So through the modifier text field style and you will see this pattern will happen a lot. There will be list styles, button styles, et cetera. And so we have a few options. Plain, automatic, rounded border.
85:30 - 86:00 And if we do rounded border, you can see that if you win, try and zoom a bit. Yes, I can zoom a bit. Can I move it a bit? I'm trying to make it so it's like as big as possible and I don't hide it. But you can see that we have the rounded border around the text field and we've changed this by applying a style to the text field. What else could we do with a modifier? We could, for instance, disable the text
86:00 - 86:30 field itself with true and false. And most of the time we wouldn't pass true or false. We would pass a Boolean at state property or a Boolean at binding property. This way we can change this programmatically depending on the logic of our app. But you can see that now the text field has become disabled. More interesting, we can also disable the auto correction, for instance, even though it has been so now it's called autocorrection disabled, so like that.
86:30 - 87:00 And so now the auto correction has been disabled. So, of course, I'm on a Mac with a keyboard, so you don't see it that much. But if you test it on an iPhone, you will see that auto correction has been disabled. By using this modifier, we can do basically like all the things we could do with a UI text field. In UI kit we can also call auto capitalization of the text. So it has changed to text input, autocap input like that.
87:00 - 87:30 And we can say, for instance, we want to auto capitalize by words. And so now of course you don't see it because I'm typing on my keyboard, but I'm not using the shift key or anything to write a capital letter, I'm just typing in lowercase letter. But you can see that by word it's being capitalized when I write my name.
87:30 - 88:00 And finally we can also apply other modifiers. Like for instance a modifier you will see a lot is the padding modifier that lets you add a bit of padding around the view. And for instance we can say, okay, we want to add a padding but only horizontally. So only an extra padding on the left and on the right, or as we would put it, on the leading and the trading edge, but nothing extra on the top or on the bottom.
88:00 - 88:30 Okay, what else can we do? Yes, one thing I want to show you on text field. So text field, if you look at all the inits that we had, you saw there were a lot of in it and also a lot that have been, that have been how do you say deprecated.
88:30 - 89:00 That's the word I was looking for. Now, it doesn't mean that because they've been deprecated, you won't be using them here. My project has been configured to run on iOS 16. It's probably not the case for you and for instance, this in it that takes a closure that is called every time the value in the text field has been changed. If you had needed it, you would have used it on iOS 14.
89:00 - 89:30 This has been replaced by a system that I will show later that uses a property wrapper called at focus state and it allows you basically to know that, to know, like when the user has hit the return key on a text field. If you need to implement a flow where you automatically highlight the next text field, you would have used an editing change you've seen it has been marked as deprecated because my project is iOS 16 minimum and indeed there is the Focus State API available.
89:30 - 90:00 But if you are still using iOS 14 and you need to have this behavior of knowing when user has typed the return key in your text field, you won't have a choice but to use the API that is currently marked as deprecated. So my point with this very long sentence was to say it's not because an API appears deprecated. When you create your basics with a project with iOS 16 as the minimum by default, that you won't actually be using it because if you need to support older
90:00 - 90:30 versions of iOS, then you will have no choice but to use the API that are deprecated by now because you don't have access to their more modern replacements. Okay, what do I want to show you on the text fields? If you want to store a password, you have secure field, for instance. So like password. So for the password we need to introduce another add state.
90:30 - 91:00 You know what, no, actually I will use the same one because this way it will be even more like visual. So we have another text field, a secure field. Actually I will give it the same text field style because it looks a bit weird like that. Okay, and remove the padding there better. And so if I write into the secure field so I won't write my password, don't worry, I will just write hello world. You can see that here the password is hidden, but
91:00 - 91:30 of course you can see that it's still writing. The good thing because I'm displaying just above what is being written and my keyboard is mapped to Qerty, so I don't know on which key I should strike. Just to show you that we get the same kind of UI widgets than we do in UI kits. Maybe one thing you might be wondering is what do we do when the text field
91:30 - 92:00 requires us to write more than one line? Because here if I hit Enter, you can see that there is no new line that is appearing. So this might have changed a bit in iOS 16, but there is low chance that you will get to use iOS 16 as your minimum version. So I went through the iOS 14 version, but in iOS 14 there was a component called text editor that was introduced.
92:00 - 92:30 And so text editor, you can see it just takes a binding to a string like that. And so text editor, you can see it's this thing here, and you can go into multiple lines. So it's kind of like a UI text view. And the reason why I wanted to mention it is because like I said, it's iOS 14 and above. And so if you were using Swift UI on iOS 13 and you needed a text field, a text input that can go over more than one
92:30 - 93:00 line, you just didn't have actually any alternative. So that's one of the reason why I really want to drive that point, that committing Swift UI on iOS 13 is not the best choice. You will actually need to go back to UI kit for a lot of things. For instance, here you need to write to wrap a UI text view into something that Swift UI can use. I will show you how to do it later. It's not that hard, but it would be extra work
93:00 - 93:30 and also room for extra bugs because the more code you have, the more probability you have that. There will be a bug somewhere. Okay, I see it's been 1 hour and a half and I've covered what I wanted to cover in this first live stream. So I think this is when I go back, when I go to the recap part. But I'm happy because 1 hour and
93:30 - 94:00 30 minutes is a good time, actually. So I'm pretty happy about it, about how it went. I could cover everything I wanted. Before I go to the recap, I'm going to do the little ad for myself by saying that this training course is free. But if you have enjoyed it, you can leave a tip to support my content creation and basically all of the hardware or the video and audio hardware that I buy. So there is a link in the description, there is the link visible also here in the corner.
94:00 - 94:30 And if you leave a tip during the live, your name will actually be displayed on the video for everyone to see. That being said, let's go into the recap part. So first I want to do a recap on the way that Swift UI deals with a change in the state of the app and deals with the need to redraw GUI. So the way it works is that when the content
94:30 - 95:00 of a property has been annotated with at state changes, the property wrapper will intercept the fact that there has been a change and will let the Swift UI engine, we could say, know about it at that point. What Swift UI will do is that it will regenerate the body of the view. So it will regenerate this thing. Remember, this is just a struct and this is cheap to create. It's just a struct, so it can afford to
95:00 - 95:30 create it even if it might not be needed or if it might not need everything. Once Swift UI has the new body, it compares it with the previous body and it's able to do that in an efficient way because as we've seen, this body has a type that encodes the entire structure of the view hierarchy defined in the body. And since that structure is the same
95:30 - 96:00 throughout the lifecycle of the app, swift UI is able to easily compare easily. In a sense, it's efficient, it doesn't take too long, is able to compare the new version of the viewer key, including the value of the states and the previous version of the viewer key. And for instance, when the username has changed by comparing the new body and the old body, swift
96:00 - 96:30 UI will see that here the text field isn't the same because the text field has a username that is now different than before. So Swift UI, we understand that these things don't need to change for now. However, this thing here does need to change. And so it will redraw, not necessarily directly, but it will start the process of redrawing this text
96:30 - 97:00 field, of course, because views are laid out. If a view changes, it might also require redrawing other views because their layout has changed. So actually Swiftly is going to take that into account and it's going to compute the layout coordinates, et cetera. But the point is that Swiftway will only redraw the views that need to be redrawn. And this is one of the reasons why Swiftly can manage to be quite efficient is because it can rely on the
97:00 - 97:30 fact that the body always have the same structure. And so it's very easy for Swiftly to compare things and to pinpoint the places where changes have been made and from that to only change these places and the ones are impacted by these places changing. So that was the recap about the Swift UI view update lifecycle in a nutshell, of course, because
97:30 - 98:00 in reality there is definitely more complexity to it and not all of it is documented. So there is part of it of which we can only make assumption, but we don't know, we don't have something written by Apple. And before we end, I want to answer the question I had mentioned at the beginning of the live stream, which was if we go into the view protocol, you can see that it has a recursive definition, meaning that a view is a
98:00 - 98:30 tag that has a body which itself is a view. And there was the question of when and how does this definition, this hierarchical, this recursive definition stops? We know it has to stop somewhere because if it didn't, the app couldn't compile because the app would be like our code would be of infinite size and it's not the case. So we know that it stops somewhere. So let's see how. First, remember that we saw that the entry point,
98:30 - 99:00 the root of the tree was the app. Then we had the scenes, then we had our views. And so here the leaves of the tree are the text, the text field, the text editor, et cetera. So let's actually take a look at text and let's take a look at what its body could look like. So we can see first, text is defined just as a strike that implements equitable. There is no mention of view that makes sense because it only comes later through an extension.
99:00 - 99:30 So I'm going to scroll down a bit. Hopefully I won't scroll past it. I'm looking for the part where text confirms to view. It's here. So here, this is where text confirms to view. And you can see no body is implemented. And the reason is because the type of the body is never. This means that the body is never called.
99:30 - 100:00 It's impossible to call it, it's code that cannot be run. And so it means that all of the views that are like the leaves of the tree structure, so views like image, text, et cetera, they actually have no body. They have a body of type never, meaning that they just don't define a body and they have another mechanism that is private to Swift UI to actually perform like
100:00 - 100:30 their side effects, which is to display text or to display an image on the screen. The reason why I only mentioned text and image as having a body of type Never is because I'm actually not sure for text Field how it works. Because it's possible that text field is a composition of a text and other things. So let's see actually, so you can see text field has a body of type some view, we don't know which, but text field is not actually a leaf of the Swift UI
100:30 - 101:00 of the tree that is a Swift UI app. It's because even though text field is part of Swift UI, it's probably created it's not even probably, it's for sure create it by composing other Swift UI views. But at some point this has to stop. And for instance, in the case of text, we saw that the body was of type Never. And let's look at image for instance. So image it is also of type Never.
101:00 - 101:30 I don't know if text and image are the only two real leaves in Swift UI that have a body of type Never. I remember that for UI kit, I had heard the UI kit engineer say that in UI kit, actually the only component are allowed to write into the graphics card, into the video memory were UI label and UI image and everything else was actually made by composing these two building blocks. So it's actually very possible that that
101:30 - 102:00 is the same thing in Swift UI. But at least I wanted to show you this because it answers the question of where does the viewer key stop and how does it stop if you're not sure what never is? I won't go into the details here because it's a big topic, but I have a few videos about never on my channel and it's really one of the most, like a fascinating part of the Swift language. So if you're not sure what never is, I would really recommend that you take the time to
102:00 - 102:30 learn a bit about it because you will, I think, enjoy what you're going to find out. And with this recap, this time we're getting to the end of this first live stream. So thank you for following it. I hope you have enjoyed it. We've covered. So what does a Swift UI project looks like? What are the building blocks, the cornerstones of Swift UI? Then we started to tinker a bit with the most basic Swift UI components.
102:30 - 103:00 And even though we went for simple things, we still saw in quite a realistic way how the lifecycle of Swift UI view looks like for the next live stream. What will be its content? I can tell you, because all the material is already ready. We will be focusing on the layout system of Swift UI, which is quite different from UI kit, and I think it might deserve a live stream of its own UI.
103:00 - 103:30 There will be only that in the live stream because I remember what there is in that chapter and there is quite a lot of things. It will probably be next Thursday. I will need to confirm, but we'll probably be next Thursday, and I will announce it probably on Monday. So probably next week, same time, we will talk about the layout system in Swift UI. Finally, last thing, if you're watching in the replay, you might have already found in the description a link to the project we built during the Live.
103:30 - 104:00 If you're watching Live, the project wasn't available, but the project we built, I will put it in the description, even though it's quite a simple project, so it's not like I think you were able to follow without it. But you will be able to have the final project if you want to check it out, if you want to tinker with it and not have to follow along to see all the steps that lead to that project. And with that, I just need to say
104:00 - 104:30 thank you for following this live stream. If you've enjoyed it and you have colleagues that could also find it useful, please share it with them. My goal is for the maximum number of people to be able to see it. That's why I really wanted it to be like free on YouTube. And I just have to say, yeah, thank you for attending this first live stream. I'm really happy with how it went now. I'm looking forward to the next one. Have a good evening or rest of your day, depending on where you are in the world.