[ Silence ]
Good afternoon, and welcome.
How's everybody doing?
It's been a fun week, excellent, good.
I'm Gordie Freedman.
I work on UIKit, and today we're going to talk about State restoration on iOS.
So has this happened to you?
You're using an application, you go to do something else, and when you go back, the application's lost your place.
Maybe you were typing something, maybe you were reading something and scrolled somewhere, but the application went back to the beginning.
In fact, maybe you don't really remember what you were doing.
You were hoping the application would remember.
And as developers, we don't want this to happen to the users of our apps.
It can be very frustrating.
But the good news is we've got some really nice APIs that make it very easy to provide a seamless experience when applications start back up.
I'm going to talk about four things today.
First I'm going to go over a small recap of the feature.
It's not a full review.
We did a session last year in 2012, and if you want to fill in some of the gaps, you can go watch that.
We also have some documentation online, and you can check that out.
But I think even if you're not that familiar, you'll be able to follow along just fine.
I'm going to focus a lot on what's new in iOS 7.
We'll see what we've added and how that plays.
We're going to talk a little bit about security and background operation couple of interesting topics that I think we might want to spend a little time thinking about.
And then finally, I'm going to go over some of the tools that we have that can help you to be able to both validate that you're doing or your app is doing what you expect, and help diagnose problems.
So when we talk about state restoration, it's a simple idea one application to just go back exactly where it was so the user's experience is not interrupted, as if the application had just been in the background all the time.
And if the application exits and restarts, the user won't know.
And it really is predicated on how the user views this, and we want to think a lot about what the user's doing.
You want to look at the different parts of your application and examine what you need to save and what you need to restore.
And that's great, but start at the top down.
Think about it as if you're using the application and think, "If I was using this and it went away, where do I want it to come back," and then from there, let that inform what you save and restore.
I'm going to give a short demo just to kind of highlight what I'm talking about.
So I've got a very simple application, got a collection view, you can see, do the nice collection view layout stuff.
And I'm going to scroll around and look for an image that I want to see.
So these are all thumbnails with little titles pretty standard stuff.
I'm going to select one you can see that I've got the selection there let it roll in.
Let's make it a little bigger so it's easier to see.
Maybe I'll even get rid of these bars here and make it like that.
So as a user you might find an interesting picture and then you want to go show it to somebody, or the phone rings, or something happens.
The application goes into the background.
And the application can exit if left alone for awhile for various reasons, so I'm going to force that here.
Now, I just want to point out one thing.
Ordinarily when a user goes into the switcher and flips an app up like I just did, it'll get rid of all the state restoration information.
We do that on purpose to kind of save a user if every time they run the app, it starts up in a bad state and they're stuck.
First thing a frustrated user might do is go in and flick that up.
We'll get rid of the state, give them a clean start if that happens.
Hopefully it won't, but it's an out.
But for developers, sometimes you don't want that to happen.
If you're trying to chase a bug, you're trying to diagnose something or just simply testing, it's very convenient to go in, kill the app and restart it.
You don't want to lose the info.
And I'll talk about that a little more later, but I'm using that trick here just to make the demo a little easier.
So the app's not running now, and if the user walked up to their friend and said, "Hey, look at this cool picture," well, let's see what happens if we start it back up.
And it goes right back to where it was.
It remembered that we weren't showing any of the bars, remembered the size of the image, and even some things that are behind the scenes.
Let's go here, I'm just going to peel it back with our cool new gesture, and you can see that it remembered the scrollPosition and the selected cell.
So that's a pretty unexciting demo, but it was supposed to be actually.
The idea is it's predictable, the users get what they want, and it's nice and easy for everybody.
So let's look at what we did in order to accomplish that.
So first, what was actually restored?
We saw it from the user's perspective, but as a developer, what were the constituent pieces?
We had a navigation controller.
It remembered what was pushed on it.
We also remembered the scrollPosition in our collection view and the selected cell.
And finally, we remembered what image we were showing, the transformation we applied to resize it.
So you'll find that when you write state restoration code, a lot of what you do is map what your application has already done into what you need to save and restore.
Typically, you'll find that there's a lot of really strong parallels between code you've already written, ad in fact, you'll be able to leverage and reuse most of the code you've written.
So here, let's see what happens before we even saved state when the user selected that cell and we pushed on that image view controller.
If we didn't take any action and we just loaded the view controller, we wouldn't have an image or a title.
We want to put something there, and we also want to remember that we're going to change that title up top, too.
So what do we do?
Well, we have a method called prepare for segway that you use when you have storyboards.
So that's what I have in the example here.
And then prepare for segway, I hand the view controller that's coming in, our image view controller, enough information so that it can get the image and set that title.
So now when I did that segway, we actually have that information right there.
So similarly, when I save and restoreState, I'm going to want to be able to maintain that.
So what do we do?
Well, let's look at how we saved state.
When the application goes in the background, we're going to go all the view controllers with identifiers, all the view controllers that need to save their state, and give them a chance.
So we're going to call them method encodeRestorableState with coder.
We're going to hand a key to archiver where it can stash any information it wants to restore later.
So what do we need to save here?
Well, we've got the image, also that title.
But we don't want to write out the bits of the image and actually save an extra image file.
And in fact, if you think about it, you probably have one place that informs you of both the image itself and that title.
So let's just save an identifier that we can use later to look up this information again.
And that as simple as just encoding something into that archiver that's passed into the method.
And you can see here my image ID is a string, so I'm just going to encode an object, give it a key so I can look it back up later.
Well, we also remember whether or not the user was showing the bars on the top and the bottom.
So how do we save that?
Just as simple.
Just going to encode a Boolean here, and that's all we have to do.
So you'll notice, I'm not showing a lot of code right now, and there's a couple reasons for that.
One is, what's important is to try to get the concepts across, so you can see what it is that we're actually trying to do.
If I show you the code, it's easy to kind of get lost in the forest just looking at it.
Now, we have released the code, so you'll be able to check out this whole example and see everything I'm talking about here in more detail, but you can do it on your own time.
So how did we know to call encodeRestorableState for that view controller object?
Well, here's all the view controllers in my application so far.
We've got the navigation controller, that collection view with all the little images, the thumbnails.
What we just looked at was the image view controller, and of course there's some views that go along with those.
What you do is you give them restoration identifiers.
That tells us that you want us to keep track of those objects when we save state and when we restore it.
And we will also call the encodeRestorableState method on all of them so that we save everything.
Okay. So how about when we restoreState?
So at this point, the application is starting back up.
Do you need to do anything different when an application starts up when you're restoring state versus the very first time the application launches?
Well, when an application launches, we tell the delegate that we're starting up, and here we just simply call or recall, the method application Will finishLaunching with options.
And you don't have to do anything different here in the state restoration case; just proceed as normal.
Set up your base interface, will either load your base interface from a storyboard or a nib, or you can execute whatever code you have, get your window visible, and you're good to go, and that's our starting point.
Then we're going to go and we're going to call the restorationMethods for the objects that are participating.
So in this case, let's look at the image controller.
So here, you can see we're starting off without our image.
How do we get it back?
We have a complimentary method, decodeRestorableStateWithCoder.
It's kind of the analog to the one I just showed you, where you saved your state, fairly logical.
So what we're going to do is we're going to pull in that image identifier, which informs us both of the image and the title.
You can see that I got that.
Well, how did we get it?
Similar to the way we encoded it, we just simply decode it.
And when you write this code and you look at it, the code itself is very simple.
What's interesting is when you think about how your application is structured and see what it is that you need to save and restore.
The code is very boilerplate.
We also kept track of whether or not we were showing those bars.
Again, we just simply decoded Boolean and set it up.
Now, I'm not showing you the code that actually goes and draws the image and sets the title.
In your application, you've already written the code that does that.
When you first presented that image view controller or used the segway transition, you obviously have some code that goes and loads in the image.
And with state restoration, you'll always be able to reuse that.
So here, all we're trying to do is get the information we need and then pass it around.
And I'll show you that in a little more detail later.
So do we have to do anything else?
I mean, we had a lot of different things getting restored, and I just showed you a little bit of code.
Remember, the navigation controller remembered to stack.
It remembered that we had this view controller presented on top I'm sorry pushed on top of that collection view.
We also had scroll position and our selected self.
And we also had that image sized up as it should have been.
Did you have to write any code to do any of that?
Well, it turns out you didn't have to do anything.
You get all of that for free.
And how does that happen?
Well, I mentioned before that when you set up all the restoration identifiers, it both informs us of what needs to be saved but also allows us to call methods to save and restore state.
And we have a whole bunch of base implementations that save all the stuff for you which is very convenient, saving you the tedium of having to write these very common things.
So we keep track of a lot of default behaviors, a lot of information automatically for you.
So you get a lot of leverage, you get a lot of bang for your buck for setting this up.
So let's talk about what's new in iOS 7.
We had some great successes this year.
We've seen people implementing this and some really nice apps incorporating state restoration.
And we felt that we had a nice starting point for all this, but that there were some additional things that we could do that would make it even easier to use, and also we wanted to continue to grow as we add new facilities to iOS and as apps continue to get more sophisticated.
So let's look at what we've got.
We found that with view controllers and views, you sometimes wanted to also have objects participate in state restoration like a data source or some other nonview controller object in the same way the view controllers and views participate.
So we added the ability for any object to be able to get added to the state restoration graph and save and restore its state.
Also, we've made it easier for you to figure out when you can apply state.
Something that's a little tricky sometimes is when your application restores all of its state but isn't sure of the order that different things will get resorted in.
So after you've pulled the view controller state back, is it safe to go and draw everything on the screen, or apply everything?
Well, it might depend on other objects that are also participating, and we don't want you to have to worry about that.
So I'll show how we've made that easier to handle.
We've done a lot of work with Snapshot handling.
Previously when an application restored state, we would show the default PNG, and when the application started up, we would just jump to wherever its state was.
Now to provide a more seamless experience, we'll use a Snapshot very aggressively, and I'll go through how you do that and how you still have some control over that.
There's also some small enhancements I'll discuss.
We just keep adding new things.
Last year in 2012 when I talked about this, I mentioned you can implement some state restoration for your app and then enhance it or extend it as you add new features.
And we're taking our own advice and doing the same thing, so we started with the most critical things, the basics, and then we started to add more things for this year.
So that's what's new.
Okay, first is generalized objects.
So the idea here is to be able to take objects that are in view controllers and views and also use them in the same way in state restoration as you've been able to with our existing API.
So here's two of our view controllers.
We have both the collection view and then we also have that image controller.
And a very common thing in an application is to have a data source object.
And with that data source, you'll be referring to it for multiple objects in the system.
So here I'm using the data source to inform you of what images I have, how many, what their titles are, and to get the image bits themselves kind of wraps over where all those images are hiding in the file system so I don't have to replicate that code everywhere.
So I'm going to want to be able to save and restore a reference to that directly.
I don't want to actually encode the object completely and make copies of it; I just want to refer to it.
And the data source doesn't actually need to save and restore any state of its own, but I will want to be able to refer to it when I'm saving state for other objects.
And something that's kind of similar is when you have a shared object amongst the many view controllers that might be dynamic.
So I'm going to extend the demo that I showed you before, and we're going add an Inspector so we can set up some effects, some image effects.
And here you can see that that Inspector and the image which is now kind of a different color, are sharing a filter object.
And this Filter object does have some state, so it will want to save and restore state, and I'll also want to be able to maintain those references.
So let's look at how our example application has changed.
So I've got a data source object here which I just described, and it's being referred to by both of the view controllers.
Now, I'm going to extend the application and add an Inspector, so I'm going to present something and it's going to use a filter object.
In fact, I might have more than one filter object, and they'll be referred to for multiple places.
So what I want to focus on here is the data source and these filters.
These are these objects I'm referring to as generalized objects, and we're going to see how they can play along with everything else.
The first thing you need to do if you want to use these objects in state restoration is register them.
We've added a new method, on UI application.
It's called RegisterObject for state restoration.
I'm glad we have code Complete, because that's long.
This is very similar to setting up a restoration identifier on a view controller.
You pass in the object and you can see that it actually implements a new protocol, and we'll get to that in a minute, then you also pass us a stringRestoration identifier.
Now, for view controllers and views we made this a property, but I didn't want to force developers to have to subclass a base class that we would contrive just so that they could register an object.
We need to hook in, we need to know when the object's registered.
I didn't want you to have to subclass something and make sure to call Super, so we felt this was a nice clear way to identify what's participating.
You just call this method with your object and the identifier you want, you're good to go.
So let's look at that protocol that I mentioned.
It's called UIStateRestoring.
It has the methods to save and restore state for that object.
These are actually optional.
There's some cases where you won't actually need to save and restore anything; you just want to add the object to the graph of objects we're keeping track of.
We also have a property that you can use to scope the object's identifier.
Sometimes you might want to use the same object or the same class of object in more than one place, and you'll have creation code or something that sets up the identifier, and it would be contrived to have to give it, the restoration identifier some weird name just because of where you put it.
As an example, let's say on an iPad, you have an image editing app where you can apply two different effects.
So on the left here, you can have one set of effects that you're showing on the image, and you might have a different set on the right side so the user can kind of compare and contrast approaches.
And you might be using the same effect objects, or the same filter objects, and you just want to give them the same name.
You can scope them by setting their parent.
Often you'll set that to a view controller.
You might set it to another restorable object.
This is what we implicitly do for the view controller hierarchy.
We actually keep track of the parent of an object based on whether it was presented, or if it's pushed on a navigation stack or in another collection controller like a tab view, and here we make it very explicit for you to do.
Also, in some cases, the objects may or may not exist depending on what the user has done.
So I showed you this beginning of the demo and I didn't create any filters, so there aren't any in my examples so far.
Now, if my application starts back up, I don't want to create every possible object I might have on the off chance I might be restoring them.
It'd be a lot nicer if somebody kept track of that for me and told the application, "hey, create this because it existed when you saved state".
So by specifying a restoration class, you're telling us who we can ask to recreate this object as needed.
And in the example I'm showing you, all these different pieces here, these filters are actually created on demand, and we'll see how we can do that.
This protocol that you use to create the object is very simple.
So we've specified a restoration Class.
When we're restoring state and we need the object, we call a class method, objectWithRestorationIdentifier path, and it gets passed in two things.
We give it an array of identifier components.
The last component in that array is the identifier, and often that's all you'll need to look at.
However, that array contains the identifiers for all of the restoration parents.
That way if you've scoped it and you want to be informed about which one of these objects we're asking for, you have that information.
We also pass in the coder that was used when you initially saved the object.
So why do we do that?
Why not just let you create an object.
Well, you're probably going to go through some initialization code, you may need some resources, and it might be convenient to look at a little bit of the information that was saved to help inform that.
Also, let's say that you have a dynamic database, and we're restoring an object that no longer corresponds to anything in the database.
You might have synchronized the database or changed things so that that object doesn't exist.
You can look in the coder to find out if indeed that object is still around or not, and if it isn't, you can just return nill from this method.
We'll be fine; we'll just stop paying attention to it, we won't try to restore its state.
You return one of these state restoring objects, and you'll all done.
So now let's look at when we launched the app before.
I mentioned when you call application willFinishLaunchingwithOptions, or rather, when we call it, you don't have to do anything different than you already did when the app started up.
But remember, in that method, you're setting up the basis for your application, and if we have a data source object that we want to refer to, you're probably going to have to do something to connect that up when you do your launch code.
And here I'm adding one line to register it for state restoration.
Just as I showed you before, we've given it an identifier, we've set up our object, and now we know about it, we can find it if you refer to it while you're restoring state, and when you go to save state, we'll keep track of it for you.
So let's go back to that segway code.
So before we even save state, remember that we want it to switch to this image controller.
We're going to also hand that image controller to the data source as well; that way, it knows who to ask to get the actual image file and to get the title.
So here we go.
Now, we've got all the information we need and we've got a nice shared object that we're using to keep track of everything.
So what do we do when we save state?
Well, again, we want to keep track of that image and the title, so we're going to write out an identifier for those, but we're going to write out an additional thing, and what's that?
Well, we want to keep track of the data source, so that when we restoreState, we can get a pointer back to that without having to do an EndRun with globals or doing something contrived to try to find it.
We can just refer to it.
How do we do it?
Same way we save anything, we'll just encode the object.
Now, we're not going to make a copy of this, because it's been registered for state restoration and we know about it and we know that it's a state restoring object, so we'll just save a reference.
That way you don't end up with a bunch of disjoined copies, strewn about your application that aren't the right thing.
How do we restore it?
Well, you can probably guess what's going to happen here.
We're going to pull that data source back in.
That's going to inform us of what image we want.
Remember, we saved and restored the image identifier.
And now we're pointing back at that data source object so we can use it and everything's wired up just as it was when the application was last running.
So it makes it really simple to maintain object graphs.
And again, we just use that coder, simple little line of code there, decode it, and you're good to go.
Okay, I'm going to show another demo that adds on the first so let's take a quick look.
Okay, so here we are, back where we were before.
Let's go back to this image, make it a little bigger.
So let's say that we want to put a cool sepia effect on it.
So here's that Inspector you might recognize it from one of my screenshots earlier and I'm going to dial in a whole bunch of sepia because I don't think you can ever have too much.
See what it looks like.
I'm a big fan of sepia, actually.
I think it can use even a little more.
Yeah, I like that, nice and gold.
And maybe I can soften it up with some blur that's my other filter.
Not so much.
I don't really like that, so I'm just going to turn it off, but I'm going to keep it in my back pocket.
Maybe I can tweak it a little more, make it kind of nice again.
All right so let's put the application in the background, want to go off and do something else, there's something exciting on the Internet, don't want to miss that.
And then I usually spend probably too long on the Internet, so the application is exited now, so we're going to start it back up.
And let's hope that it comes back.
Again, my goal here is unexcitement.
So there it is.
Now, it remembered that we were showing this filter inspector.
It also remembered that it was disabled and that I had that radius set kind of low, and it even remembered that we'd already applied a filter to that image.
Now, in an image editing app, you'd probably play around with filters and eventually you'd commit them and then it would save that information in the database, but here I'm kind of in an editing or playful mode where I haven't really committed anything; I haven't modified this image in the database, so I want state restoration to keep track of what I was doing.
So it got everything else, too, just like it did before.
If we go back there we can see it's got our collection view and all that good stuff okay, so we got everything back, no gasping, no flashing.
Great. All right, what happened?
What did we actually do?
Well, just like before, we brought back the image and the image title.
but now we added this new inspector.
And it was presented, it was a presented view controller, and that just kind of came back in the right place.
Everything was good.
And we also had two filters and these were those new types of objects that also get to play with state restoration, and they had a little bit of state, which they saved and restored.
And then finally, we actually were able to apply that to the image, and I did that kind of behind the scenes.
And this is interesting, because when you do state restoration you don't want to just have one of those Hollywood houses where it looks like a house but if you ever walked inside there's nothing behind it.
You actually want to restore the entire structure of the app so that it presents kind of a continuous and seamless experience when the user navigates back to where they were, that they don't get anything unexpected.
Now, when we initially presented that inspector again, I'm using storyboards and I did a segway what did I do?
I created that filter object and then when I present it, it had that filter to refer to.
That way I could share the filter between both this inspector and my image.
You may have multiple objects that are all sharing some state.
I don't want to get two separate filters eventually when I want to restore state, because as I change the settings here, I want it to be operating on the same filter that's being used by the image.
By the way, again, this is what's happening in the application before I've even saved state.
This is the, how did I get to where I am piece.
Now we want to save that off so we can restore ourselves.
So what do we do?
Again, we use encodeRestorableState with Coder.
We're going to want to save, whether or not that filter's enabled, and also what we've got it set to.
But here's the interesting thing.
Remember that I've got this filter object.
Why don't we use that to inform us when we restore our state rather than save it separately in the inspector, so all the inspector has to save here is a reference to this filter object.
And this filter object itself will implement, encode and decode, so it will save its state.
And we had one other object that also referred to the filter, and that was the image view controller.
It'll also save a reference to the filter, but they're both pointing at the same object.
So let's look at restoration.
Yes, the filter object is shared.
So let's go through it in a little bit more detail.
So when we wanted to save state, we needed to register the filter objects with state restoration.
I've drawn them in a big bright blue on the side so you can't miss them.
We need to save references to them.
We want to save the information that those filters have, so what we need to do is we need to register them.
Very simple, similar to what we did with the data source.
We're going to save a reference from our image view controller to those filters and also from the sepia inspector.
And then the filters themselves will save their own info.
That's just whether they're enabled, what the intensity is.
Now, we're going to do everything kind of in reverse when we restore, so it's very symmetrical.
But there's one other thing we need to do when we're restoring state.
Remember that these filters may not have existed; if I hadn't used them, they wouldn't be there, so I wouldn't need them.
So we're going to consult the restoration class to restore them only in the cases where the user was actually using them, when they existed at the time we saved state.
So that's what we'll do here.
So we'll recreate them, we'll then restore references, here's our filters.
So we've just created them again.
The state restoration runtime will ask the restoration class to create them by calling objectWithRestoration identifier path.
Now, you'll notice they don't have any state yet, so what's going to happen next?
Well, we're going to restore our references to them, but they still don't have any state.
We're just going to wire them up to our view controllers, so we can see there I haven't actually applied that filter yet.
So we'll let the filter object restore its own state recalling decode.
So now it's restored its state.
I don't want you to have to worry about what order this all happens in, so I'm going to talk about how we can leverage this later and make it real simple to apply it so that you then eventually get that nice sepia look on your picture, and we're back to where we were.
So let's talk about how we apply the state.
The first thing we do as we're restoring is get back our image.
But we can't go and apply that filter yet.
The filter might not even exist at this point.
We're just in the decode method for this view controller object.
And at some point we are going to go grab that filter.
It'll get created, it will restore it state.
Now we're good to go.
Now we can apply that filter.
But when? How do we know?
So we've added a new method.
This method's for view controllers as well as any of the state restoring objects, and it decouples decoding your state from trying to apply what might be more of a global state across the whole application.
It's just a simple little method, application finished restoring state.
It's kind of like awakeFromNib.
It's telling you, everything is restored at state; everything is created that we know about; it's safe to go in the water.
Go on, apply your filter.
So if we didn't have this, you'd probably have code like this.
Now, I mentioned I wasn't going to show you much code; this is actually the only code slide so mainly because I like this cool effect.
So the idea here is I don't want to update the image when I'm decoding my state because everything else might not exist yet, so I'm just going to decode my state and not do that thing.
And then when application FinishedResotringState is called, I'll call updateImage.
And if you're wondering, what's this updateImage, imagine I don't have any stateRestoration.
I have a segway to a view controller, I tell it what image I want it to show, there might be some filters that are set up.
So I'm going to write some code that goes and fetches that imageAppliestoFilter, sets the title, do all of that.
That's updateImage, and if you look at the sample code you'll see that I'm able to just reuse that method when the application restores its state here, so I don't have to go and write a whole big bifurcated strategy for restoring the image and setting it up in this case versus that case; got one cute little piece of code.
So there is one area where we got a number of questions and they were kind of the same question.
When do I have to create my objects, and when will you automatically find the ones I've already created?
You have a lot of view controllers.
You have some of these new state resorting objects.
And some of them exist when the application starts up; others come into being dynamically.
So let's look at that in a little more detail.
So if you think of the set of application objects you have, I like to refer to everything that exists when the application is already started as base objects.
These are loaded from a storyboard or from various nibs.
They're created by your code in application WillFinishLaunchingwithOptions.
Before we do state restoration, they're already in play, they exist.
So if they're going to be using state restoration and we need to find them, you don't have to do anything.
We'll just be able to find them and look them up because we've got some magical little tables where we keep track of everything.
What about all the dynamic objects?
These are presented controllers, view controllers you might have pushed on a navigation stack, some of these restorable objects like those filters how do you get them?
Well, if it's a view controller and it's in a storyboard, you actually can get it completely for free.
We'll just find it.
That's because we know what storyboard it came from, we know what its storyboard identifier was, so we can keep track of it.
So you'll notice when I presented some of those view controllers there, I didn't show any code to have to recreate them and represent them; we were able to go and hoist them out of storyboards ourselves.
However, if it's not in a storyboard, or if you want a little bit more control, you have to write a little bit of code, and that's where the restoration class comes in.
So you can use a restoration class for view controllers in the same way I showed you for these new generalized objects.
And also for view controllers, as a fallback, we'll ask the application delegate for them if all else fails.
Now, if you implement a restoration class, that trumps everything.
That gives you control.
Let's say going back to my earlier example maybe you have a dynamic database with images.
These can synchronize and images come, images go.
So if the image that was being shown when you saved state isn't in the database when you restore it, you may not want to bring back that view controller and show us something ugly like imageNotFound.
You want to just avoid it altogether.
And it's always fine to return nill when we ask for a view controller.
We'll do the right thing.
If it was presented, we just won't present it; if it was pushed on the navigation stack, we'll go one back and so on until we get to a view controller that still exists.
So we give you that control to make sure that we don't go and force you into some boundary situation where you don't have all the assets you need that make sense.
So here's the base objects in the example app I showed you: the data source, that navigation controller, and the collection view.
They were all in my main storyboard; they just got created by the time I got into application WillFinishLaunchingwithOptions.
And I put that Inspector in a storyboard, so then I was able to just completely forget about it.
I didn't have to recreate it; it just magically came back, it was presented.
Now, if I want a little more control, I can take that image controller, and even if it's in a storyboard I can still give it a restoration class, or if I was creating it out of whole cloth, myself encode, I'd give it a restoration class.
And the filters, as we saw, had a restoration class which recreated them on demand.
So when you think about your objects and which ones need a restoration class, which ones you'll have to recreate when we're restoring state, break them up in your mind, what's a base object.
Then you don't have to do anything, and of the dynamic objects, which ones do I actually need control of or what am I going to have to create?
Makes it a lot simpler.
I mentioned we did a lot with Snapshot handling.
So in iOS 6, we wouldn't use the Snapshot at all.
And that was kind of jarring, because the application would come up with the default PNG, restore its state and then kind of slap you when it went back to where it actually was.
So we're trying to be much more aggressive now.
And we'll show the Snapshot wherever we can.
So when we launch an application, if the Snapshot's available and if we can use it, we'll show that.
It looks much more seamless.
However, there might be cases where you want to use it, so we give you some control.
We've added a new API.
This is on UIApplication and you can tell it to ignore Snapshot on the next launch.
You'll do this while we're saving your state.
So if we're saving state in one of your view controllers, notices, this is kind of tricky.
I might not come back exactly to the same place, ignore the Snapshot.
Then we'll use the default PNG.
That means only one of two things will ever happen.
We'll show the same Snapshot that we're going to launch to, or we'll show the default PNG, which is predictable and at least it's somewhat familiar, second best choice.
So why would you want us to ignore the Snapshot, though?
Well, here's some examples.
Maybe your application is showing a network error.
Can't get on network; please try again later.
Click the application in the background, it exits, user goes to maybe a better coffee shop with free Wi-Fi, they start the app up again.
And it would be kind of silly for this network thing to be showing, seeing that there's an error freaking the poor user out, and then have it just dismiss itself or disappear when the app started.
You also might have things like a table view of data that changes frequently.
Maybe you have the top 10 awesome kitten videos of the day, something like that, and they tend to change pretty quickly, I can tell you from experience.
So the application when it starts up, you might not want to show a list of things that you're actually not eventually going to land on, and the user's stabbing away at this video and it doesn't show up, so it might be better to avoid that altogether.
There's also some implicit cases where we'll actually detect Snapshot wouldn't be the best choice, so there's a couple there.
One is, if the top most view controller doesn't have a restoration identifier, we're going to assume, okay, you're app's pretty awesome and it restores state, which is great.
Thank you, but we can tell that you're not going to restore to this one.
There might be some boundary area of the app that users rarely go to, setting something up that they would typically only do once.
That might not be a battle worth fighting for the first release, so you may not save the state of that particular view controller and you may be focusing on more important things, such as articles they're reading and things like that.
So in that case, if we detect there's no restoration identifier, we won't show the Snapshot; we don't want to give the user false hope when it's starting back up.
Also, there may be some things that we don't restore, and I'll show you an example of that.
So there's a whole bunch of areas where it's either inefficient to try to restore everything or it's just complicated enough that we haven't gotten to it yet.
Similar to the advice I gave last year where you take an approach where you start with the most important things and then add to it, we're in the same boat.
So we don't want to show a Snapshot if we know we're not going to come exactly back to the same place.
So I'm going to do another demo, but this one's kind of quick, so I'm actually going to use a movie.
So here's our application, we're looking at the image, and let's say that I go to the activity sheet.
Okay, so we actually don't share the activity view controller state, and there's a couple of reasons why we don't.
Mostly, it's because the application is handing us a whole bunch of data.
It could have handed us a video to mail to somebody to really annoy them, it could have handed us a lot of content, and it can often be a [inaudible] content or something that may not exist when the application starts back up.
So it would be both be very costly for us to save all this data and it might also bite us when we start the app back up but we can't find it.
And it could be confusing for the user if they start the application back up and they just see this activity view controller and they're not really sure what it was they were trying to share or what they were trying to do.
And you can see the image peaking through a little bit here, but in other cases you might not see that.
So what do we do if we put the application in the background and it exits and we start it back up?
So let's take a look.
So I did something kind of subtle here.
It might not have jumped out at you, so I'm going to replay that kind of in slow motion.
So let's see the application start back up, now watch the transition.
See how it kind of faded in?
It's very subtle, but let's look at it if it doesn't do it.
Starts up, boom.
Kind of jarring, kind of disjoint.
See it again.
So that's kind of unpleasant as a user, and let's look at what we do regular speed.
Nice. It just kind of fades right there.
So at least we're not slapping the user's attention around with this.
So that shows a few different things.
Already in the previous demos that I did, you saw us using the Snapshot, so that covers the first part.
Now when the application starts up in restoreState, it really does look seamless.
You might have even thought I'm cheating and I didn't really kill the application but I promise I did.
And in this example, we're showing how you both have control, how we'll sometimes implicitly notice that we shouldn't use the Snapshot, and how we'll do kind of a nice transition in these cases to sort of ease the user back in.
So we've added a few enhancements.
I'm just going to go over them kind of briefly now.
We've got some keys that are available in every coder.
So in the initial implementation when we came out with this last year, an application could look at the bundled version that was used when it saved state.
So it could tell, this old version of the app saveState I've changed drastically so as I restore the state I might have to do some transformations, or maybe I don't actually want to restore state from this very, very old version of the app, it's just too much.
And that information was available in every one of the coders.
Most of your app might be fine with this old state but there might be one view controller that's changed more radically, so it would look at this and say, "hey, wait a minute.
Let me see who saved this state, our old version of the app."
We've added a few new keys that accomplish very similar things.
The first one is to tell you the system version.
You may have noticed iOS 7 changed a little bit from iOS 6, so your app might need to adjust metrics or do something different when it's restoring state, so you can tell what version it ran on when it saved state.
Also, we put the time stamp from when we saved state.
This was a very common request, as it's so useful.
In some cases, after an app's been inactive for awhile, you might actually want to restore something a little bit different.
You might want to go back up to the beginning.
Because it might be confusing to the user if they dig way, way down in the app and then a month later, when they run it again, it goes to something that doesn't even make any sense anymore, something that's no longer relevant.
So you'll want to take maybe a little bit of notice of what time or the date that this was saved.
It made it easier to handle static table views where their content doesn't change.
Now, because a table view can have dynamic content, in the first release of this, when we saved state and we wanted to keep track of selected cells and the top cell that you were scrolled to, we would actually ask the data source for the table view, what is an identifier for this cell that makes sense to you?
The reason we did that was because the cell at index 3 today may not be the cell at index 3 tomorrow.
It may not even be the cell at index 3 in 5 minutes or an hour.
So we don't want to just select something based on its index path if that data could change.
So we would ask the data source, who knows all about the data, to give us some identifier, which we would save instead of just the index path.
And when we restored state, we would then do the converse and say, "here's an identifier; where's the index path now?"
And that works out great, especially if you have something like music or photos or a set of articles that could be moving around and getting sorted and changed with things getting deleted and added.
However, it's also pretty common to use table view for a static set of things, maybe some switches that you have.
Maybe that inspector I have there might end up with a fancy table view with a whole bunch of different items.
And it's kind of a lot of work to have to convert these index paths into some identifier that you contrive and convert it back when they're never going to move.
So now, if your data source doesn't implement the protocol we detect to ask this question, we'll just go and save the index path directly, and it can be really useful.
And speaking of selected and scrolled, we now added support to UICollectionView.
We'll remember all the selected cells in a collection view and also of the scroll position.
And you actually saw that in the demo, so we do that all for free.
And then finally, one thing that can be extremely frustrating to a user is when they're composing mail.
Let's say that you find a really awesome image or an interesting article and you want to share it, so you bring up the activity sheet as I showed before, and continue all the way to mail.
So now you're not in the activity view controller anymore.
That's gone, you're now actually in a mail composition controller.
And you type this elaborate message, put the app in the background for whatever reason, it exits, start it back up oh, no.
Gone. So we thought that was a really important thing to keep track of for users as mail can be fairly lengthy.
So if you have an activity view controller and you give it a restoration identifier, we'll keep track of mail drafts and we'll save them and we'll bring the user right back and restore them.
And over time we plan to add more to this as well so that we'll start saving more and more specific activities, but we thought mail was the best place to start.
So I just want to take a moment to talk about security and how that relates to state restoration.
We actually use data protection on the archive itself.
So the state restoration archive that's saved is not accessible when the device is locked.
It's an encrypted file, and if the device is locked, even if somebody stole your phone, managed to break into the file system and pulled that off, they wouldn't be able to look at it.
So why do we do that?
Why is it important to protect this file?
Well, there's a few reasons.
One is it's really easy to leak sensitive information by mistake.
You might keep track of the scroll position, which could inform somebody who really knows what the app's all about, how many entries you have and how you've been using it.
There might be identifiers that you use for some of your view controllers or some of these objects that actually give away a little bit of information about what a user is doing with the app, and for some business apps or sensitive personal apps, you might not want anybody to know about this.
You might be adding a new contact and it's not saved completely, but you're adding in someone's personal information; you want that to be kept private.
Also, your application already may be keeping things private.
You may already be using data protection for the application, and we don't want to be the weak link in that chain, so we felt that it was very important to make sure that the state restoration archive was protected and that you didn't have to worry about it.
So the action on your part, you don't have to do anything.
You can put whatever you want in there and not worry about anything leaking out because we're protecting it.
I'm going to come back to that in a minute and see how that relates to this topic.
So we added something really neat on iOS 7 that allows applications to run in the background, and they can go and fetch assets or do calculations or get ready for when the user's going to use the application, which is pretty cool.
So if we're doing some background operation and the application does state restoration, we want to make sure that everything comes back predictably.
So what do we do?
So this is my application, and let's say that your application just gets started up in the background and here's my little magic wand.
So your application just ran unbeknownst to the user, did its thing, and since it participates the state restoration and since the device unlocked, when it starts up, we go through the standard state restoration flow just like we normally would.
That's because the user might take their unlocked device and switch over to your application, and we'd want it to a restored state and be back where the user expects it to.
But what do we do if the device is locked?
Well, we can't access that state restoration archive, so in this case we take a simpler path.
We let the application get its work done, fetch its assets, do whatever it needs to do in the background, but we don't try to restore state, we won't be able to access the file and it will fail, and very importantly, when the application finishes running in the background, we won't clobber the state by saving whatever its current state is.
If the application is running while the device is unlocked, if it runs in the background, when it completes its background task and notifies us, we'll save state again.
The application may have changed its appearance, it may have changed some of the behavior when it did this in the background, but if the device is locked and it couldn't restore state in the first place, we're not going to have it save state; in fact, the app's just going to exit after it's all done with its work, so that it's just getting work done, loading those assets, but not perturbing the user, and when they start it back up it'll go back to where it was last time the device was unlocked.
One other thing about this, now that it's more likely or that there's more potential for our application to run in the background, if you're restoring state, keep in mind when you start up, the application's data may be different and that you might want to take that into account.
And state restoration is built around the idea that you should be able to save state and then restore it even if all your data has changed.
Many of the things I was describing before are about that very thing.
But just be sensitive and keep it in mind.
So now you've gone and implemented state restoration, but you want to be sure that your application's doing the right thing.
So do we have any tools that can help you?
Well, one of the problems with developing this that you might run into, the archive itself is fairly opaque.
It's not a text file.
You can't just go and look at.
So how do you tell what's in there?
How can you ensure that you've actually saved what you intended to save and make sure that we've kept track of everything that you expect?
Well, we have a new tool that we're going to make available from our developer support.
You can run this tool and it'll output everything that's in the archive.
I'm just going to show you a little bit of that.
Kind of looks like one of those 1960s movies about computers so very textual but very informative.
So you're going to see a whole bunch of stuff like this, and this is just kind of the top of it.
So this first tells you what objects have restoration classes, and that's real useful because a common problem is when you forget to set a restoration class or you set one by mistake on something that doesn't need it and you're wondering, either you're not getting any objects back or you're getting two for the price of one.
So right here you can look and see everything that we expect to use a restoration class.
Also, we just have a set of top level information.
So I mentioned we keep track of the bundle version.
We also have these new keys, when did you save your state.
What was the system version that was used when we saved the state?
And then for all of the objects that are participating, we save a bunch of information about those.
So here's our image view controller.
So you can see on the top there highlighted in yellow, we tell you the type of object it is, so you can kind of scan down very quickly looking for view controller, view controller and it also tells you the class of it, so you can look at it and go, "hm, that's not the class I expected.
How did that happen?"
And you can also look at what it saved.
And this stuff is very, very straightforward, right?
We referred to our data source.
Notice it says, "object identifier proxy."
That means this is a reference to an object that's also participating in state restoration and not an actual object.
Here, I actually put my filters into a dictionary, so this is just a textual representation of a dictionary.
So the dictionary itself was encoded and the keys were encoded, but you'll notice again, we're using proxies for the actual objects, the filter objects in the dictionary.
And here's the identifier for the image as well.
So sometimes when you're trying to diagnose issues, you can learn quite a lot simply by taking a look at your archive.
And I think it's very useful as you're building new code and you're testing things, to just take the time to go through here and make sure everything you expect is in it.
Now, I mentioned that we can pull things out of the storyboard automatically.
So here I'm just showing that we keep track of the name of the storyboard and also what the storyboard identifier was.
And that might be useful to you as well, even if you're not depending on this behavior, just so that it helps you to triangulate on what this object actually is.
You're not going to have a picture of the view controller on the right as I'm showing here; you're just going to be looking at text and you might think, what is this thing I'm looking at?
Oh, came out of the storyboard.
There we go.
Okay. How about these generalized objects?
Again, we do the same thing.
We're showing that it's just a general object, it says restorable object that's my terminology.
We show the class of it, and it saved a couple things, so we just keep track of all of that.
So pretty dry, but I think it's very interesting when you see all of this.
Okay, I'm kind of running out of time, but I have a couple more things.
We've added a profile you can install and we'll log a little bit of extra information.
You can also set a default for the simulator.
So you get kind of a play by play in Xcode's console as your app is saving state and restoring it, and it could be pretty useful to look at that, too.
And we have a profile that you can install that puts you in what I call developer mode.
That's what I was using in my demo so that I could kill the application without losing state restoration.
And it's really useful when you're chasing a bug or you just want to check things and you want to be able to go on the switcher and kill it but not actually lose the archive.
So we did a recap.
I'm hoping that if you haven't used state restoration, this shows you just how easy it can be to incorporate it in your app, and you'll go back and you'll want to take a look at this and see what you can do.
And for those of you who have already been using it and new people as well, I hope that the new features show you that you can also extend things and it makes it even easier to use.
Talked a little bit about security and background operation.
We covered the tools that we have, and that's it.
Jake Behrens is our Frameworks Evangelist.
He'd love to hear from you.
We've got some great documentation online.
Of course, the forms are always available, so talk to him if you have a chance, and that's it.
Thank you very much.
[ Applause ]