Xcode is the development environment for creating great apps for Apple platforms. Find out how to take advantage of Xcode features to go all the way from a new project to App Store distribution. Along the way, you'll learn how to navigate the Xcode user interface, how to take advantage of the source editor and live user interface previews, how to incorporate community-developed Swift packages into your app, and how to refactor and test your code, all while developing a working SwiftUI app.
Along with my colleagues Holly and Honza, I'll be walking you through how you can build a simple iOS app using Xcode.
Xcode is an integrated development environment used for developing software in Swift, Objective-C, and other languages.
In the session, we'll be covering how you can create a new project using Xcode, write and navigate your source code in Xcode's Source Editor, run and debug any issues that may exist within your code base, extend the functionality of your app using packages and frameworks, and finally how you can test distribute your app to the App Store.
Let's get started with creating a new project in Xcode. In front of you, you see the Xcode window which I'll be discussing in four different sections.
In the center section is the Source Editor where you can view and edit all of your files.
In particular, we have the Source Editor open and you can use it to navigate and edit all of your source code.
There are other editors available to use such the Project Editor. And here, you can customize your project settings when you need to.
Within the project editor, you will find targets for your app.
A target contains instructions to build one product.
Examples of products include libraries, frameworks, test bundles and the app itself.
To the very left of the Xcode window is the Navigator where you have quick and easy access to all of the content within your project.
You can use the Navigator selector bar to select a navigator. You have many available to you. And because we have the project navigator selected, you can use it to add, delete group, or otherwise manage all of the files that exist within your project.
On the very right is the Inspector and it provides with you contextual data about the contents of your editor.
Because we have the Source Editor open, you can view information about the file that's being displayed such as the file name and the file path.
The top section is a toolbar.
And here, you'll find the Run button which will build and run your product.
The Stop button will terminate the current action in progress.
The next two drop-down menus are the Scheme and the Run Destination.
A scheme a sharable file that contains rules for our how app will be built, run and tested.
The Run Destination is where you will run your app.
You can choose to run your app in a simulator for a device such as the iPhone XR which is what we're doing up here.
You can run it on your Mac or a connected device such as an iPhone or an iPad.
The last three buttons are the Show and Hide buttons which will show and hide different sections of the Xcode window. And these can come handy. For example, if you're developing code and you need more space in the editor, you can use the right mouse button to close the Inspector and provide yourself with that extra space in the editor.
Now, I'd like to bring your attention to the Xcode Help Menu where you have access to resources such as Developer Documentation, Release Notes and Xcode Help.
Xcode Help is an amazing resource for learning about Xcode. And we highly recommend that you browse through it on your own.
So now that we walked through the layout of the Xcode window, let's go ahead and create an actual project from scratch.
So in front of you is the Welcome to Xcode Window. And on the left, you have the option to create a new project which will store all of your files and resources for your app.
You can also clone an existing project that may be hosted on the source control account such as GitHub.
And finally, you can also open up a Xcode Playground which allows you to experiment with your Swift code and then see the result of that code in real time. On the right are all of the projects that we've been recently modifying, and so we have quick and easy access to them. I'm going to go ahead and create a new project in Xcode.
This will open up the template selector.
Templates are starting points for our app. And there are a variety of templates that are available for us to use.
In order to pick the right template, we need to start out by identifying the platform we're developing for. And I know I'm writing an iOS app.
So I'll go ahead and click on the iOS tab.
Within this tab, you'll notice that there are two categories of templates available such as the Application templates and the Framework and the Library templates. For the purpose of this session though, I'm going to go ahead and select an Application template and I'm going to pick the simplest one which is the Single View App and I'll click Next.
So my teammates and I have decided we want to build a meditation application.
And we've decided to call it Mind. So for the Product Name, I'm going to enter in Mind.
For the Organization Name, typically, I would put in the name of my organization, but for the purposes of this session, I'm going to call ourselves Example Team.
The Organization Identifier is then the reversed DNS of the organization name. So in this case, it is com.exampleteam.
Finally, the Bundle Identifier is autofilled and it is a unique ID for your app within Apple's ecosystem. It is a combination of the Product Name and the Organization Identifier.
For the Language, I will go ahead and leave at Swift because I want to write my app in Swift.
And I will ensure that I have UI Tests included so that it creates a target for them. Because as developers, we want to be in the habit of constantly testing our code.
We'll show you later how to add unit tests. So after you click Finish, it will open to Save sheet.
Here, I can decide where I want to save my app.
It defaults to the Desktop and I'm happy with that.
So I'll leave that as is.
But one thing that I do want to ensure is that Source Control is available from the very beginning of this project so that I can manage, track and backup any changes that I make during the development process. So I will go ahead and check the Create a Git Repository on my Mac checkbox and I'll click Create.
So we have our template setup now.
We can add an app icon to our app. App icons are the images that a user will select whenever they want to launch our app.
App icons are assets.
Examples of assets include images and colors.
Assets are managed and organized by an asset catalog and we can access that asset catalog through the Navigator by clicking on it. And because we want the catalog for our app icon, let's go ahead and click on the app icon and the editor.
And you'll notice from the catalog that you can have assets for Notifications, Settings, Spotlight as well as the app itself. So I have an app icon sitting on my desktop. It's ready to be used.
And I have device that uses 2X resolution. So app icon-- assets are available for 1X, 2X and 3X resolution depending upon the device you use. So I'm going to ahead and grab this app icon and drag it into the 2X catalog box for the iPhone app.
Now, I want to test my app icon to make sure that it actually works.
So to do that, I want to run it in a simulator for the iPhone XR.
So I'll change my Run Destination to the iPhone XR, and then I'll click the Run button.
This will launch the simulator. And you'll notice that the simulator goes about launching my app immediately. I know this because it's displaying Hello World and that's what my template is set up to do.
So I need to go to the Hardware Menu to actually see my app icon in the home screen. So I'll go to the Hardware Menu and click on Home.
This will bring me to the home screen and I see my app icon is there. If I click on app icon, my app comes back into the foreground. So great, I know that my app icon works. I can terminate execution of the simulator. And now, we're at a good point where we can commit and save our changes so that our colleagues Holly and Honza can continue developing on this app-- on this project.
To do that, we first need to add a GitHub account.
We can do that through Xcode Preferences which you can access from the Xcode Menu and then going to Preferences.
Xcode Preferences lets you customize Xcode for your needs.
And in order to add an account, we'll go ahead and ago to the Account Preference Pane and click on the Plus button.
You'll see that there are a variety of accounts that are available to us. And since we're interested in the GitHub account, we'll click on GitHub and click Continue.
So now it's asking me for my account credentials so I am going to go ahead and type in my account name and my password.
So it's signed in to my account which is great, so I'll go ahead and close Xcode Preferences.
And now, I need to make the actual commit. So to do that I'll go the Source Control Menu and I'll click on Commit.
This will open up the commit sheet. And here you can verify all of the changes you made and you can add a commit message to let your colleagues know what you changed. So for the commit message, I'll say that this commit will add an app icon.
And I'll click commit which will close the commit sheet.
So now to get to this point in our development, we started out by creating a project using Xcode.
We then chose a template that was appropriate for our platform.
We added an app icon to our asset catalogue and then we used Xcode source control functionality to commit our changes so that our colleagues could continue developing on our project.
To learn more about Source Control we recommend that you check out the Source Control Workflows in Xcode talk from 2018.
Now we're at a point where we can start adding actual meditation functionality to our app.
And to do that, I'm going to invite up my colleague Holly. Thank you.
My name is Holly and I'm an engineer on the Xcode Source Editor team.
And welcome to the Source Editor.
This is where you will write all of the code for your app.
To the left of the Source Code we have the line numbers, and to the right of the code we have the mini map which shows you a miniature view of the file in the editor for navigation.
Above the source code we have the Jump Bar.
The Jump bar also helps you navigate the file in the editor using the function popup.
The Jump Bar also lets you customize the layout of your editor using the Editor Options and Editor Split menus.
We are already making great progress on building our meditation app.
Let's have a look at where we're headed.
We are building a meditation app that allows users to select a duration and meditate for that amount of time.
When the meditation is over, the app will write the user's mindful minutes back to their health data.
We'll need to add quite a bit of Swift code to get our app working.
But instead of trying to read the code that I write, I want you to focus on the tools that Xcode provides to aid the editing process. And if you're new to Swift, welcome.
To get started with Swift, I recommend going through the Swift guided tour which is available online or in an Xcode Playground so that you can experiment with the Swift code as you walk through the tour.
This resource is available on docs.swift.org.
And with that, let's head over to Xcode.
I added some code to the project template that Prachi showed us to implement timing of meditation and drawing a peaceful background for the app.
We still have to implement a UI for selecting a meditation duration and for starting the meditation.
We also have to implement the class that interacts with HealthKit.
To get our app up and running really quickly, I implemented a mock HealthStore that does not interact with HealthKit and we'll implement the real HealthStore later.
So here, we're looking at the ContentView.swift from the project template and I added a title and a background.
While building the UI for your app, Xcode can show you a preview of what your UI will look like on an interactive Canvas.
To show the Canvas, we can select the Editor Menu and click Editor and Canvas.
The Canvas will build and run your code as you edit so that it can show you the results of your code in real time.
So now in the preview, we can see the welcome title and the peaceful background.
Next, I want to add a meditation view. So I'll create a new file, and I'll use the SwiftUI View file template.
And I'm going to call this MeditationView.
Right now, the preview is showing me a full device, but the view that I'm working on is only taking up a small portion of the screen.
I can modify the preview provider which is what's supplying the view to show on the Canvas to only show the view that I'm working on using the previewLayout modifier.
When I start to type the modifier, Xcode will bring up the Code Completion Window.
This shows me a list of suggested symbols based on the text that I typed as well as the surrounding context of the code.
The modifier that I want is the first one in the completion list and I can press Enter to accept the suggestion. Now Xcode inserted the symbol into the editor along with the placeholder for me to fill out the remaining code. And I'll fill that out now with a sizeThatFits.
Next, I know that my MeditationView will need to interact with the MeditationController.
So I am going to add a property wrapper that wraps a MeditationController, and I'll resume the preview.
If you're unsure of what a certain API does in the Source Editor, you can view documentation for that API by holding down Option and clicking on the symbol that you want to view documentation for.
This will bring up the Quick Help popover which shows me the declaration of the symbol along with its documentation.
Before we move on, I need to supply a MeditationController using the environmentObject modifier.
Now, let's start building up this view.
Right now, we have text that's showing us Hello World, and I want to change this to show the remaining time for the meditation which I can get from the MeditationController.
And as I updated the code in the editor, the preview updated to reflect this change.
Now, the text looks a little small to me and I can make it larger using the Inspector.
So, I'll show the Inspector from the button in the Xcode Toolbar. And I'll click on the Attributes icon.
Then I'll click on the view that I want to inspect.
And here I can see the values of all of the modifiers being applied to this view.
Right now, the font is inherited, and I can change it by clicking on the Menu, and selecting Large Title.
When I do that, the preview updates and the Source Editor automatically adds in the code required to make this change.
Above the text, I want to show a button to allow users to pause and resume their meditation.
You can add in ready to use resources into the file that you're working on using the Library which you can access by clicking on the plus button in the toolbar.
The Library has different categories of objects including views, modifiers, and code snippets.
Let's look at the code snippets category.
Xcode has built in code snippets and you can add your own snippets too for fragments of code that you write frequently.
Here, you can see all of the snippets that I have added to allow us to add code really quickly during this demo.
But now I'll switch back to the View Category, and I can type in the view that I'm looking for.
I can drag in this button into the Source Editor or directly on to a preview.
And now the Canvas is telling me that this button will be added to a new vertical stack along with the existing text. When I drop the button, the Source Editor will add in the necessary code to embed both the button, and the text into a vertical stack by adding a VStack.
And now I can fill in the placeholders.
When we tap the button, we want to toggle the meditation.
and rather than showing text, I want to show an icon that's either showing play or pause.
Now finally, I only want to show the remaining time if the user is actively meditating.
Otherwise, I want to show a picker with preset meditation durations.
Xcode knows a lot about the structure of the code that I have written in the editor, and it can help me transform and refactor my code using structured editing.
If I hold on Command and click on a code structure such as Text, Xcode will show me the Action Menu which has many different actions that I can perform to transform this code structure.
There are also options in the Menu to Jump to Definition and to view Quick Help for the text symbol.
Since I only want to show the text under a certain condition, I'll click on Make Conditional.
And now I can fill in the placeholders again.
The condition is if the meditation is active.
And now, I have another placeholder further down in the file. And I can jump to it, using the Control-forward slash key binding which helps me really quickly fill out the missing code without even having to touch the mouse.
Now, this is exactly what I want my meditation view to look like.
So now, I'll switch back to the ContentView to add it there.
I want to add my MeditationView to the bottom of this VStack along with another spacer.
And now, the preview has updated to show me my welcome title, my Play button and my picker to select the meditation duration.
Now, that I'm done with the UI, I'm going to close the Canvas.
And I'll hide the Inspector to make some more room in the editor.
Before, we try to run our app, I want to modify the MeditationController to make debugging a little easier.
And here, I'm going to use the mini map to navigate to the Meditation Timer State section of code.
The mini map shows me text labels for all of the marks throughout this file.
And I can navigate to a mark by clicking on the label in the mini map.
A mark is a special comment that Xcode understands to show your sections of code any editor, in the jump bar and into the mini map.
Now, in this section of code, I have several computed properties that indicate state.
To make inspecting the state easier, I'm going to add a stored property called State that has one of the possible values stopped, paused, or running.
And I'll default this to stopped.
Now, when we update the MeditationTimer, we want to look at the timer state and update the controller state using a switch statement.
The possible values of the timer state are nil, paused and running. And in Swift, switch statements must be exhaustive.
If they're not, I'll get a compiler error telling me to add the missing cases. And notice that I've gotten a compiler error in my editor without even building my code.
These are called live issues and they appear as you type.
So if I click on the live issue, I get a Fix-It asking me if I want to add the missing cases. And I do. So I'll go ahead and click on that.
Now in the case where the timer is nil, I want the state to be stopped.
Now, rather than having a catch all case for all of the possible values that can be wrapped, I want explicit cases for each of those values.
So I'll change this underscore to the first value which is running.
And now that I've done that, this switch statement is no longer exhaustive.
So, I'll get another live issue with another Fix-It to add at there with last remaining case.
And I don't need this associated value so I'll go ahead and remove that.
You may have noticed that these two names, running and paused, are the same as the remaining cases of this State enum. And I can use multi-cursor editing to quickly fill out the code placeholders.
Right now, I have one insertion point, and I can add another one by holding down Control and Shift and clicking where I want to place my next insertion point.
Now that I have multiple insertion points, I can perform any command and that command will act on each my insertion points.
To see all of the commands that are available, you can go to the Xcode Preferences, select the Key Bindings Tab.
And here you can see all of the commands and their key bindings, and you can even change the key binding to be whatever you like. So I'll will show you a few now.
I can select the word back, copy, jump to next placeholder, type and paste.
And now, we're done.
And this is all of the code that we need to implement the basic functionality of our App.
Before we dive into running and debugging, let's review what we learned about the Source Editor.
We saw how Xcode's interactive Canvas can help us preview the UI of our app and help us edit the appearance of our views.
We learned how code completion can greatly speed up the development process.
Then we saw how Xcode can help us transform and add functionality to our code structures automatically from the Action Menu. And finally, we saw how live issues and Fix-Its can help us fix our compiler errors before even building our project.
For more information on the new Swift language features that we saw or the SwiftUI framework that we built-- that we used to build up our views, please watch the What's New in Swift and the Introducing SwiftUI Session recordings.
And now that we're ready to run the app, I'm going to hand it off to Honza to walk us through running and the bugging.
Hi, my name is Honza and I'm and Xcode engineer.
So now that Prachi created our project and Holly added some codes to it, we'll talk about how we can build, run and debug our app on the simulator and on a real device.
And then, we'll add a Swift Package dependency that allows us to add new feature to our app.
So let's get started.
So Prachi has shown you how to build and run our app using the Run button in the toolbar.
But we can also do this from the Product Menu where we have the options to Run, Test, Archive, Build and many more.
So right now, I will run the app on the simulator.
The app is being built, installed, and launched on the iPhone simulator, and the simulator app comes to the foreground automatically.
So this is what our app looks like right now.
So, because we're moving pretty fast, let's do a quick meditation using our new app. All I have to do is click on the Play button to start a new 3 minute meditation.
So the meditation started correctly, but the Play icon didn't change which I think is wrong.
Just like in music apps, we want to show the Play icon when the meditation is paused, and the Pause icon when the meditation is running.
So we'll use the debugger integration in Xcode to help us find and fix this bug.
To run our app with debugger attached to it, I don't need to do anything special.
As when I just run my app right now, Xcode automatically attached debugger. So, I'll leave the app running in the simulator right now and go back to Xcode.
And we'll start to looking in the MeditationView.
We'll get to the MeditationView by using the Jump Bar.
And the MeditationView is responsible for showing the Play icon and the remaining time label.
And here, it seems that we're getting the image from the MeditationController's displayedIcon property.
So, to get there, I will Command click on displayedIcon and select Jump to Definition.
And here we are in the MeditationController.
So I will add a breakpoint to the second line of the displayedIcon property getter by clicking on the line number.
And because the app is still running in the simulator and the timer is still ticking, the breakpoint got hit right away and highlighted the line in green.
Breakpoints in general allow us to pause the app's execution when it hits a specific line of code.
So at the bottom of the Xcode window now, let me make this a bit bigger, we have to debug area, at top of which is the Debug Bar with the buttons to control the debugger, as well as to activate features like the View Debugger, the Memory Graph Debugger and more.
Below it, we have the variables view on the left and the console on the right.
And finally, on the left hand side of the Xcode window, we have to Debug Navigator within information about our running app, like how much work it's doing, how much memory it's using.
And below it, we have to calls stack.
The call stack is the record of how this code is being called.
And when I select a different frame in the call stack, Xcode switches the Source Editor, the debugger, and even the variables down here.
So, I'll switch back to the original frame and we'll get back to trying to fix the bug where the icon didn't change after we started the meditation.
So, let's look at and which icon is being used to right now. I can do that by selecting the variable and clicking on the Quick Look icon at the bottom.
And here, we get a preview.
And because the variable that we're previewing is an image, we actually got a rendered version and damage right here in Xcode.
Quick Look preview supports images, colors, views, any custom objects that implement the debug Quick Look object method. So in the preview, we can see that we're still showing the Play icon even though the meditation is already running.
So I wonder if it's because the MeditationController is in the wrong state.
To find that out, I will expand the self variable which refers to the MeditationController we're debugging here and we reveal the properties. And one of them is the state property that is telling us that the MeditationController is in the running state.
So that's what I expected. And that means that the displayedIcon property getter is not taking the state of the MeditationController into account when picking which icon to show.
So to fix that, we will check if the MeditationController is running.
And if so, we will show the pause it, we will show the Pause icon, and otherwise, we'll show the Play icon.
Now, because I don't need the breakpoint anymore, I will remove it by dragging out and letting go.
And because we changed the code just now, I will stop the app and click the Run button again. This recompiles the project, reinstalls and relaunches the app in the simulator.
Now this time, when I start a new meditation, we can see that the icon changed from Play to Pause. So the bug is fixed. Great.
So we'll stop the app for now and we'll hide the debug area.
So, we have been running our app on the simulator which is a great way to quickly iterate on our code.
But I would also like to install my app on a real device so that I can start meditating on the go as well.
First, to be able to run-- to install and run apps on connected devices, we have to sign into Xcode with our Apple ID.
We'll do that by going to Xcode Preferences, select an account, and adding new account.
We'll select the Apple ID, type in the username and password.
And there, we sign in to Xcode with our Apple ID.
Next, I'll close the window and I will go to the Project Navigator and select the project.
Here, we'll select the app target and go to the Signing &Capabilities Tab.
This is where we manage code signing and capabilities.
Capabilities allow us to declare what permissions our app needs.
And in our case, we need to access to the HealthKit data to be able to write meditations that the user performed in our app, but also to read meditations that the user performed in other apps so, that we can show them statistics for all of their mindfulness activity.
So we'll add a new capability, search for health, and select the HealthKit capability.
Next, I have this iPhone connected to my Mac here.
So, I will select that as the run destination, and I will click Run.
Now, the app is being built for the device, installed, and launched there. And so that you can watch what's going on on the screen, we'll use QuickTime Player which allows me to stream the iPhone screen back to the Mac.
So there, we have Mind running on a real iPhone now and I could just unplug this phone and start meditating on the go.
Now, let me stop the app and switch the destination back to the simulator.
When you want to find out more about devices, you can go Window, Devices and Simulators where we can see the name, the type, and the OS version of the device, as well as we can see the installed apps that we've put there.
But also, we could actually configure the device to connect to Mac over WiFi.
In that way, I wouldn't need to physically plug in the phone to the Mac over USB at all and I would still be able to build, run, and debug on it.
So, now that we successfully run our app both on the simulator and on our device and we even fixed a bug in it using the debugger, let's talk about adding more functionality to our app. I'd like our app to show the users statistics about their meditations, like how many they have performed, what the average duration was, and so on.
But calculating statistics is not a specific problem to just our meditation app.
So we have created a Swift Package called QuickStats that solves that problem for us.
A Swift Package is basically a folder with the manifest file and source files that you can use to build products like our QuickStats library.
To add the package to our project, I will go to the project editor and select Swift Packages at the top.
Here, I will add a new package to our project.
And because Prachi signed us into GitHub with our account, we can actually see all the repositories that our account has favorited.
QuickStats is right here at the top, so I'll select it.
We'll, use version 1. That looks good.
And this is where we make sure that the QuickStats library gets linked with our app. I'll click Finish, and now Xcode manages the fetching of the package in the background.
And in the Project Navigator, there's an Swift Package dependency section where I can actually browse the sources of the package which is a great way to understand how the package works under the hood. Now, before I hand it back over to Holly to integrate this package into our project, let's do a quick recap.
We saw how we can run and debug our app on the simulator.
And we also ran our app on a real device.
And then we added the Swift Package dependency to our project that allows us to add a feature to our app.
These are the sessions relevant to the topics discussed in this demo. And next, please welcome Holly back. Thank you.
During this demo, we will see how to use the QuickStats package in our project.
After that, we will walk through how to restructure our project by moving our model code into a framework.
Let's head back to Xcode to get started.
Now, that we've added the QuickStats package, we can import the package into our code and start using its public APIs. As Honza mentioned, we want to show our users some statistics about their meditation sessions in the ContentView.
We'll jump back to the ContentView.swift using Open Quickly which you can find under the File Menu.
In Open Quickly, I can enter any type name, method name, or file name to navigate to.
So I'll type Contentview and press Enter.
The first thing that I need to do is import QuickStats.
Now we're ready to start using the APIs from this package.
I'm going to add some code below the contentView from a code snippet that implements StatisticsView that takes in an array of meditation sessions and displays statistics about those sessions using QuickStats APIs.
Since I have access to all of the package source code, I can jump to the source code implementation to understand how it works.
So if I Command click on QuickStats.averageDuration and select Jump to Definition, I'm now looking at the actual implementation of this method.
I can see where the file is in the Project Navigator by clicking on Navigate, Reveal in Project Navigator.
And now we can see that we're in the package source code.
I can navigate back to the previous file by using the Editor History button in the Jump Bar. Now, let's add the StatisticsView to the ContentView.
But before we do that, I want to show the Canvas.
And I'll zoom out so we can see the full device. I'll add the StatisticsView below the spacer and it takes in an array of sessions which we can get from the MeditationController.
Now, we can see the StatisticsView at the bottom of our ContentView.
And now that I'm done with the UI, I'll close the Canvas again.
Now, we want to start writing unit tests for our model. And to make this easier, we are going to move our model code into a unit testable framework.
I could choose to use a Swift Package, but I only want to share this code with my team. So I'm going to choose a framework instead.
We need to create a new target and I can use the filter bar to search for the framework.
And I'm going to call this framework MindKit. I want to make sure to check the box to include a unit tests so that a unit test target is automatically created when I create the framework.
Now, before I move the code over, I want to import MindKit into all of the files that I know will need it.
I know I'm going to move over HealthStore.swift. And this file has two public types that are used throughout the project.
And I'm going to use the Find Navigator to figure out where these types are used.
I'll switch to Find Navigator, and the Find Navigator allows me to search my entire project for text, symbol references, regular expressions and more.
Right now, I want a regular expression and I want to search for HealthSession or HealthStore.
And I'll press Enter to see the results. I know that I'm going to be moving HealthStore.swift and HealthStoreFactory.swift into the MindKit framework. And I can these results by clicking on the disclosure triangle.
Now, I'll navigate to each of these files and add the import. So I'll jump to the top of the file here, and the import, and then finally, we need it in ContentView.swift.
Now, we're ready to move the files over. So I'll switch back to the Project Navigator. As I mentioned, I want to move over HealthStore.swift, but I also want to move over HealthStoreFactory.swift.
I can select multiple files in the Project Navigator by holding down Command and clicking on the other files that I want to select.
Then, I can drag these selected files into the MindKit group.
When I do this, Xcode automatically updates the target membership for these files.
And we can verify this by showing the Inspector and seeing that the target membership for the file open in the editor which is HealthStore.swift is now the MindKit framework target rather than the Mind app target.
Now, I haven't forgotten that we still need to implement the HealthStore that interacts with HealthKit.
We're going to do that now so that we can start integrating real health data into our app.
The first thing that I need to do is import HealthKit. Now, I've never used HealthKit before. So to get started, I want to read the documentation.
I can do this right in Xcode by opening the Developer Documentation window which you can find in the Help Menu.
Here, you can search for a framework from the SDK, a specific API, or a programming topic, such as requesting access to health data.
So here I'll search for HealthKit.
And now I have access to all of the documentation for the entire framework. And this is also available offline.
Luckily, I have all of the code that I need ready in a code snippet. And I'll add that at the end of the file.
Now, before we start writing unit tests, I want to add my own documentation for the APIs in the MindKit framework starting with the HealthStore protocol.
I can do this using special comments called doc comments.
Xcode knows how to generate a doc comment template for declarations.
And this feature is available through the Action Menu.
So, I'll Command click on the first API that I want to document which is requestAccess. And then I'll select Add Documentation.
Now, Xcode has inserted a doc comment template with placeholders for the method description as well as the description of the parameter that it takes in.
So this method requests permission from the user to access mindful sessions. And the completion parameter is a closure to execute when the request is done.
Now, I know that this method can execute asynchronously. And I want to add a special note that-- to document that.
And I can do that using a special bullet point. And now I can add that note. Now that I have written the documentation, I can view this in Quick Help.
Again, we can bring up the Quick Help popover by option clicking on the symbol that we want to view documentation for.
And now we can see the description that we just wrote, the note that we wrote as well as the description of the parameter. And this is available at any call site of request access.
For more information on writing and documenting your own APIs, please see the Swift API Design Guidelines which is available on swift.org. During this demo, we covered how to use and navigate code from a Swift Package.
We talked about creating a new framework target in our project and moving existing code over into that framework.
Next, we looked at the Xcode Developer Documentation Window. And finally, we learned how to write our own documentation through doc comments. Now, I'll hand it back over to Honza to talk about Testing and Distribution.
Now, in this section, we'll talk about how we can test our code in Xcode, and how to distribute our app once we're ready to ship.
Now, since our app is coming along pretty nicely, we need to make sure that it continues to work properly.
A great way to increase our confidence in the app's quality is by using automated tests.
There are two high level categories of tests that we will write for our app -- unit and UI tests.
Unit test ensure that a single component such as our HealthStore works properly by giving it a specific input and verifying that the output matches our expectations.
UI test on the other hand ensure that all these components are integrated correctly and that the app works from the user's perspective.
So let's dive back into Xcode.
So Holly already created the unit test target for the MindKit framework called MindKitTests.
But we'll still need to add it into our test plan.
A test plan is a file-- a repository that describes how our tests are built and run.
A way to see which test plan our scheme is using is to go-- to click on the Scheme and select Edit Scheme.
We'll switch to the Test Action, and here we can see all the test plans used by our scheme. There's only one and that the default. So we'll jump to it by clicking on the jump arrow next to the test plan's name.
The Test Plan Editor shows us which test targets it's using and we already have the UI test target here for which we'll write code in a minute, but we'll still need to add the unit's test target.
We'll do that by clicking on the Plus button at the bottom and selecting MindKitTests.
Now, let's actually write our unit test code.
I will write some unit tests for our HealthStore.
So what I'll do now is to Control click on the MindKitTests group and select New File. I will use the Unit Test file template and we'll name the file Test HealthStore.
That looks good.
The first thing we'll do here is import MindKit because that is where the code lives now.
And to be able to test not only public but also internal interfaces of the MindKit framework, we'll add the testable keyword to the import.
Next, I'll add two tests to our class.
The first one verifies that after we saved a meditation, we can retrieve it right back.
And the second one ensures that we can actually request access to read and write data.
So I'll run these tests by going to Product, Test.
Now, these tests are being built for the simulator and run on the iPhone XR simulator.
Now that the tests are finished, we can actually see next to the test name in the Source Editor diamonds that both of them succeeded.
Good. Now, we can also see the test hierarchy in the Test Navigator.
So we added a few unit tests for our HealthStore but we want to make sure that the UI of our app works as well.
So we'll add some code to our UI test.
I'll jump to the existing MindUITests class by selecting it in the Test Navigator.
And here, we will add UI test code that launches our app, starts a new meditation, a few seconds later, it pauses the meditation, and then finally, it verifies the remaining time label, shows what we expect.
So I will run our test again.
And this time, I'll bring the simulator to the foreground so that we can watch the UI test run.
So the app is launched and new meditation has started. And a few seconds later, it gets paused and the app gets terminated.
Next, we can also see the unit test launched the app for a moment.
Now, it seems that some of our tests failed. And to figure out what exactly happened, we'll go to the Report Navigator by clicking on the right most Navigator button.
Here, I'll select the top which is the most recent test action and we get to the test reports.
Here, I can see that the new UI test I just added is marked in red which means that it failed.
And to know what exactly happened, I will disclose the test and drill into the failing activities to see that the search in failure says that 02:56 is not equal to 2:56.
Now, this is starting to make sense. But to really understand what was on screen when the failure occurred, I can disclose the failure itself to reveal an automatic screenshot which I can preview the click icon.
And here, I can clearly see that the remaining timer label shows 02:56 but our test assertion at 2:56.
So I'll close the preview and we'll jump back to the test source by clicking on the jump arrow next to the test name.
And here, we'll fix the assertion by adding, deleting zero.
Now, I'll rerun just this one test by clicking on the test diamond next to the test name.
And again, we can see the app being launched and new meditation starts, few seconds later it gets pause, the app gets executed, and this time-- terminated, sorry, and this time, we can actually see with the test diamond that the test succeeded. That's great.
Finally, now that we have a functional app, we would like to make it available to more people.
To build an app for distribution on the App Store or TestFlight, which is Apple's beta testing service, we need to perform an archive.
To do that, we first select the generic iOS device run destination, and then select Product Archive.
And this builds the app in the release configuration and produces an archive that we can use to distribute our app. When it finishes, it opens the organizer automatically, and here, when we select the archive, we can click Distribute App. And we would go through this flow to submit our app directly to Apple from Xcode.
Please note that to deploy apps to TestFlight or the App Store, you'll need to register developer account associated with your Apple ID.
Once your app has been uploaded, you can manage it using the App Store Connect website.
And this way, you can ask your friends and family or your colleagues to download your app using TestFlight and eventually getting listed-- get it listed on the App Store as well. So in this demo, we started by creating unit and UI tests for our app. And then we learned how to edit our test plan and how to use the Test Report to diagnose a test failure.
Then we built an archive and discussed how to use the organizer to upload our app to TestFlight or the App Store. To learn more about these topics, please refer to these talks.
And now, let's recap what we saw in the last hour.
Today, we went through the whole journey of creating an app from scratch.
Prachi created our project and introduced the Xcode UI.
Then Holly added codes to our app using the Source Editor features to make that process really smooth and fun.
Then I came up to discuss running and debugging on the simulator and device, and we added a Swift Package to our project.
Then Holly came up and integrated the Swift Package and split some of our code into a framework.
And finally, we just learned how to use the testing integration in Xcode and how to distribute our app to the App Store or TestFlight.
For more information about the session, please refer to this link. And if you have any questions, there's a lab starting right after this session ends.
And have a great week. Thank you very much.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.