Lecture 1: Getting started with SwiftUI

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Paul Hagerty is an absolutely incredible teacher.

πŸ‘οΈŽ︎ 70 πŸ‘€οΈŽ︎ u/SophiaofPrussia πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies

What a time we live in, where a highly respected University, freely gives away their lessons and reading material/homework plans.

Thanks Stanford for 10 years of iOS support!

πŸ‘οΈŽ︎ 36 πŸ‘€οΈŽ︎ u/NewUnityModder πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies

Thanks for this! Probably the best teacher for the topic out there.

πŸ‘οΈŽ︎ 6 πŸ‘€οΈŽ︎ u/oloshh πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies

This is an excellent intro. Did last year's and was productive in SwiftUI right away. Highly recommend this over any other intro format.

πŸ‘οΈŽ︎ 6 πŸ‘€οΈŽ︎ u/recurrence πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies

I cannot spell Model-View-Controller without Paul Hegarty.

πŸ‘οΈŽ︎ 6 πŸ‘€οΈŽ︎ u/kentliau πŸ“…οΈŽ︎ May 19 2021 πŸ—«︎ replies

not sure if you'd know, but how is this course compared to Angela Yu's SwiftUI course on Udemy?

πŸ‘οΈŽ︎ 4 πŸ‘€οΈŽ︎ u/nicebrah πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies

Why are some videos on private?

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/Mank15 πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies

This is great, thanks a lot

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/valdelaseras πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies

What are the recommend classes to take prior to this one? Thanks!

πŸ‘οΈŽ︎ 1 πŸ‘€οΈŽ︎ u/Parralense πŸ“…οΈŽ︎ May 18 2021 πŸ—«︎ replies
Captions
(upbeat music) - Stanford University. - Hello everyone and welcome to Stanford University's CS193p This is a course about developing applications for iOS devices like iPhones and iPads using the development environment called SwiftUI. This is a replay. This course was originally offered to my students at Stanford back in spring quarter of 2021. My name is Paul Hegarty. I've been teaching this course in one form or another at Stanford for about 10 years. And I know that all of you are coming to this with a very wide variety of backgrounds and experience and expectations for what you might get out of a course like this. So this time I decided to do this little intro for non-Stanford students to try and give you an idea of what to expect in this course before you dive in. This quarter was another pandemic quarter, only offered remote, so you're going to be consuming this course in the same way as my students were, on video, and there's definitely disadvantages to doing that. I love live lecture, can't do that, but there are advantages to watching on video as well. For example, you've got pause and rewind. That's a great feature to have when you're consuming very highly technical course content like you're going to find in this course. Of course, my students also had highly interactive class forums and the TA, and you're not going to have that, but there are a ton of really great resources out there on the internet. There's a very vibrant SwiftUI community. And this is not the only place to go out and learn iOS programming. So you'll definitely want to seek out all of those resources as you watch these videos if you haven't already. Now, this course plays out in kind of a narrative format which works well for the students because they're interweaving it amongst all their other courses. And so, we work together, the students and I to build the couple of good size applications, a card game, and a drawing application. So I'm telling part of the story when I'm lecturing and demoing and they're participating in the storytelling too though via their homework assignments. Their homework assignments are always building on the stuff that I'm doing in lecture. And so we post all the homework write-ups and all the demo code at cs193p.stanford.edu. So be sure to go look for those. They are absolutely essential to getting the most out of this course. This course is also intended, not just to be a, a how-to course in iOS programming but it's also a little bit of a how-things-work course. Systems design is really important for our CS students to learn and so, we try to spend some of our time in the lectures in this course talking a little bit about how SwiftUI is doing what it's doing, not just how to turn the knobs to make it go. So you'll see that flavor kind of sprinkled all throughout the lectures. A little bit about the prerequisites in this course. For the students here at Stanford, they have the prerequisite to take at least three, and recommended four, intro CS courses. So, they're relatively experienced programmers. One of the things in particular that students all know by the time they're taking CS193p is object-oriented programming. So even though we don't actually use much object-oriented programming doing SwiftUI, the concept that you learn in object-oriented programming, like instances of data structures and encapsulation, these are really good things to know when you're trying to understand how SwiftUI works. Also, SwiftUI requires you to learn a new language called Swift. And for all of my students, you know, they'll have learned a new language three or four times before coming in here, so it was kind of old hat for them to learn a new language. So if for you Swift is going to be your second language ever or you're a first time coder and it's your first language, that is going to add a significant extra challenge to absorbing all the material in this course. So as you can probably gather from all that, this course is not aimed at the first time programmer. I will say though, that if you are just starting out coding or even if you're not even a coder at all, maybe yet, you might still find the first couple of weeks of this course very interesting to watch just to see what it's like to develop an application for iOS, because we dive right in. Students at Stanford, haven't learned Swift yet so we don't really assume that they know anything at the start. We're going to go step by step. We encourage the students to follow along. The homework really requires them to follow along. And so you should be able to do the same thing really, no matter what your level of programming experience is, at least for that first few lectures. And then you can decide kind of where you want to go from there. So hopefully that gives you all the information you need to know to get started. So, off we go. Let's start by looking at what we're going to build and we're going to do that in these iPhone simulators. These two things you see on screen are simulating an iPhone 11 on the left right here, and an iPhone 8 on the right. When we run our application to see if it's doing what we want, of course we could plug our iOS device, our iPhone or iPad, into our Mac and run it on there. But, a lot of times it's nicer to be able to just simulate a device and see it right on our screen. That's what these simulators allow. They simulate not just our application running on an iPhone, but most of the iPhone environment as well, like the settings app. We can go to the settings app and set things that might affect the way our app runs, or contacts where you need to access the address book, calendar, et cetera. All these things that our application might want to interact with are also simulated on the iPhone. Here's our app that we're going to build this quarter. It's called Memorize. It has no app icon yet. Hopefully we'll get to that during the quarter. I'm just going to tap on it to run it. Here it is, and it's a game. I'm going to click here on this Halloween version of it. It's a card matching game. Some people would call this game concentration, perhaps, or memory it's sometimes called. We're going to call ours Memorize. That's going to be the name of our app. It's a very simple card matching game. You click on cards and they flip over and you're just trying to match them. These cards have emoji on them. Our Halloween has a nice orange theme to it. Those two cards don't match so I have to keep searching around. Oh, I think that was this one, right? So now I could find a match. There it is. You get a little spinning animation there. Notice also that there's this timer ticking down in the background. That timer is essentially saying how long this card has ever been face up. We clearly want to reduce that as much as possible and match these cards as quickly as we can. Now, notice there's no score on the screen because I'm leaving that to you on your homework assignments to decide how to allocate points based on this timer ticking down and how quickly matches are made, or maybe penalize when you could have made a match, but you didn't. There were two cards that match and you're like, "Oh, I didn't- Oops, I didn't match that one. Oh no, that was the same as that one." So you might be losing a lot of points here, clicking around, trying to find matches or you might be gaining points because you're so good at memorizing and so you're like, "Oh yeah, I know exactly where this thing was. It was right there and I'm going to click and match, and the timer doesn't tick down, et cetera." So I'm gonna leave that all to you. I don't want to bias you with any particular canonical implementation of the scoring. So that's totally up to you. This UI can do other things. We can create a new game. We'll restart with all the cards face down, and re-shuffle everything all around. You see there's a lot of animation in this game. Animation is very easy to do in SwiftUI. Back here, this part of the UI that we saw over here lets us choose a different theme. We had Halloween. Let's pick Vehicles. Now we're matching vehicle emojis. That one had a match there. There's another match. But, it also let's you edit these themes. I can go here and hit edit and then I can click on these and it brings up this nice UI for adding emojis to my theme, changing the theme's color, maybe changing how many pairs of matching cards, what is theme's name. You're going to be doing all of this UI, a hundred percent of it, in your homework. By the time we're done with this just a few weeks from now, you're going to have the skill to be able to build UIs even as complicated as all this. Now this is obviously a fair amount of UI to build. We're not going to build this all just this week in the lecture time we have left. We're going to get ourselves started by just building some of it, a little bit of it. In this simulator, I have a version of Memorize right here that is going to be what we're going to build in this week's lectures. You can see it has the cards and I can tap on them and they do flip over, although they don't animate. Obviously there's no timer there. Also, if I flip over all the cards, you'll notice that no two cards are the same. These are all 12 completely different cards. So, we can't play the matching game because we have no matching cards. In general, the whole logic of playing the matching game, we're going to do that next week. What we're doing this week is just trying to start building our UI and have it look like this. Obviously we're not doing any of this sophisticated UI over there, we're just trying to get our cards up here. We are going to put a couple of things down here that aren't in our final version like this plus button, which adds a card. Add more cards. Also, our UI is going to scroll because we can hit so many pluses here that the cards don't fit anymore. Whereas over here that's not true. By the way, that's really noticeable if we take this and rotate it. This button here will rotate to landscape mode and the cards resize themselves a little bit so that they fit the space more perfectly. In our version when we rotate, it still works, but we have to be scrolling because we can't fit all the cards. Our cards are a fixed size right here. I was originally going to have you do a shuffle button down here in your homework, that would shuffle the cards around. But I actually decided to have you do something a little more ambitious which is to shuffle the cards but also provide a very, very simple theme chooser. Nothing like the theme chooser we saw on the left here, but just something that lets you use what we're learning this week. Also, you probably noticed that that shuffle is doing a little bit of animation but I decided to put that off for now as well, so you won't have to do animation for the shuffle buttons in your homework and we're going to talk all about animation in a couple of weeks. The tool we use to build all this is called Xcode. It is one-stop shopping for doing all of this stuff, whether it's editing your code, running it, seeing the UI as you build it, debugging it, et cetera. All in one place. Let's talk briefly here about how we get a hold of Xcode. We need Xcode. And since it's a Mac app, of course, we can go to the Mac App Store. If you go to the Mac App Store and go to the search bar and just type in Xcode, then you'll get the top match which will be Xcode. If you click on it, this is going to say, download. Just click on that and you're up and running. It's a free app, costs nothing, and you can join a developer program with Apple for $99 a year. I'll talk about in a moment what you get for that, but it's not required. Not required for this class, nothing that you do in this class, this app that we're building over here, none of that requires joining the developer program at Apple. So it's free. So everything's free. Now, if you're a little bit bold and adventuresome and you want to try the beta version of Xcode, which of course they're always coming out with betas every few weeks, you're certainly welcome to do that. I'll show you briefly how to do that. Just bring up your Safari, go to developer.apple.com. In fact, we can go directly to developer.apple.com/downloads, probably the fastest way to get there. You can see there are beta software downloads, both of Mac OS and iOS. But also, under applications here, you're going to see Xcode 12.5 beta 3. This is again going to update over time. You just click download and you can run it. Nothing I do in this course is gonna require this beta, so you're perfectly fine if you just want to use the version off the app store. Maybe start off with that one, then as you get more confident and you want to be on the bleeding edge of things, feel free to switch over to the beta if you want. Once we get Xcode on our machine, we launch it by clicking on it. I happen to be running the beta version here. When we do and we get this splash screen. Beta or normal, you're always going to get this splash screen. A very simple starting point in Xcode: on the right over here we have all of our recent projects. Things we've been working on will be stored here. Then on the left, we just have three options for starting a new project or finding an existing project that's not in this list, which is pretty rare. All of the projects we work on are kept in here reliably, so this is usually how we open that. There are two ways really to create a brand new project. One is to create it here. That's what this first one is. The second one is to clone a project that is in a source code repository somewhere. I am going to talk a little bit about source code control and repositories later in the quarter, but for now, we're just going to obviously be creating our very first project ever by clicking this "Create a new Xcode project". This "Open a project or file" down here, not going to really have to do that. Those things will all be over here. Click "Create a new Xcode project". It immediately says, what kind of project do you want to create? Because Xcode can build not only iOS apps, which is what we're clearly building here, but also Mac OS apps, Apple Watch apps, Apple TV apps, even multi platform apps that run both on Mac OS and on iOS. We will be doing that for the second big app that we build later in the quarter. But, today we're going to do iOS apps. Even within iOS, there are different kinds of apps here. Most of the time we're going to do this just basic "App". But, later in the quarter we're going to make a "Document App", and there are other kinds here. You might explore some of these for your final project. But we're going to do iOS app. Just click here and here and make sure you do that when you're building your app. Here's where you might want to pause and go get Xcode if you want to follow along. If you do, be sure to click 'iOS' and then 'App' before you click 'Next'. When you do that, it's going to ask you some questions about this iOS app you want to build. First question: what do you want to call this thing? We know that we're calling our app Memorize. The second thing here is the team. This is the development team working on this. Well, that's going to be you. When you run this, unless you've used Xcode before, this probably says something like 'create a team' or something. You're going to click on that to create a development team. It's really easy to create a development team, you just need an Apple ID. That's just your normal iCloud login. Again, it's not going to cost any money. You're just going to go and register this development team with that iCloud Apple ID and that's it. Then you'll be off and running. Next, you're going to have a string, this organization identifier. You are the organization. Basically, it's the organization you work for, but you're a student. If you're not a Stanford student, this might be the company you're working for. This has to identify your organization that you're working for on this. If you're an individual, I really recommend using what is called reverse DNS notation right here. Maybe your email address, or if you're a Stanford student, edu.stanford.cs193p.[your SUNetID] instead of instructor. Maybe you could even skip the CS193p if you want. But, you just want to pick something here that no one else is going to pick. If you work for a company, this might be your company's website name backwards, or even your company's website name backwards and then the group you're in at the company. This just has to be a unique thing that identifies the group that's working on this app. Xcode quickly combines the name with that to create this bundle identifier that's a unique ID for this app. Makes perfect sense. These last three little choice boxes here are letting you choose between the new way, SwiftUI, of developing iOS apps, and the old way, which is called storyboard. I only have 10 weeks to show you this stuff so I can't show you both. The new way, it's very new only introduced about two years ago, but it's very powerful and it's also benefited from all the learning that the old way had. When you're creating an app, you're always going to have these three buttons be on. SwiftUI, the new way, SwiftUI App, that's the new way Also, you can mix the new way with the old way of creating an app. It's kind of odd, but you can do it, We're not going to. We're always going to do SwiftUI App. Since we picked these, for the language, there's only one choice which is Swift. SwiftUI is totally dependent on the Swift language, which is a new programming language that I'm going to not assume that you know. I'll be showing you that language from scratch the entire quarter. If we had picked the old way up here, then we would have another language choice here called Objective-C that was the language that the old way was originally written in. But again, it's all Swift all the time in this course, so we're always going to have these buttons in these Swift settings here. Last thing: regarding these switches down here, make sure they're all off for this first app, but we are later going to look at this core data thing. That's an object-oriented database. I probably am not going to have time to show you the testing framework in SwiftUI, but it's pretty darn amazing. It lets you test not just the backend code but also your UI to make sure that your UI is looking like it's supposed to. But again, please, all of these off for the first version here, Memorize. When we hit next, now it just wants to know where are you going to put this thing in your file system? I strongly recommend putting it in your home directory in a folder called Developer. So all of your projects should be collecting over here in your home directory Developer. This is the canonical place to put it. You can see that Finder even puts a hammer icon on there. It recognizes this as a standard kind of folder. Down here, we have the source control that I was talking about at the beginning where you're storing this stuff in repositories, and this is something we will talk about later in the quarter briefly. Source control is good as an individual for versioning your app as you work on it but it's really valuable for teams. When you're working on a project with teams, five programmers or something working on one app or even a hundred programmers working on one app, how do you not step on each other? This whole source control thing provides a mechanism for checking out your code, making changes, checking it back in, making sure it doesn't conflict with what other programmers on your team have done, et cetera. Again, we'll briefly talk about this later in the quarter but we definitely want this off to start. I say definitely, but I'm going to do it with it off. So if you're following along, you might think that yours looks slightly different if you have it on. So let's leave that off and hit create and voila, it created our app for us. This is our first iOS app. Congratulations, you've built your first iOS app. This is the main screen of Xcode. You're going to spend all quarter long living here, so I'm going to spend some time talking about all the parts of this. I'm going to start right up here at the top with this fun little combo of buttons. This is how you run your application. So the first thing you do is pick where you want to run your application. That's this. Right now, it says iPad touch (7th generation). That's where it would run it if I ran it but I'm going to click on that, and you can see that I can choose to run it on an iOS device connected to my Mac (I don't have any connected right now) or I can run it in one of those great simulators that we saw. There's the iPhone 8 simulator, iPhone 11. We're going to run our app on the iPhone 12 mini, my favorite iPhone. You just select where you want to run it and you just press this play button, and then when you're done, you press stop. So play and stop. So let's go ahead and play. It's going to launch this iPhone 12 mini simulator. There it is. Then it's going to install our app on it and it's going to run the app. There it is. It just says "Hello, world!". Now, those of you who were looking back here at our code probably saw that "Hello, world!" right there, and you were like "Hm, I bet this app says 'Hello, world!'" And in fact it does say "Hello, world!". That's what this app says. Otherwise, it's just big blank space. That's cool, we can do that and we can do things like rotate and it's nice. It keeps it automatically centered. We're going to find that this thing where we rotate and our UI changes, we have to do very little code for that. SwiftUI pretty much handles that for us, centering things properly and all that. Then when we're done simulating our app running right here, and again this is a full iPhone simulator. I can switch over and run settings over here and go back, switch back to my app, full simulation there. So when we're done, we press stop. It stops running. I have the menus hidden just to give us more space but obviously there's a lot of menus up here in Xcode and we will be using them. Obviously as the quarter goes along you'll be learning them as we go. It can be intimidating to see so many menu items with so many things, but again, we'll slowly unveil them. It won't be quite too intimidating as all that. There's a little status wonder here that just tells you what's going on. Here, we just finished running Memorize. It'll say when it's compiling and all those things. Let's take a look at this blue area here on the left. This is called the navigator and it does what it says: it lets you navigate your application. It lets you navigate it in lots of different ways. These little icons up here are letting you choose those different ways to navigate it and the default here is to navigate it by file. These are all the files that are in our application. These four files were created for us by Xcode, to get us started, and I'm going to actually look at all four of those in a moment. But we can also navigate other ways by searching throughout our project or if we're debugging, we can look at all of our break points, et cetera. We'll see these different ways of navigating as we go. All of the parts here can be resized. Just grab this with your mouse and you can make things bigger or smaller to allocate the space as you want. You can also hide and show with this little button. A lot of times, once you're deep into doing some editing, you really don't need to switch back and forth between files here, especially because you're going to see tabs developing along the top here, like this thing that says ContentView.swift, where the files that you recently edited in are in tabs. So then you really don't need this as much, unless you're going to search or something like that. Now on the right, this area here, this gray thing is called the Inspector. I'm going to show you that a little bit later. In the center, this two paned thing here is the main editing window. Usually you're going to have your code here on the left and you're going to have one or even more of these other ancillary windows. This particular little space right here is very cool. This is the previewer. The previewer previews your UI. It actually shows you what your UI looks like without having to run it on the simulator, and it shows it to you, mostly, in real time. It does pause occasionally. It says right here "Automatic preview updating paused" That's why we're not seeing our "Hello, world!" code over here show up. But, we can resume it at any time with "Resume". When we resume, it essentially is like launching a little simulator in place right here. We can zoom out a little bit and we see our UI. There's our little "Hello, world!" UI. We can divide the space up better if we want. We're going to see this preview used as we're doing development. It's just always going to be previewing for us. It's a really powerful, really awesome system. Up here at the top, we also see there's a little line that's just saying where we are, specifically where our cursor is. If I click down here, it's actually saying we're in this body thing. If I click down here, it's saying we're in this ContentView_Previews thing. You can even click on this and navigate around, jump your cursor around, jump it down to the bottom, jump it back up to the top, et cetera. This is kind of where our cursor is up here. One thing that's cool about these three things here, the preview, our main code editing and this inspector, is they'll stay in sync. If I click on this line of code right here, it not only selects this thing that says Text("Hello, world!"), but it's selected that "Hello, world!" text thing with a blue line here and it made an inspector, some kind of UI over here, for inspecting or editing the attributes of this thing I have selected. If I click away, then it stops selecting it here. Nothing has to be inspected. Click back. It's doing it. If I click away, I can also double click in here and it'll select it here. Show me here and select it over here. These things are linked. They're always showing you, unless this thing is paused, they're always showing you what's in the other three panes. We can edit things or change things in any of these panes. For example, we have "Hello, world!" here, what if we said "Hello, CS193p!" Look at that, it changed here and it changed up here. We could change it up here. We could say "Hello there, CS193p!" Changed it here, changed it here. What was really cool is as I was editing it here, it was changing in here in real time and it will always do that as long as it's not paused. If it gets paused then you're just going to say, resume, and it will continue. This inspector over here is pretty powerful. It's not just changing the text. You can also change the font, font color, et cetera. Here I even have some padding. You see this little blue dot says that my padding is on. Sure enough, you see this says padding right here, we're going to look at all this code in a bit here, but this little padding in here, if I turn this off, it takes that out of there. Or if I turn it back on but only for vertical padding, then I get padding vertical. Again, we're not worried about what all this means, but the point is that as we can change things over here, it's changing them over there. That is your tour of Xcode. There is the debugger which comes up from the bottom. We'll see that in a little bit when we start doing some debugging. You won't need to be using the debugger during this first week's lectures. The stuff I'm going to be asking you to do on the homework is very straightforward and will not require debugging. Let's go back and do what I said and look at these four files that Xcode created for us when we created this project. We'll start with this one: Assets.xcassets When it says assets it means things like images, sounds, and videos, those kinds of assets. What we do for that when we're building an iOS app is we drag the assets into here and we give them names. In the white column here is going to be the names of the assets and then here is going to be the actual assets themselves. You will see the images showing up right here. Some assets are more complicated than the others, like your app icon is quite a complicated asset because it has lots of different resolutions. These resolutions here are dependent on the environment, whether it's on an iPad or an iPhone or you are in the spotlight area, is it said a notification that just came in on your iPhone for that app, etc. If you have an app, especially an app that you're shipping to the app store, you're probably going to have an artist or somebody make some perfect nice icons that look good at all of these resolutions. We're not going to look at the assets more than this, but we will be using it later when we want to add images to our application. What about this thing, Info.plist? This is essentially the settings of your app, but this is a pretty raw way to edit it and we usually don't edit this Info.plist directly. Instead, if we go up to our project and click on the project itself, we get a nice UI for editing these same settings right here. And what kind of settings are we talking about? Well, does this app run on the iPhone? Yes. The iPad? Yes. Does it run on the Mac? No. We're not building this Memorize app to run on the Mac. The next app that we do, we will have it run on the Mac. Also, are we deploying to iOS 14, iOS 13, iOS 11? The farther back we tried to deploy, the fewer new features we get to use. All of this stuff, when you change them here in this nice UI switches and all that, it changes it in this list over here as well. We don't really look at our Info.plist hardly at all. We're almost always clicking up here if we want to change project settings and 99% of the time, you don't need to change any of these settings. They just default to the right thing. That leaves us with these two files right here. They're both .swift files, Swift language files. Swift is a new language that I'm going to be showing you from scratch. This one right here, MemorizeApp.swift, I'm not going to look too closely at that one. It really doesn't matter too much. Couple of things to note about it, it's our main program. In C, you have main.c which is the main C module where your app, when it runs, starts executing. We have the same thing in Swift and this is it. Because we put this @main in here, this becomes our main program. We don't worry too much about all this. The main thing to note here is that this ContentView() that's in the middle is basically saying that this other Swift file, ContentView.swift, is the thing that describes what our app looks like. When we go to our simulator over here and see our app, this whole area right here no matter which app we're talking about, is our ContentView.swift. That's really all the main program is saying is what is the name of that main area? And that's this, ContentView.swift, so this code is the entirety of the code that makes this. In fact, it's a little bit more than the entirety of the code. It's also got this little thing at the bottom ContentView_Previews. This is the code that glues this previewer to our ContentView. So really only this is the entirety of the code that draws our "Hello, world!" And this glue code, we hardly ever even touch this. I'll show you a little bit later in this week's lecture, how we could modify this a little bit but most of the time we don't pay any attention. In fact, I usually like to just get it out of my way, so I don't even see it. It's down there. It's doing the glue but I don't even look at it. Notice, by the way, that when I made a big change like that, our previewer paused so I can hit resume and it'll continue. Okay, that is it. That is your tour of Xcode. Now we're going to focus in on these lines of code and understand what every line of code in here does. I'm going to reset this "Hello, cs193p!" to "Hello, world!" Let's hide that and focus in on that ContentView right there, with that little bit out of the way. Let's just go through this line by line. This top line: import SwiftUI. This one's an easy one. This is like include or import that's in other languages. We're basically just saying that this file is going to use the package Swift code called SwiftUI. That's made by Apple and it ships with all iOS devices and on Mac OS and Apple Watch and all these things. It's here because we're doing UI in this file, but not every file that we create is going to have UI. For example, the files that we create that do the logic of our game, that actually match cards and keep score, that is not UI. That is logic and that will not be importing SwiftUI. One of the great things about SwiftUI is how it clearly separates that logic from the UI. But here, we're working on UI. We're not even going to start doing our game logic till next week, so this is all UI, so of course we want to import SwiftUI here. This is the entirety of our code that generates the UI and it's creating a data structure here. So struct is short for data structure, and most languages have structs. Structs are essentially collections of variables and C has this and pretty much all languages, they may not at call it struct, but they have some sort of collections of variables. Swift's collection of variables is pretty powerful because not only can we have variables in our struct right here, in fact, here's a variable we're going to look at later, but we can also have functions. So, func foo, have some code in there, this is perfectly legal. We will be looking at functions especially next week, but we actually don't need much in the way of functions to build this UI it turns out, but structs can have functions on them. That might feel to a lot of you like object-oriented programming because object-oriented programming is some data variables encapsulated together with the functionality on it. What we call methods in object-oriented programming. And Swift does actually support object-oriented programming and we will even be using object-oriented programming especially to connect our logic to our UI. You'll see that next week. However, nothing that you see this week is object-oriented programming. Structs in particular, even though they can have variables and functions on them, are not object-oriented things. They're not classes. There's no inheritance or anything like that and structs have different things, that I'm just about to talk about, that lead to a kind of programming that we call functional programming. Swift supports both object-oriented programming and functional programming. And we use the functional programming design model in the UI code that we built. We use the object-oriented design model to hook up our model, our kind of logic, to our UI. Today all the things we're talking about are functional programming. All right, we clearly don't need this function foo, not doing anything anyway. What's the next thing after struct? Struct is a keyword. All our keywords, of course, in magenta here, easy to understand them. Next word is ContentView. That is just the name of this data structure and this can be any name we want. This is our app we just created, it says, "Hello, world!" It didn't really know we were going to build a Memorize app so it called this thing ContentView because it's essentially the contents of our entire app. I'm going to leave it to that but down the road, we're probably going to rename this to something like MemorizeView or something a little more specific to what we do, but it's just a name of this structure, nothing special about it. This is very special. This little :View, when you're defining a struct, means that this struct that we're creating behaves like a View. I told you, this is functional programming and in functional programming the behavior of things, how things behave, is crucial. Most of how a thing behaves is the functions that you can call on it that defines how it behaves. But even the storage, the data storage, functional programming says nothing about how data is actually stored. It can talk a little bit about what data there is and what data should be in this struct but it doesn't say how it should be stored, whether it's stored in memory or calculated. In that way it's very different from object-oriented programming because you're not encapsulating the storage with the methods on that storage, the functionality. You're just talking about the functionality and describing the storage that might exist. You're not actually implementing it. When you say that you have a data structure that behaves like something, in this case behaves like a View, and we'll talk about what a View is in a minute here, that's really a double-edged sword. One side of the sword is really great, which is that a View has a lot of functionality that's built into the SwiftUI library. As soon as you say, you behave like a View, you get all that functionality because Views do all those things and you behave like one so that's great. The other side, the other edge of the sword is that you might have some responsibilities if you want to behave like a View. You can't just walk down the street and say, yeah, I behave like a View. Sometimes behaving like a View means you got to do some stuff too. In fact, behaving like a View, even though it's hugely powerful, really only requires you to do one thing, which is to have this variable. We're going to look at that variable and what that means in just a moment. But first let's talk about what a View is. When we say that this data structure we're creating behaves like a View, what does that mean? Well, a View is just a rectangular area on screen. This struct ContentView is this rectangular area. The corners are rounded here just because the device is rounding them off. This large rectangle area is this View, ContentView, and a View has the capability to display things inside. Here we see it displaying some texts. That's good. It also can receive input from the user in the form of multi-touch events. Taps, swipe, pinch, things like that. That's all a View is, really. It's just a way input and output in a rectangular area on screen. Now that's simple in concept, but in implementation it's super powerful because we want to build very beautiful rectangular areas on screen. Like for example, this where things are flipping over. In this sort of View right here, we have this ContentView or this top level View, but there's also a View here, which is this text. This card is a View that's got multiple things on it. It's got this emoji. It's got this kind of rounded rectangle drawing around it. If we go look at a complicated thing here, we got all kinds of Views in here. That text, this smaller text, this little arrow right here, the whole thing where we can click on something and it goes to another View. Those are all Views. Everything here, everything on screen, every rectangular area is a View. You can see that some Views like these cards are embedded in larger views. Views inside Views. This is kind of obvious, almost every UI system has this idea that there's rectangular areas on screen and you combine them to make your UI. But in Swift we do it with this functional programming model and we say that we're building this ContentView that behaves like a View. What can a View do? A ton of things. We actually earlier saw something a View can do, which is it can be padded. We had this text here before. It had this little padding turned on and it got a little bigger, a little space around it. That's just one tiny thing. Look at all these other things up here. Those are all things that views can do: set their color and all these things. We're going to see all of this and how we leverage the power of the behavior of a View a little bit later. But first I'm going to look at the flip side of View, which is this requirement that if we want to behave like a View, we have to implement this variable. This is a great opportunity to talk about variables inside of a struct, inside of a data structure in Swift. This is what it looks like to declare a variable, super simple. Keyword var for variable. body is just the name of that variable. Then :some View, that's different than this one up here. :some View is the type of that variable. Now, this is a pretty complicated, not necessarily complicated, but an important kind of type. Tt's a little bit odd. Normally the types will be very straightforward. Like var i is an Int. Or var s is a String. That's what most variables look like in Swift. This one has this weird, some keyword in there, this some magenta keyword. Also, it's got this View thing which we know that a View is a behavioral thing. So why is the type of this body variable, some View behavioral thing? Well, it's kind of exactly how it reads. The type of this body is something that behaves like a View. That's what the type of this var body is. Let's think about that. That's kind of strange. To create a data structure that behaves like a View, you are required to provide a variable whose type is some other thing that behaves like a View. That's kind of strange. Here's an analogy that might make it make sense. Why the requirement to behave like a View is that you have to have a variable that provides some other thing that behaves like a View. That analogy is Lego. Hopefully, all of you have had the joy of playing with Legos in your life. Legos are little blocks, little building blocks you use to build really cool things from a little tiny house, Lego house. You can build the Lego Star Wars Super Star Destroyer and everywhere in between. So Legos are very powerful little building tools. If you think of Views as being kind of like Lego, the analogy, it's not perfect, but it kind of works. Let's think about a Lego. Let's say I wanted to build a Lego house. Okay, a Lego house has got all the rooms in it. It's got a kitchen. It's got the bedrooms. It's got bathrooms. Let's say it's got a dining room. In each one of those, there's a lot of other little sub-Legos in there. Like, the kitchen's got a bunch of kitchen cabinets and table and appliances. The dining room has a dining room table and dining room chairs. You can see that the Lego house, we're actually building out of other Lego. We can think of that Lego house as just a thousand pieces of Lego. But actually when we really build something like a Lego house, when we're building let's say the dining room, we build the little dining room table out of some Lego and then we built one dining room chair out of the Lego. Then we are going to build another dining room chair and another dinning room chair exactly the same. We might have, I don't know, eight dining room chairs around our dining room table and they're all exactly the same those dining room chairs. So if we think of the dining room chair itself as a Lego, yes it's a Lego that we built out of other Legos by stacking them on top of each other and connecting them up, but once we've done that, it essentially become a dining room chair Lego. Then we can take eight of those and combine them with a dining room table Lego and now we essentially have a dining room set Lego. Then maybe we combine that with the rest of the furniture in the dining room, we have a dining room Lego. Then we put the dining room Lego together with the kitchen Lego and the bedroom Lego and the bathroom Lego, we put them all together, now we have a house Lego. We can put that whole huge house Lego together with other house Legos to make a Lego neighborhood and Lego planet, the Lego universe. We could build an entire universe out of Lego. If you think of it that way, you make the simple leap to say that a Lego dining room chair is itself a Lego, built out of other Lego, then that's how Views are created. That's why it makes perfect sense that if you're going to behave like a View that you have to provide this body variable that is some other View. Because we're going to be building Legos out of Legos. It's as simple as that. To understand our analogy a little bit better, let's talk a little bit about the kinds of Views that you're going to find in SwiftUI. Of course, you're going to find this kind of View: Text, which is like a Lego brick, a basic building block, stands on its own. If we look in our UI, they are everywhere. Here and here and here. On the card, this emoji is just a string, a little Text. So that's one clear kind of View. Similarly, we have these shapes like rounded rectangle and circle and oval, and things like that, these basic shapes, those are Lego bricks as well. But the real powerful Views that we're going to find in SwiftUI are the combiners, the Lego combiners. They're the things that take these other Views and combine them on screen. Either arrange them in a grid, like this perhaps, or maybe in just a line across, stack them on top of each other, things like that. Those kinds of combiner Views are probably the most important thing to making complicated user interfaces in this Lego model of piecing things together. There is one other kind of View that I'm going to talk about, which is like if you want to use our Lego analogy, it's a bag of Lego. If you buy a very large Lego set that has thousands of pieces, let's say, Star Wars Millennium Falcon or something. When you open the box, the people at Lego have very kindly grouped a lot of those thousands of pieces into little clear plastic bags, so that when you get to the part of the Millennium Falcon, let's say, the gun turret on the bottom or something, you don't have to search through thousands of pieces to find the pieces to build that. There's a bag. There's the gun turret bag and you open it up and there's only a couple of hundred pieces in there to build that part. So you don't build your Lego Millennium Falcon by just throwing the bag on top of it or sticking the bag in there somewhere. You open the bag and combine the Legos. So, those last two kinds of Views I talked about, the combiners and the bag of Lego, they go together. A combiner is obviously going to take a bag of Lego and open up and put it together. Armed with that knowledge of the different kinds of Views, you're going to see that this var body is almost always going to be a combiner View. In our case, right now, it's just a single Lego brick, this Text, but this some View is going to be a View that is a combiner View most of the time, the vast majority of the time. We'll get back to this some View syntax and what that really means in a second. But first I want to talk about this little piece of code right here. What is this? It's just kind of plopped in here right after this var body: some View. This is actually a function and I told you that Swift is a functional programming language. And in functional programming languages, functions are really, really important. In fact, functions are first class citizens and we can drop functions anywhere we want. This is something that for some of you, maybe even programming Java or languages like that, having functions be things that are just plopped right in the middle of your code might be slightly jarring but you're going to want to get used to it because in a functional programming language functions are everywhere. They are just absolutely everywhere. This function happens to take no arguments right here and it has no name. It doesn't need a name because I just plopped it right in the code here. This function actually returns something. It returns a Text, this Text. You might say, "well, where's the return statement?" There really is a return statement right there. It's kind of a hidden return statement right there. I'm going to leave it in there if I build under Command-B to build by the way, it says "Build succeeded". That return does belong there, it's just being hidden by Swift just to make the world look a little nicer. We're going to see a lot of examples of Swift hiding extraneous keywords and things when it's kind of obvious what's going on there. It does that all the time to make our code look a little bit nicer. This is a function with no name, takes no arguments. It returns in this case, a Text. So what's it doing there? What is this function plopped right in the middle of the code, right after this var body? This var body is not actually stored in memory. It's not a variable stored in memory. It's actually a variable that's calculated by executing this function. Every time someone asks this ContentView struct, "Hey, what's the value of your variable called body?" It executes this function and returns whatever it returns. In this case, it's going to return this Lego brick, this text. A text, what is a text? A text is another struct that behaves like a View, the Lego brick I said, so it has to be that. In other words, somewhere in SwiftUI there's something that says struct Text. It behaves like a View and it's probably got a var body. It's some View and inside there there's some code right there. There's probably some code something like this, somewhere in Swift. Maybe not exactly like that, but something like that. So, this is itself just something that behaves like a View. You've got a function here that returned something that behaves like a View and that's good because this var body is supposed to be a type that is some kind of View, something that behaves like a View. So these match up. This function is returning something that matches the type of this variable. Of course, if you're going to have the value of a variable be set by plopping a function right in there and have it be executed, the types better match up, whatever this returns, better match up to this. And it does in this case. It's great. In fact, this is going to help us understand what some View really turns into when our compiler is compiling this code. some View, it's not in and of itself a type. It's more like some advice to the compiler saying, "Hey this variable's type is going to be some View. Please go figure out what it actually is and replace it with that when you compile it." In this case, the compiler is going to look at this function, see that it returned a Text and it's going to essentially replace this with Text because that is its type. And again, if I compile, succeeds! Because this var body's type is Text. It's got a function, returns a Text. Why didn't we just say, var body: Text from the first place? Why did we do this weird some View? There's really two reasons for that. One, when we're trying to behave like a View, this View thing has to say what you have to do to behave like a View. So it's not going to say, "Oh, you've got to provide a var body that's a Text." Because of course you could behave like a View and your var body could be some combiner view that's doing this whole UI over here. This entire UI in this is returned by the ContentView of this version of the app. Part of is just the declaration, just declaring that that's going on. But another part of it is, we're going to make this code in here more and more complicated. It starts out as a single Lego brick, ends up being an entire game playing app. And then as it gets more and more complicated, the type of the thing that this returns is obviously going to get much more complicated and we don't want to have to figure out what it is exactly, or type it. We want the compiler to figure that out for us. That's what compilers are good at looking at the code and bringing out what the types of things are. It's very, very good at that. I can show you that very, very vividly by talking about something we already saw, which is padding. I clicked on my Text right here. That has brought back up and we can resume our preview here, brought back up, it's showing in the preview and also it brought this inspector back for us. If you remember when we originally started this whole thing with this Text we went over here to this padding and we turned it off. It used to be a little blue dot there and we turned it off. I'm going to turn it back on. So, it's back on now with all the sides, see padding all right there. Let's talk a little bit about what happened here when we turn this on and off. What is this line of code that got plopped in when we turned that back on? This is probably a little more understandable, if I move this onto the same line and you look at it like this. First, let me explain that this padding is just a function that exists in all structs that behave like a View. So any struct like ContentView or like Text, anything that behaves like a View, it has a function on it called padding. This is how you call a function in Swift. You just find the struct that you want to call the function on. If you're doing object-oriented programming in Swift then it's the object, an instance of the class. Then you just say '.' and the name again. Hopefully very familiar to you, Java and other languages do this exactly the same way, and then if there are arguments then you just provide them here. Swift arguments to functions, you're going to find to be very, very, very flexible. They can default. You can have different arguments that mean different things. For example, here, we have this .all and I will explain what things like that are later, but that means all of these here. We saw that if I click some of these off now it's .horizontal, but it even has other things too. I can type a number here like padding(20). That means put 20 points of padding on every side or padding(100), put 100 on every side. Or no arguments, which means just use default padding, which is a really good one to have because the default padding might be a little different on an Apple Watch vs. Apple TV vs. MacOS vs. iPad. So a lot of times we'd like to use the defaults of things because they're platform specific. But the point is we can put a lot of different things here in the arguments and it's the same function, padding, does the same thing. It's just that you're providing different information to tell it to do what it does. This function, padding, returned something. This is really, really important to understand that this padding function returns something. What it returns is something that behaves like a View. It's a different thing than this. This padding does not return a Text. It returns a padded, modified other View which happens to be a Text in this case. The actual type if I wanted to type it here, I could go to try and look it up and documentation, it's probably something like ModifiedContent, something, I don't know. Something complicated, but it's definitely not Text. In fact, if I put Text here and hit build it says "Build Failed". Cannot convert this expression to type Text. Because this expression is not a Text, it's whatever kind of View .padding returns. It's really important to understand what's going on here, because we are going to be doing a lot of these kind of little functions that return a new View, a View that's different than another View. They're called view modifiers, because they obviously modify some other View. In the Lego world, you can think of it as, we took this brick and we sent it back to the factory and said, "Send us a new one, please, that's padded a little bit around the sides of it." That's essentially what happened and the factory quickly sent us back a new one and that is now the brick that we are using here. So it is a modified Text. Every time we do a modifier here, it's going to essentially create a new View. That's why having this be some View, especially as this gets more and more complicated, is really valuable to us. We can see that even more if we add more modifiers because we can of course take these Views and modify them and modify them again. Let's take our Text right here and change its color, for example. I'm going to have my Text selected here and over in my inspector, I'm just going to change, let's say, the color of the font to orange. It added another modifier here between that and the padding. Let's see if it worked. It sure did. Now, we actually have three Views going on here. We've got this original View. We've got the View returned from this function, which is a Text modified to have its color be different, and then we have a View that's returned by taking that colored text thing and padding it. It's this View that is returned as some View right there. You can see there's a lot of power here, creating exactly the kind of View we want with these modifiers, but really we're only still talking about taking a brick and modifying it. A single Lego brick modified certainly is nice, but we need to be able to combine bricks. When we build something like this card right here, this is a combination of this rounded rectangle and a little emoji string right there on top of it. Combining these, and then combining those into this grid and then combining it all into a big app, that's we want to do. Let's focus here on making just a single card and using a combiner View to combine a rounded rectangle with the text on top of it, this emoji text on top. To do that, I'm going to comment out my Text here for the moment. So I type Command-/ there. It's a great way to quickly comment things in and out, by the way. You'll notice I got all kinds of errors: my preview can't biuld and all this. That's because I commented out the only thing in this function that returned some kind of View. This var body, this function that provides this value, has to return some kind of View. Let's do that. Let's have it return a RoundedRectangle. RoundedRectangle, another thing built into SwiftUI, it is a Lego brick. Notice that as you type, Xcode is always jumping in there trying to help you out. Here, it's helping me out with all the different ways that I can create a RoundedRectangle. I can do it by specifying the corner radius or even the exact size, the width and height of the corners. I want this with corner radius, so I'm going to click here and sure enough, it filled out some default corner radius here, 25. There is a rectangle with corner radius. I'll click away so we can see it. There it is, looking nice, looking good. Looks like a rounded rectangle to me. But, a somewhat strange thing happened on the way to creating this rectangle that you haven't seen before. Here's my creation of a rectangle. Look at the arguments to create it, very different than what we had with Text or even the function calls we had like color.orange, this argument has a label. Arguments with labels is very common in Swift. It might even be more common than not having argument labels. This Text doesn't have something like String because it's kind of like its argument is some text, so it's a little redundant. Same thing here. Saying foreground color is color: orange, that's the word color too many times. By the way, you don't even need this Color because Swift is smart enough to know that you're passing a color, and so you can leave that Color out as well. Swift doesn't like you typing the same thing over and over, color, color, color. But here, with RoundedRectangle, since I can create one by specifying the corner radius or by specifying the size, if I were just to say RoundedRectangle(25.0), it's just not clear enough what that 25.0 is. So whenever you define your own function and the arguments, and it's not obvious what an argument would be, you want to define it with a label. We're going to talk all about functions next week and how we declare them, how we make arguments, how we make them optional, all that business. And one of the things that we're going to see is we almost always put a label on our arguments. Really makes the code easier to read. One of the best things that Swift inherited from its predecessor, Objective-C, is these nice labels. Of course I can change this to anything I want, I can also change it over here in the inspector. We've got the RoundedRectangle over there. A RoundedRectangle is just a View. It behaves like a View. It's a Lego brick. So I could do things like padding and put some padding on it. Maybe I only want horizontal padding and it's going to do what I want. Make it match up in the inspector. It's all great there. RoundedRectangle is also a Shape. I told you that Lego bricks are Shapes, Circles and Rectangles, RoundedRectangles, Ovals, they're all Shapes. A Shape has one extra thing that it can do, which is that in addition to the Shape being filled in like this, you can just outline the Shape and you do that by saying .stroke So if we put stroke on the end of something that is a Shape, then it will just do the outside edge. See the outside, only the outside edge right there which is what we want it to look like, when the cards face up anyway. We want it filled when it's face down and stroked when it's face up. You can also do fill, that fills it in, but this is the default, so that's why we originally had this and it wasn't there at all. Stroke is just a function that things that are a Shape understand. So I can't stroke a Text. It's because a Text, while it's a View, is not a Shape, so it can't be stroked. But all things that are Shapes also are Views and that's why we can pad them. The stroke also can have arguments that are optional. lineWidth: 3 makes this line a little bit thicker. Notice this also has a label. So these labels are not just in the creation of structs, they're also when you call functions. Not all of them have it. Padding doesn't use a label and as we saw foregroundColor doesn't use a label, but some of them do. So we'll leave that in there just to remind you that that can happen. We could also do color. Maybe I want this RoundedRectangle to be some color, like maybe the red that we have over here, this red going on. So how do I make it red? Well, I'll just go over to my inspector, Oh no. In my inspector, there's no color. When I inspected a Text, it had the color there and I just picked the orange and I got this orange text right here. But that doesn't exist here. So what am I going to do? Well, what appears here is the most common things that people want to put in here. But everything that a View can do is available via this search field right here. See where is says "Add Modifier", it's going to let you add any of the modifiers that don't appear here that you want. If I click in here, you'll see that there are an awful lot of modifiers that Views know how to do. We are amazingly going to cover most of these by the end of the quarter. But, right now, it looks kind of daunting, such a long list. How would you find what you want? Well, you can search in here by just typing for example, 'color', and this will show you the, looks like the seven things that a View can be modified to do related to color. Like Color Invert would invert this probably turn this from black to white. But we know that we want this one, Foreground Color. When you select it, it actually did add it then as one of the sections here, Foreground Color. We don't want blue. We want it to be, let's say, red. So now we have the red border that we want there. This is getting a little bit messy over here in that our code is wrapping, and it's like wrapping in the middle of a function call here. This is why you're going to see a lot of times, these things put on their own line. So I'm going to put that on its own line, that on its own line, that on its own line, very common to do that. We've gotten really good now at taking a basic Lego brick, like the RoundedRectangle or a Text, and modifying it to make it look the way that we want. If we look at these cards, it's just a combination of a RoundedRectangle and some Text. These emoji are just little Text strings. So how do we combine these things? Well, we want to return some kind of View, which is a combiner, a View combiner like the Lego combiner we were talking about before. So, that's exactly what we're going to do. We're going to return a different kind of View called a ZStack. I'm going to talk about in a moment here what a ZStack is all about. Let's get rid of our RoundedRectangle. When we try to create a ZStack, do our little open parentheses, Xcode suggests two different versions. One, which has some alignment argument and then content and another one that is just the content. We'll talk about this alignment in a second, but the key argument to a ZStack is content. So let's type this content argument. This is the label of this argument. And what kind of thing is it? Well, it turns out to be a function. Yes, functional programming strikes again. This is a function and this function is actually going to return a bag of Lego. Remember the bag of Lego in our analogy, when we're building the Millennium Falcon, that's what we have to give the ZStack is this bag of Lego. Swift knows that you're going to want to make these bags of Lego a lot and so it makes it really easy for you to do. It's really enhanced the concept of a function to be able to create a bag of Lego. This kind of function that you pass to a Lego combiner view is called a View builder. Essentially, it lets you list other Views in here and then it bags them up into a bag using this function right here and returns it so that the ZStack will have a bag of Lego to work on. All we need to do is take these things that we've already built down here and just put them in here. We don't need return statements in here. We can just list them. This is very strange function like syntax because there's no return statement involved here. This mechanism, this view builder mechanism, knows how to take this list of Views and actually combine them into another View which is a bag of Lego View. The type of that other View, you don't really need to know what it is, but it's called TupleView. You're never going to be typing that in your code because you don't care. This happens for you automatically, this view building mechanism that creates bag of Lego, and you're gonna use it all the time. You're going to be listing Views like this all the time. This bag of Lego is even more powerful than just listing the Views. You can also put if-then's in here. These bags of Lego can have conditional statements in them. You can even define variables in here. But there's really not much else you can do. It's basically, list Views, use if then's to pick Which views you want to have in the bag of Lego, and then if you need to do some variables you can do that as well. Notice that I've been arranging this in the background here. I had the texts have its things on separate lines as well, but I used indentation so that when I look in this bag of Lego right here, that I'm giving to the Zstack, that the leftmost edge is lining up the actual Views and the modifiers are indented a little bit. What is this ZStack thing going to do with this bag of Lego that we passed it? Well, a ZStack stacks these views on top of each other from the device out towards the user. Exactly what we want, right? When we're building this card, there's this kind of background of the card and then on top of it is this nice string right here, which is the emoji. So it's stacking them towards us. There are other combiners that stack things horizontally and other ones that stack them vertically and other ones that stack them in a grid like this. So we're just starting with the first one which is building the card but when we want to have multiple cards we're going to start using some of those other Lego combiners to combine them in different way. You can see it actually already worked, background card and then here is our "Hello, world!". What we've built here is actually going to be a sum View which is a ZStack that contains a RoundedRectangle and a Text. This is not simply ZStack because the type of the ZStack includes the type of the things that are included in it. So that doesn't really work to say ZStack. We'll let it build. You'll see that won't allow that to happen. That's again, why we need some View. We build this complicated collection of Views that are combined with the ZStack, we want to let the compiler figure out the complicated type that's involved here. So we never type the type with some View we always just let some View get calculated for us. I want to talk a little bit about these modifiers that we have on these. Right now, we have the modifiers on here, each as we want it, but let's talk about what it means to put a modifier on one of these view combiners. It's really kind of two different categories of things that you want to put on a ZStack. One of them might be padding. Currently we have padding on this rectangle, we also have padding on the Text. You can see there's padding around the Text. We currently don't actually need padding around the Text. There's no reason to have this padding around the Text. So if we take it off and we resume, it doesn't really change the way things work. We also have padding on the RoundedRectangle, which we kind of want because we don't want it to be over near the edge right here. But we could put this padding on the ZStack itself. So if I take this padding off of here and put it down here, I'm now doing this padding function on this ZStack that I created. And remember ZStack is just a View, it behaves like a View, therefore it has that function padding, it can be padded as well, and it looks like nothing has changed. By putting that padding on here everything looks the same, but there is a subtle difference. Watch this. If I click on the rectangle, you see the blue line that defined where the rectangle is, it's no longer padded. So there's no padding on the rectangle. If I click on the Zstack, that's where you can see the padding. The blue line goes all the way to the edge right there. View modifiers like padding work perfectly fine on something like a ZStack. There's no difference really between a ZStack and a RoundedRectangle and a Text, in the sense that they're all just Views, so they can all of course be padded. But there are other kinds of modifiers that are a little interesting when it comes to a view combiner. Let's take for example, foregroundColor. Let's take the foregroundColor off of each of our Lego bricks in here and put it on the ZStack instead. Look what happened over there. I put this on here and everything inside the ZStack turned red. The text turned red and the rectangles turned red. So what does it mean to say the foreground color of a combiner is red? The combiner itself doesn't actually draw anything. It combines other things that draw, namely the Rectangle and the Text. So this kind of modifier gets passed on to all the things inside. Putting .foregroundColor(.red) on the ZStack is exactly the same as putting it here and putting it here separately. This is only though the default color, if you put it out here on the ZStack. If I still wanted my text to be orange I could still say .foregroundColor(.orange) and my text would turn orange. So that is allowed. This is going to be a foreground color of it. This is the default that it's inheriting from its container. And remember, we're eventually going to have containers inside containers, inside containers as we build these complicated views and the awesome thing is they'll pass their colors down the chain to each of the levels. So, if this whole grid of cards is red, we're probably going to set the foregroundColor to red at the very top level. At the grid, we're going to set that to be the foregroundColor of the grid and all the things inside, including all these cards, are going to inherit that color. Unless they want to override it, they get that color. Before we move along here, I actually want to clean up my code a little bit. Remember we talked about how Swift doesn't like you to have a lot of extraneous stuff. For example, foregroundColor(Color.orange), we could leave this Color off because Swift can figure out what's going on there. We also know that this return up here, not needed. This is a function, we know it returns some sort of View. The compiler can look in here and see that there's only really this one line of code. This looks like multiple lines of code but really it's one thing. It's a modified Zstack. It's the only thing that's in this function so it knows to return this one thing, especially since it matches some View right there. So we don't need that. But there's some other stuff we don't need here as well. This argument to Zstack, ZStack only takes one argument. It could take another argument by the way. Let's put it in here, alignment. For example, top. That's still stacking these two things on top of each other, the "Hello, world!" and the RoundedRectangle around it, but it's aligning them so they're stuck up at the top instead of the default alignment, which is center. Let's get rid of our orange texts, we want it to all be red. This argument right here, content, its value is a function, one of these special view builder functions right here that wraps this up into a bag of Lego but is still a function. Any time you have a creation of a struct or even calling a function and you're passing an argument whose value is a function, then as long as it's one of the last arguments, it can be removed from being inside the parentheses We have this (alignment: .center) and now I've got this function just kind of hanging out on the edge. It's very similar to this function, hanging out on the edge and this body thing right here. We can just leave this like this. Why do we do that? Why does Swift allow you to just have this last argument? And you can also do the last couple arguments if they're both functions. Why do we have it hanging out outside of the list of parameters? It's purely for looks. It's purely because it looks nice and it's even nicer if you don't have another argument or you're just not going to use that argument. In this case, you can get rid of the parentheses as well. Now you have this beautiful little code here that says, Oh, I got a ZStack on these two things. We're always going to do this. No one ever types, content: this thing. They will all just leave that off. If we want to put the alignment in there, that's fine. We can go back and put alignment in, but if we're not doing that, we just always do this. A lot of people dive right into SwiftUI and they start with this and they don't really even understand what's going on here, but this is just a function that's an argument to ZStack, is the content argument to ZStack, and it's a special function because it's a view builder where you can just list views and it packages them up for you. But it's still nothing more than that. We're going to stick to our pre-pandemic lecture schedule which is to have two 80-minute lectures. So I'm going to stop here and we'll start off next time by continuing this demo and creating multiple cards and making them look a little better, make them scroll around a little bit, adding some buttons, etc. - For more, please visit us@stanford.edu.
Info
Channel: Stanford
Views: 162,843
Rating: 4.9772296 out of 5
Keywords: SwiftUI, Xcode, iOS, iPhone, iPad, Swift, Stanford, CS193p, coding, iOS programming, Memorize, ZStack, Text, RoundedRectangle, some View, Hello World, var body, padding, foregroundColor
Id: bqu6BquVi2M
Channel Id: undefined
Length: 81min 43sec (4903 seconds)
Published: Mon May 17 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.