Featured • iOS, macOS, watchOS • 37:24
Xcode is the development environment for creating great apps for Apple's platforms. Start the week by watching the Xcode team demonstrate the latest features and improved workflows in Xcode 7. This session also provides a complete overview of the in-depth developer tools topics covered at WWDC 2015.
Speaker: Ken Orr
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
[Ken Orr]
Good morning. [applause]
[Ken Orr]
Xcode 7 is our next major release of tools for building Mac, iPhone, iPad and Apple Watch apps. Let's get started this morning and take a look at what's new in Xcode. The biggest news this year is that we've added support for a third platform, Watch OS, and of course, you can build Apple Watch apps right in the same great Xcode tools that you already know. Xcode 7 also includes Swift 2, building on the new programming language we introduced last year. Swift 2 is faster across the board, not only will your apps run faster when you're running and debugging in Xcode, more importantly, they'll run faster on customer devices.
Swift 2 also includes a number of new language features, like Error Handling which introduces an explicit syntax that makes it much more natural to deal with errors in Swift. Availability, Swift now has insight into the minimum OS required for particular API, making it easier for you to adopt new API and also maintaining support for existing OSs.
Testability. Test bundles can now see internal API, letting you get broader test coverage without having to expose anything additional in your sources. Protocol Extensions lets you add methods to any type that implements a particular protocol. You can convert all of your Swift code to Swift 2 using Xcode 7's Migrator. It works great for projects as well as playgrounds.
We have also added a couple of new language features to Objective-C to make it work even better with Swift. Like Generics which let you specify type information for collections. Also Nullability Annotations which let you specify when you expect something it to be nil or non-nil. In Objective-C which makes it really seamless when you want to interact with options in Swift, really nice. We have gone ahead, we have adopted all these language features in our own SDKs. So you will start seeing the benefits today.
Now, if you want to get started with Swift 2 or maybe some of those new APIs you saw yesterday, well there's no better place to do that than in the playground. We introduced playgrounds last year and they have come a long way since then. Not only can you explore and play with code, but now you can explain an idea or a concept all from within a playground.
We have introduced features like Rich Comments which let you explain what's going on in the surrounding code using a simple mark-up syntax. They have beautiful formatting and fonts which really help them stand out. Within these comments you can include things like web links or lists or even images.
We have also made it possible to pull results which were shown in quick-look popovers, you can pull them right into the source code under the line of source that generated them. This really helps tie the cause and the effect much more closely together. This is really nice. You can add almost unlimited functionality to a playground by adding Swift code to the new supporting sources folder.
This helps you keep your playground clean and focused while also giving you a place to put the supporting functionality. There is also a performance one here because the supporting sources, they can be compiled down because they're not run interactively. They're only there to support your playground and that helps them run really, really fast.
Our newest playground feature is Pages which lets you create content that progresses through a topic. For example, if you wanted to author a playground about sorting, you could add an introductory page that went into the fundamentals of sorting and then you could add subsequent pages that covered things like specific sorting algorithms quick sort, bubble sort. Then, when you wanted to provide navigation through the pages, you can add some of the new mark-up syntax we have introduced. Playgrounds are a powerful way to teach. Last year we introduced the guided tour as a playground. This year we have updated it to use Pages.
That's Swift 2 and the new playgrounds. In addition to iOS 9 and OS 10 El Capitan we have added sport for Watch OS 2. The new WatchKit will help make your apps more responsive, but it also gives you more control and flexibility as a developer. If you haven't already, I encourage you to check out What's New in Watch OS 2. Some really nice stuff.
You can build your entire watch app, of course, right in Xcode using storyboards where you can quickly lay out how your app will flow from screen to screen. You can design and implement glances or even the new WatchKit complications. For iOS, using things like the new StackView it never was easier to create a universal app that deals with things such as changing screen orientation or different screen sizes. With the new iPad multitasking, size classes which you define in interface builder, they have never been more important.
Along with iOS 9 we're introducing a new crosscutting feature called App Thinning. The App Store can tailor your app to deliver the best, smallest possible version to each unique customer device. This will let you focus more on building a great app and worry less about size because you will know that customers, they'll never download bits they won't use. Xcode of course has great support to help you configure how your app will be thinned.
There are three separate parts to App Thinning, starting with Bitcode. When you archive for submission, Xcode compiles your app down into an intermediate representation called Bitcode which gets sent to the store. The App Store can later re-optimize your binary, helping you future-proof for things like compiler updates or even new processer capabilities. To take advantage of Bitcode you don't actually have to do anything. Xcode will do all the hard work here.
The second, there is Slicing. When the App Store goes to send your app to a customer device it will only include artwork that's needed for that particular device. For example, if you have both 2x and 3x artwork in your app for an iPhone6 and a 6+ the iPhone6 will only get the 2x artwork and the iPhone6+ will only get the 3x artwork.
To take advantage of Slicing, all you need to do is use Asset Catalogs in Xcode. Third, on-demand resources, which let you control when assets are downloaded. For example, you can start downloading level 5 of your game just as the user is finishing up level 4. It gives you a ton of control. Really nice. Here to give us a demo of Watch OS 2 and App Thinning is Jon.
Jon Hess: Good morning. Today I would like to show you two of my favorite new features in Xcode 7; native-watch extensions and application thinning. Let's get started with our trivia game project. Now in our trivia game we already have things set up for WatchKit 1, and right now I want to update it to Watch OS 2.
It looks like Xcode has the same idea. Here in the navigator, I can see a project modernization sequence already queued up for me. I going to go ahead and select it and begin migrating my project settings to Watch OS 2. Here in the panel, Xcode gives me a brief overview of everything that's going to happen. I would like to go into it with more detail for you.
Just like Watch OS 1, Watch OS 2 applications are composed of an app extension and application. Your code goes in the app extension and drives the app remotely. New in Watch OS 2, both the app extension and the app run directly on the watch. This allows our applications to be more responsive and independent. Sounds great. I want to perform these changes.
What just happened? Xcode took care of the details of migrating my project settings to Watch OS 2. It configured my Watch targets to build against the new Watch OS SDK that we released yesterday, it set their minimum deployment target to Watch OS 2 and it configured my Watch app extension to be copied inside of my Watch app so that when they're installed on the Watch itself they both go over together. All right. That's everything with upgrading my project settings to Watch OS 2.
Our Watch application is nice and light, but our iOS application is a quite bit bigger. It is mostly due to all of these images in my asset catalog. I want to make it smaller but don't want to remove any content. This is where the new App Slicing feature comes in play. You see every one ever these images has a 1, 2, 3x representation? Well with App Slicing, Xcode 7 and the App Store are going to work together to make sure that each device just gets this single image that best suits it.
This cuts 30- to 40 percent off the size of our application and the best part is it's pretty much automatic. All I need to do is use Xcode 7 in an asset catalog which I'm already doing. What about the other assets you would like to target for each device. We have extended the asset catalog in Xcode 7 to support arbitrary data. You can put whatever you want in here.
Down here further in the catalog, I have this skylines folder. It's filled with 3D models of cities from around the world. We present them to the user and they guess which city they are looking at. San Francisco, I have a really high-quality model of the city of San Francisco I would like to include in our game, but I only want to send it to the most high-end devices.
No problem. Just like images can vary by scale factor and size class, data assets can vary by device performance characteristics, things like the amount of memory on the device, or the GPU capabilities. I want to add a specialization for machines with 2 gigabytes of memory. Then I will just go ahead and drag in my high-end resource and I'm good to go. Each device will get the resource that best suits it without double-paying. All right.
Now I would like to show you on-demand resources. On-demand resources allow us to host the content for application remotely on the App Store. We opt our resources in to on-demand hosting by tagging them with strings. The strings can be anything we want. For example, if we're making a game, we might tag each of the assets that comprise one of the levels by that level's name. Then, at run time, we use the new NS Bundle Resource Request class to fetch and pull down whole tags worth of content into our game for fast, local access. Let me show you how to get started with on-demand resources.
Here I've selected a folder in the catalog. It represents all of the questions in the world genre of the game. In the inspector I'm going to use the new on-demand resource tag section and tag this content, world questions. I've just opted all of it in to on-demand hosting.
Now, what kind of things can you tag in a catalog? You can tag entire folders like I just did. You can tag images and data assets directly, you can also tag Sprite Atlases in the Asset catalog. Sprite Atlases are a new component of the Asset catalog in Xcode 7. By putting your Sprite Atlases in the catalog, it makes them eligible for the Splicing feature I mentioned earlier. You can also tag loose files in your Xcode project.
This inspector gives me a great overview of all of the tags on a particular file. What if I want to see all the files in a tag, or just all the tags period. For that, I can head over to the Project Editor, by selecting our Application Target and going to the New Resource tag section I can see all of my tags. As you see, I tagged a lot of content earlier. It is a great place to get an overview and make sure things are consistent like I expect.
For example, I see this books tag doesn't match the format of the others, they all have this question suffix. No problem. I'll edit this, and update all the content in one go. Now with tag to all of our content for on-demand resources, and I would like to show you how to started using it from code. That's where the new NS Bundle resource request class comes into play. Here in our game class, we have two callbacks that will be perfect for this, start using genre and stop using genre.
Two reasons they are great for using on-demand resources first, they are bracketed in time, and second, they happen a just a bit before the user actually initiates the game but as soon as when we know what they're going to play in the game, It lets us pre-fetch the on-demand content.
I'll get started with an instance variable to hold an NS Bundle resource request. NS Bundle resource requests are substantiated from tags, and remember, tags are just simple strings. I'll use our genre's name with batch questions appended to the end to form our tag. Then I can create the bundle resource request from that tag. Finally, I can invoke the request with the new begin accessing resources with completion handler method. This is an asynchronous method that runs in the background. It downloads all the content from the store, and when it's done, it fires my completion handler.
Once my completion handler runs, and until I say I'm done with the resource request, I have fast local access to all the content. This is my favorite part. I get it all, that content with the same APIs I'm already using. Methods like NS Bundle, Path of Resource, UI Image, Image Name, Texture, Texture Name, all continue to work exactly as they did before. I'm not making any changes to the rest of the resource lookout code throughout my application.
Now, I set all that content as available until I say I'm done with the NS Bundle resource request. How do I do that? In our stop using genre method, I'll invoke end accessing resource on the NS Bundle resource request. This moves all the content that I fetched into the cache so it is available for future access but it also marks it as available for purging in the even that the system runs out of space. With that, we have written all of the code we need for on-demand resources. I want to build and run our game. We'll start a new game. I'll show you some of the debugging functionality for working with on-demand resources.
Here in the debug navigator, I'm going to select the disk gage to bring up the disk report to get an overview of all the ways the application is using the disk. We've added a new section here in Xcode 7, on-demand resource tags. You see can see my tags, their size, and their current status.
All that are currently marked not downloaded, Xcode is mimicking the role of the app store right now. All of my resources are in Xcode, not on the simulator yet. But, when I click one of these genres, the code that we just wrote runs in the background, downloads the content and now you see my tag is marked in use. If I switch to a second genre, you can see the first content is moved to the cache, just marked downloaded, and now engineering questions are in use.
That's Slicing and on-demand resources. With Application Slicing, we're able to lower the size of our iPhone 6 application from more than 140 megabytes to less than 100 megabytes. With on-demand resources we were able to further lower the initial install size down to just 30 megabytes. Now users can get started with our game faster than ever. Back to you, Ken. [applause]
[Ken Orr]
Thank you, Jon. This year we have introduced a number of new features targeted squarely at helping you enhance the quality of your app. Let's start by talking about debugging and profiling. In Xcode 7 we have brought the energy gage to iOS apps. IOS 9 contracts energy on a per process basis. That's reflected right here in the energy report.
The gages in Xcode are a great way for you to match what you expect to be happening against what's actually happening. If you see a spike in energy usage and you're sitting in your app apparently idle, that's a first clue that maybe you have a problem. Sometimes when you have a problem like that, you know exactly where to go looking in your code. But when you don't, you can jump right into Instruments from all of the reports in Xcode. From the Energy report we can jump into the New Location instrument which lets us make sure that we're efficiently using core location APIs.
We can answer questions like are we asking for the user's location too often, are we asking for the user's location with too high a precision? Things like that are going to cost energy and we can investigate those right here. For iOS, this is also the new Metal System Trace instrument letting you see how the frame rate is being effected by things like your own code.
The graphics driver, hardware rendering, it gives you insight into the entire Graphic Stack, really powerful. You may also notice here in Instruments that there is a redesigned track view. It has a cleaner look, more importantly it is more natural to use. With gestures like pinch to zoom, navigating through your data is really, really easy. That's a quick peak at the new Instruments.
I'm willing to bet that every developer in this room has been in a situation where a customer reports a crash and you just can't reproduce it. All right. That happened once or twice maybe? The new in Address Sanitizer in Xcode 7 can help. Address Sanitizer compiles your Objective-C in C code in a way that catch things like buffer overflows and it can catch them immediately when they happen. Xcode will stop you right on the line of code that caused the problem. This is a powerful new debugging feature. Here to give us a demo of Address Sanitizer is Kate.
Kate Stone: Thank you, Ken. Our trivia game is a great diversion with friends but some are experiencing crashes when they're setting up a game. It is unpredictable enough that it is the kind of bug that's hard to reproduce and make heads or tails of. I'm sure you experienced something similar as I've heard anywhere you have used pointers to explicitly managed memory.
Our game is looking beautiful. We can dive on in, start a new game, pick a genre, pick a few users to work with and we're ready to play. So it seems to work just fine -- oh. Being on stage is perfect to reproduce this. Hard to find bugs.
So let's have a look at this. It's crashed, where is it crashed? What can I debug? It's crashed in my main class. So there's not even I line of code I've written there. There's nothing in the Stack Trace to give me a place to start. That's typical of this kind of bug.
Luckily, Address Sanitizer can help there. We have a variety of these diagnostic tools that you can get to from Xcode. All you need to do is go to the Scheme editor for running your app. As that handy shortcut, I'll hold down Option while I click on Run to get to the Scheme Editor.
I can configure how I run my application here, including the Diagnostics tab which lets me select some potentially familiar tools as well as the new tool, Address Sanitizer. Enabling Address Sanitizer does something different in that it recompiles the application adding a bunch more Instrumentation showing me not just where I failed but why I failed as well. Let's rerun that application and see how this works.
Now I'll find when I select a genre and move to the next page it immediately stops my application because this is where the memory corruption actually occurred. Far before the application finally comes to a screeching halt I can find out what went wrong. In this case I get the exact Stack of where it stopped and it turns out that it is some Objective-C code that I'm calling.
Not everybody has the luxury of writing everything in Swift. In fact, in our case, we have this C code that's been wrapped in an Objective-C framework. That's the source of our problem. I'm not familiar with this code. I'll have a look at the code that I'm calling it from written in Swift. Here I am calling some logging API. That tells me where exactly I'm triggering the failure but still not yet why.
If I look further down the Debug navigator though, I can see that in addition to Address Sanitizer telling me that I'm using deallocated memory and that that's the actual source of my problem. I can also see in the Debug navigator what memory that is. I'm accessing the first bite in a 50-bite heat region that was previously allocated.
I can go a step further, click on and actually see the memory, and see it has been previously used to store a log message. Because it is gray, Address Sanitizer is telling me that it knows that it is no longer valid memory, no longer memory I should be accessing. It also gives me the call Stack, where that memory was originally allocated and I can see that it is when I'm creating a usage log that makes sense, and more importantly in this case, where that memory was deallocated.
I can tell here that it is when I call end logging, the particularly badly designed API. I thought it was just to flush the log but it turns out it takes down critical resources. Let's solve that problem quickly. I can take that line of code, instead of calling it every time I log a message, I'm going to call it only once during tear down. Now Address Sanitizer rebuilds the application complete with Instrumentation, still very snappy, still possible to use it interactively, and I can get a step further. It all looks good until it finds my next problem.
Because Address Sanitizer is not just about deallocated memory. In this case it is telling me about a heap buffer overflow similarly telling me about under flows and Stack memory that I'm overflowing or under flowing, it is an extraordinarily powerful tool. It's the kind of tool you should use on your applications right now to find all those lurking memory issues.
We tried to make that as easy as possible because Address Sanitizer cannot only run in this interactive form, but you can use it with Xcode Servers so you can set up a suite of tests with Address Sanitizer enabled and find those problems when they creep in your code. Because you want to minimize the number of crashes but let's be realistic, you can't eliminate them entirely. So I'm proud to bring up Itai to talk about how Xcode helps you analyze those crash logs you will get. [applause]
Itai Rom: Thanks, Kate. Good morning, everyone. As Apple developer program members you have access to the new crash logs in Xcode. When you distribute your app through the App Store or TestFlight and include symbol information we'll collect crash logs from your users. Those crash logs will be fully aggregated into crash reports and downloaded into Xcode wher you can view and analyze them right in the organizer window. The integration here is seamless making it easier than ever before to find and fix your most critical issues. I would like to show you how to use it.
Last year we introduced TestFlight. TestFlight is a convenient service for distributing beta builds of your apps and works great with crash logs in Xcode. We just distributed a beta build of our trivia game yesterday. I'll like to find and fix some of the crashes that our testers reported. I'll launch Xcode. I have already entered my Apple ID information into Xcode's Account Preferences panel, so all I have to do to view crashes is open the Organizer window.
On the left side of the window, Xcode will download information about all of the apps that my development team has uploaded to iTunes Connect for the App Store or TestFlight. I'll choose trivia. On the right, I can choose which build of trivia I'm interested in. This build 55 at the top of the list is the one that we distributed through TestFlight yesterday. I'll click that. Underneath Xcode will download information about all of the top crashes. These are sorted by frequency of occurrence, the one at the top of the list is naturally the one that our testers experienced the most often.
To the right I can see the back trace for this crash. Xcode helpfully highlights one of the Stack frames in a beautiful orangey salmon color, that tells me something fishy is happening in my app. In particular that's where my app crashed inside of this usage log and log in method. That looks similar to the crash that Kate just found and fixed using the Address Sanitizer.
That's my favorite type of bug report, I don't have to do anything since I watched her fix it. I'm going to go ahead and mark it as resolved by clicking this button on top of the window. I can have Xcode filter out the crashes I have already resolved by clicking the filter in the bottom of the window.
Now I can focus on the crashes that I still need to fix. We have warmed up with a pretty easy one. Let's take a look at the next crash. This time we're crashing inside of our splash screen view controller, the beautiful landing page in the app where you see a grid of your friends' images. It looks like we're indexing into an array and we might have indexed beyond the array's bounds. I would like to try fixing this crash. I can jump right into my source code by clicking the Open and Project button, selecting my project, and then clicking Open.
Now, Xcode has not only opened my project, it has also magically transported the crash log that I was just viewing in the organizer right into the Debug navigator where I can click through Stack Frames and navigate through my crash log and source code side-by-side. It looks like we're crashing into the next image method. This looks similar to a crash I think Jon came to my office yesterday to tell me he was hitting.
What we're doing is indexing through an array of images of our friends and incrementing a counter as we go. When we get to the end of the end of the array, we set the counter back to zero. We have an easy to miss off by one error here. This should be a greater than or equal to check. I'll fix that.
It looks like you could hit this crash really easily if you don't have very many friends, which probably explains why Jon found it. Now I can go back to the organizer and fix more crashes. The new crash logs feature in Xcode and TestFlight work great together to help you find and fix your most critical issues before you ship to your customers. Now back to Ken. [applause]
[Ken Orr]
Thank you, Itai. Testing. Over the past few years we have continually added to the testing support in Xcode. Making it possible for you to test more and more parts of your application. In Xcode 5 we added a Test navigator. When you combine that with the assistant editor we have a nice workflow for test-driven development.
We have introduced XC Test our unit-testing framework, along with Bots which let you automatically run the unit tests on Xcode Server for continuous integration. In Xcode 6, we introduced performance testing to quickly let you identify performance regressions and added testing for asynchronous APIs. In Xcode 7, we're introducing User Interface testing.
The UI testing lets you test the part of the app that users actually see and touch. The tests like this are so important because they help you ensure that your app continues to function the way you originally intended. Even as you make changes and enhancements over time. Like all the testing features we have added to Xcode, UI Tests work grade with Xcode Server.
This is particularly important for UI Test because they may take a bit longer to run. Also on Xcode Server you will oftentimes have access to many more devices than you would at your desk. This will let you get a broader range of coverage and let you get that coverage more often.
Speaking of coverage, to round things out in Xcode 7, we have added Code Coverage for testing. You can turn on Code Coverage here in the Schemes Test action, and when you do, Xcode will build your app with special instrumentation that lets it track exactly which lines of code are being executed.
After you run a suite of tests, you will notice the New Code Coverage bar here on the right side of the source code editor. This gives you a quick visual indication that shows you exactly which lines of code were called, more importantly it shows you which ones were not. Here to give us a demo of UI testing in Xcode 7 is Joar. [applause]
Joar Wingfors: Thank you, Ken. It is really easy to get started with UI Testing in Xcode. You add a new UI Testing target, like I have done here. If you have used unit testing before, you recognize getting a test case sub class and the method created for you. Had this been a unit test, you would now have to write the test method using your bare hands. Now we can write this for you recording the application. Let's take a look.
I put my curser in the Test Method and start recording by clicking the Record button at the bottom of the window. While recording any event received by my application will result in source code being emitted into my Test Method. For this test I want to configure a new game. I'll go ahead, tap the Start a New Game button.
Note that as I tap the button, the corresponding line of code showed up in the Source Editor right away. Here I'm asked to pick a genre, I'll go with sci-fi for this test. Tap next. I'll invite a couple of players, Alice, Brandon, I'll search for Stacy. There she is. I'll tap done. Tap next. Finally tap the switch to mark the game as ready. With this I'm done with -- with what I wanted to record here. Let's take a look with what we ended up with.
This first line of code contains a query to find a button label start a new game, and it returns what we call an element, an element is a proxy of the actual button in the application. Using this element I can now access properties of the button and also send events, in this case, a tap.
These next couple of lines contains the source code for selecting the sci-fi genre and for tapping the Next button. We designed the UI Testing APIs to be easy to read here, as you see here, to be easy to write and to help you produce robust tests. Now for this to be a test it would have to actually test something, and it already does. If I were to run this test as-is, it would implicitly validate that all the controls that I interacted with while recording are still available to me and fail a test if they're not.
In addition to this implicit validation, I would typically also want to explicitly validate other aspects of my application state at different points throughout the test. In this test, I selected a specific genre and invited a specific set of players. Let's add a couple of assertions to the test to make sure that's what we ended up with.
These assertions validate that there are elements in the UI of the last screen of the application that contains the name of the genre and names of these players. With these assertions in place, I will be allowed to run the test to make sure it performs as expected. No hands. The test passed. [applause]
Joar Wingfors: This is a quick overview of testing in Xcode 7. I think you should all try it. I think you'll love it. More importantly, I think your customers will. Back to you, Ken. [applause]
[Ken Orr]
Great. Thank you, Joar. We have looked at just a few of the many new features this morning. I hope you're excited by what you've seen, and you can see even more throughout this week at the many great sessions which will go into much more detail on Xcode 7. If you haven't already, I encourage you to download the new Xcode and let us know what you think. Thank you very much. [applause]