Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: tech-talks-2009-1
$eventId
ID of event: tech-talks
$eventContentId
ID of session without event part: 2009-1
$eventShortId
Shortened ID of event: tech-talks
$year
Year of session: 2009
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2009] [Tech Talk World Tour] Ef...

iPhone Tech Talk World Tour #1

Effective iPhone App Development, Part 1

2009 • 51:05

Whether your iPhone app is currently in development or already on the App Store, strong code architecture is essential. Learn the most effective techniques for data modeling, communication between view controllers, and when to use delegates and notifications. Find out how to make important decisions about memory usage, performance, and a responsive UI. Developers of all skill levels can benefit from this thorough examination of iPhone SDK best practices.

Speaker: Lawrence Coopet

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Hi, I'm Larry Coope at Apple Engineer. In this video, you'll learn about structuring your application and data to support a dynamic, flexible architecture. We'll also talk about reusability and communication throughout your application flow. You'll learn how to be ready to adopt new features and technologies as they become available in iPhone OS. Welcome to Effective iPhone Application Architecture, or as I like to say, doing things right every day.

We're all here today because you want, and Apple wants, the same thing. The best possible application for your users in the App Store. And we feel over the years we've learned a thing or two about building applications for the Mac and for the iPhone. Starting in 2001 with the initial release of Mac OS X, all the way up to iPhone OS 3.0. We've learned the paradigms, the models, the design patterns that work every day to build an effective architecture and that allows you to build a flexible, dynamic application that you can move forward into the future. But we understand the realities as well.

You start with a simple idea, and you start building your application, and pretty soon you've got something that you like. You start showing it to friends, and you take it into work, and pretty soon, before you know it, you start adding features. The designers come and talk to you, start adding new screens, new data. And what happens is things slowly build and can get out of hand quickly.

You start with a prototype, and pretty soon you've got a system that is working, but has not been built from the ground up to do the right things every day. And that's all about what we're talking about here today, is extending your application architecture to make sure that you can benefit from all the tools and frameworks that Apple provides.

So I want to talk about four things in this session. And the first one, Data Persistence Design Decisions Memory Management Application Lifecycle People ask me why we would talk about data persistence first before we talk about design decisions. And that's because if you don't understand your own data and your own model underlying that data, it's tough to make design decisions about your application and the workflow. So let's talk about data persistence. First of all, we've got to talk about the kinds of data that you're going to use in your iPhone application.

First of all, we've got user data, your media and your documents, your audio files, things that the user has control over. You've got user preferences, state, navigation state, application state, when they close. You have sensitive data, usernames, passwords. And of course, you have cached data. And by cached data, I mean data that can be rebuilt dynamically, but you want available for quick access to your data set.

So when you talk about user data, we've got multiple options. I'd like to point out some of the data sets we see and things to do and not to do. The first thing is not to use unstructured text files. This is not a proper data set and a proper model. Unstructured data is unstructured data and it's difficult to maintain and manage and extend. But we do have property lists. You've all been familiar with this. NSDictionary.

Straight XML. Fantastic use on the phone. We've got archiving. If you're not familiar with NSCoding, it's a very powerful technology for freeze-drawing objects on the phone and restoring them later on the fly. We've got SQLite. And now in iPhone OS 3.0, we've got Core Data. So let's talk about choosing your storage, your data storage, from the multiple options that you have available.

The first question you have to ask yourself is, is this a user-controlled data set? And by user-controlled data set, I mean that it's a data set that can grow from potentially zero to infinity. That the user maintains and is not under direct control of your application. If the answer to that is yes, then you should be looking at Core Data. Core Data is a powerful technology that's been available on the desktop and is now available in iPhone OS 3.0.

If the answer to that is no, that this is not a user-controlled data set, the next question is, is it a small data set? And if the answer to that is yes, then you can look at things like XML and NSDictionary to store your data. However, if the answer is no, that it's a large data set, even though it's under your programmatic control, you still need to be looking at core data.

All right, now that we've talked about choosing your storage, I want to talk about implementing your storage. And first, we need to talk about proper data objects. As you build your data store, it's easy to start saying, well, I've got all these separate objects I need to store, and I want to put them all aggregated in one place.

So we can see NSDictionary as a nice repository of storage. And that can be very interesting for simple data types. But what happens is as we build these, Each key value pair requires a key string. And what can happen is you start to spread these strings all throughout your code.

And there's no contract between the object and the dictionary and the clients of that dictionary. In the sense of, Value for key just returns an ID. It's not strongly typed. So pretty soon, you see these APIs spread throughout your code. You're accessing the dictionary, but you don't even know what type of value you're going to get back.

So you define constants and strings to make sure that you can separate out the code a little bit, but quickly, this spins out of control because, like I said, there's no contract between the clients of that dictionary and the dictionary itself. These are just opaque types, and so you don't have any idea what's happening underneath the hood.

So we recommend that you don't store these type of objects in dictionaries. You want real, proper data objects. And that means in an object-oriented world, we have an object that has the properties and the attributes on that property to make that contract complete. So when you use those APIs, there is this implicit contract between the object and the client.

So for instance, in this case, if I want to change the name of my session from a simple string to an array of strings, the compiler is going to help me when I choose that storage and I change that property type from a string to an NSArray. So let the tools help you do that every day.

So this is how you want to structure your data objects as true objects in the system, high-level objects that have this implicit contract between the clients and themselves. Next, let's talk about user preferences. And these are handled by a single class inside the iPhone called NSUserDefaults. And these are really just for lightweight settings, things like navigation state. Certainly in our own apps, in the iPhone app, the list of cities is stored in the NSUserDefaults.

And, in fact, those navigation states are a simple index stored in the phone. So when you quit the application and launch back in, that index is retrieved, and it's just an index into that array inside NSUserDefaults. Now, it should be important to point out here that this NSUserDefaults is not for heavyweight data.

No large images, no archived objects. You do not want to use NSCoding here and store these inside NSUserDefaults. And it's certainly not for sensitive data like passwords. For that case, we have the keychain. This is where you want to store all your sensitive data pertinent to your application.

And what people forget is not only can you store your sensitive data on a per-application basis, we also have the ability to store the sensitive data for a company-wide set of applications. So what you can do is if you have, say, a multiple set of social networking applications, you can store your keychain data such that when the user logs in for the first time with their application, one of your applications, then the next time they launch the other application, they're not required to log in again because you've stored that in the company-wide keychain. And this gives the user a very nice user experience because they don't have to log in every single time to all your different applications.

Next, we'll go back and talk about cached data. And why do we talk about here faster iTunes backups? Because it's important where you store that cached data to give the user the best possible experience, even when they're not using your application. So this is all about storing your data in the proper locations.

And these locations are in NSPathUtilities.h, and it's a single line of code to use. What's important to point out here is you do not want to use hard-coded paths. You should never have a hard-coded path anywhere in your application. It's trivial to get the path to any arbitrary folder on the system. And let's look at some of those folders. We have NSTemporaryDirectory.

The NS Caches Directory and the NS Documents Directory. And what's important to point out here, as you see on the slide, that during backup, the NS Temporary Directory may be cleared by the system, but it is not backed up. The NS Caches Directory is left alone on the device, but it is also not backed up. Remember, cache data is data that you can restore at any time or regenerate. Certainly, your NS Document Directory and almost everything else inside the phone is backed up.

So the point here is that even when the user is not using your application, not even thinking about using your application, if you store your data in the proper locations, you give the user the best possible experience because we don't want to have them backing up unnecessary data and slowing down that backup process.

All right. Design decisions. We've talked about data. Now we need to talk about how to decompose your app workflow to make changes easier so you can move your application forward from a feature basis. What are we going to cover? Well, first we're going to talk about targeting the iPhone OS, application flow, and the information flow within your application.

What are we going to cover? So targeting iPhone OS. This is about choosing your application's reach. Obviously, iPhone comes out, we have a base SDK and a large feature set, and all the users are available on that base SDK, and they're using that, and your application is going to cover that.

But pretty soon, Apple puts out a new release of the OS. It's got some new tools. And then it's not as quickly adopted initially, so you feel safe that I can stay on that SDK. But pretty soon, iPhone OS 3 comes out. And we've got massive adoption of that. And you need to broaden your reach and get those customers and take advantage of those features. But how do I do that without leaving my customers behind? It's very, very simple. It's all about the deployment target.

And that will give you the broadest coverage for all your users and all the SDKs and OSs. But how do you stay current and do that? Well, it's all about maximizing your exposure, and it's very, very simple. You always link against the latest SDK. There's really no reason for you to stay on an older SDK. And all you do is once you've linked against that latest SDK is you simply set your iPhone OS deployment target.

And this is how you adopt new features dynamically. And what will this do for me? Well, what it does is it allows me to weak link against the newest frameworks, and then at runtime, I can test for the presence of those new API sets, and I don't have to base any of my behavior off the OS version. This is very, very important. You should never base any specific functionality off the version of the OS. You should do dynamic lookup. And so to do that, you need to know how to understand how to read the availability macros. So let's look at those real quick.

In this particular case, what this macro says is that if the current OS version of the Mac is greater than or equal to 10.4, then this code is going to be compiled. Or in our case, what's more important, if it's greater than or equal to iPhone OS 3.0. So that means if it's iPhone OS 3.0 or better, then this framework code is going to be included in my compilation.

But what's more important, as you can see, this is taken from the UI image picker controller, is the other availability macros. In this case, we see OS X available starting, and this tells me that it's never been available on the Mac, and it is available starting in iPhone OS 3.1.

In the next case, the secondary macro says OS X available but deprecated. So this is a pair of values. In this case, we're looking at the allows image editing, which is also in the UI image picker controller. And this says that it's never been available on the Mac. It's never been deprecated on the Mac.

It started to be available in iPhone OS 2.0 and now has been deprecated in iPhone OS 3.1. So it's an easy pairing to see how you read that to tell me what's available. So how do we take advantage of these features at runtime without leaving our older customers behind? It's very simple. Runtime checking. And it couldn't be easier.

In this case, this sample code, not only I can check not only for the class, but specific implementations inside the class. So in this example, I'm checking to see if MF Mail Compose View Controller is available. And NSClass from String does that for me. And the really interesting thing about weak linking and dynamic loading is if that class is not available, NSClass from String will simply return nil. So it's very powerful.

I can check at runtime on the fly to see if this class is available. And if it is not nil, then the class is available. I can use our old friend response to selector to see if specific methods are available. And in this case, I'm checking to see if I can send mail. And then, of course, in this example, if that's not available, I'll fall back to just calling this a traditional mail client with a URL.

Also, it's important to note that for C functions, because the dynamic loader at runtime, if you weak link, resolves symbols that are not available on this version of the OS, it resolves them to null. So the important thing is this is called a T vector test. And so in this case, the UI save video at path to save photos album is a C function. And I can simply test for the presence of that function by testing against null.

Because like I said, weak linking tells the system if that method or if that function is not available, just mark its address as null. So this is really, really powerful technology, one of the most interesting things that's available at the low level in the system. So weak linking and runtime checking are very important so that you get the broadest coverage for your application.

Now, let's talk about application flow and how to design your application with some of the constructs that we've talked about previously. The important thing is organizing your content. On these smaller devices, it's really important to stay focused, not only on UI, but on the data that you're presenting to the user.

So, as you see in our own apps, it's important to focus on one thing at a time and drill down into greater detail. So I want to talk about one of our examples called recipes. And what's interesting about the recipes application, even though it's relatively straightforward and simple, it's a good example of how to structure any application and get the best possible use of the architectures we provide.

In this case, as you saw, the recipes application has three screens. A list of recipes, so we have a list controller. We have a detail screen, which shows an individual recipe, so we have a detail controller. And we show a photo of the finished product, so we have a photo controller.

And this is important to talk about. UI View Controller is one of the basic building blocks for almost every iPhone application. And the idea here is one screen, one view controller. As I said, this is a small device. You need to stay focused. The best applications stay focused on their data for the user.

And what you do is you simply subclass UI view controller to add your own application logic. And this slide is important to look at because the view controller encapsulates the three most important parts of your application. The view system, what the user sees, the data, your model, and of course the logic that binds all those together. And I said, this is the basic building block for every application, and you'll see this time and time again.

So what is the role of the view controller? Well, at Apple, we talk a lot about MVC, Model View Controller. And this is a great design pattern that you should use in every application that you're building. The point of the view controller is it is that controller that we talk about in the MVC model. But in this case, the view controller is very interesting because it also is responsible for loading the view system, typically from your nib or programmatically.

But the important part is here it acts as the arbiter between your model and the view system. And in this diagram, I want to point out something very important, which is what you don't see. You should never have that direct connection between the model and the view system.

If you do, you've got a problematic architecture. It's not going to be flexible, it's not going to be dynamic, and it's not going to be changeable. So the idea is that this view controller, like I said, acts as a model. It acts as the arbitrator of these objects and handles that flow in between. So make sure you don't tightly couple your model to your view system ever. And in this example, we're going to use UI Navigation Controller, which just implements a stack of view controllers and lets you build up a nice drill down UI, as we say, into your application.

So, we've talked about the flow of the application. How do we make the information work within that flow? Well, we need to talk about the model. This is your data. And in this case, we're looking at a recipe application. So, we've got a database with a set of recipes.

And in this case, we're going to be using core data. As I said, it's a great way to store your data. And then, inside each recipe, we've got other data objects, ingredients, instructions, and a small image. And, as well, we have a large image attached to each recipe that shows us a finished product.

So one thing that we see people doing is they have many screens, one model, and so they just think, well, why not? Why don't I just do this? Why don't I just make my model, since I only have one model object, accessible to every screen, every view in my system? Lawrence Coopet Well, that gets very problematic as we talk about a dynamic application architecture and as you want to add features down the road. So what we like to see is a more unique coupling between the screens and the data they represent. Again, we're focusing on UI and focusing on data.

So let's talk about the flow of that data in our application. Since this is a recipes application, we're going to have our application delegate, and it's going to be responsible for loading that recipe database. It's also, however, going to be responsible for instantiating that first view controller, that first list-based view controller, and handing it that database, that list of objects that it needs to display. Then that view controller is going to be responsible for the detail view. And the important thing here is that that detail view is going to be given the recipe that it's going to show.

It is not going to take the recipe. It's going to be passed that data. And this is a common theme that's very important as part of your data flow through your application. You need to make sure that you're not sharing data. You're passing that data or you're transferring ownership to that view controller.

So it only needs to know about a recipe. It doesn't have to know about the list of recipes or anything. It just knows about the one model object it's concerned with. And of course, in the same case, that detail view is then responsible for instantiating and putting that photo view on screen as well and passing the photo, again, transferring ownership of that data object to that view controller so that it can display that.

So let's go back and talk about that application delegate. It's going to load our model, and it's going to hand it off to the first view controller. So here you see in our application to finish launching method, we're going to instantiate our list table view controller, and we're going to pass it the core data manage object context.

Manage object contexts are, think of them as a scratch pad for core data. And each controller may or may not have to know about this manage object context depending on its context and what it's going to do with that. But this is what core data passes around so you can access the data inside your core data model. And then we're going to push that navigation controller on, and we're going to see it on screen.

So what happens next? Well, like all things iPhone, it all starts with a user action. So I'm going to make a selection, and when that happens, I'm going to get my table view did select row at index path method call. And the important thing here is we want to determine the minimal amount of required data to pass to that next view controller. Again, transferring ownership of that data set.

So we're going to ask the fetch results controller, which again is a core data object, that I want it to give me that object at index path. And it's going to return me my recipe object. And then I'm going to instantiate my detail view controller, and I'm going to give it the recipe that it needs to display. And then I'm going to push it on to the navigation stack, and then I'm going to forget it.

Very nice, very simple, very straightforward, right? Well, we forget until something happens. Like, I would like to edit my recipe. What if I want to edit the contents or the instructions or just simply the name of the recipe? Well, right now, we know that the ListViewController knows about the DetailViewController, that it's presented to the user. Well, if I want to change that data in that recipe, the parent will need to know.

And what's important here is that the list view might have to update if I change the name or some other data inside my detail view. That list view is going to have to reflect that when I display that. So it needs to know about changes in individual recipes.

And you say, well, the parent, the ListView, the parent already knows about the child because it's put that on screen. So maybe I'll just do this and have a back pointer to the parent. Well, in an effective application architecture, this is typically a bad idea. What we want to use is delegation, which you're probably already familiar with if you've done application development for the iPhone. Delegation is, again, a very powerful application architectural strategy and design pattern that you should be using every day.

And the interesting thing about delegation is you get to declare the protocol. You get to declare the API set. And that's really, really powerful to me because then I have control what these delegates, what kind of data they send off, and what that means to the someone who's listening to that delegate.

Lawrence Coopet So when I declare a protocol, again, it's very straightforward, simple syntax. And in this case, I'm going to declare a protocol that says that the recipe did change. Lawrence Coopet So for the recipe detail view controller, recipe did change colon. This is my method. It's a single method that I'm going to declare for my delegates to support. Lawrence Coopet I simply create a delegate property.

What's important to remember here is the delegate property is on the object that needs to be declared. Lawrence Coopet So I'm going to declare a protocol that says that the recipe did change. And that's really, really powerful to me because then I have control what these delegates, what kind of data they send off, and what that means to me.

Lawrence Coopet So think of it as I'm going from the object that knows that something's changed to someone that might want to know that something's changed. My delegate is the object that is listening to these changes, if you want to think of it that way. Lawrence Coopet So I'm going to declare a protocol that says that the recipe did change.

What's important to remember here is the delegate property is on the object that needs to be declared. So in my Detail View Controller, I'm going to create a recipe detail delegate. And, like most delegates in the system, they are simply assigned. You typically do not retain a delegate.

And that's why it's important about being a good delegate. First of all, you implement the protocol. As part of my interface for my recipe list table view controller, you'll notice here, That I declare that I support the Recipe Detail View Controller Delegate. I support that protocol. And indeed, I will implement that method. And in this case, since I'm the list view, all I'm going to tell myself is to reload the data, because something in that recipe has changed. So I want to reload my list to reflect any of those changes.

Don't forget to set the delegate. And this, again, couldn't be easier. Going back to our code snippet from before, I'm creating my detail view controller. I give it the recipe. Then I set myself, the list view controller, as the detail delegate. But it's important to be a responsible delegate.

And what's important here is to be aware that the delegating object may outlive you. So what do we mean? Well, in this case, say the list view controller was to go away, and we're going to take that off screen. Well, it's important since the list view controller put the detail view controller on screen and gave it itself as the delegate, we need to make sure that if we go away, if we are dialect, that we tell that detail view controller that we have gone away.

And we do this simply by sending its recipe detail delegate to nil. Remember, like I said, delegates are typically not retained, so you must notify that object and set its delegate to nil. This is a standard design pattern throughout the system. So it's important to be a good, responsible delegate.

But let's talk about alternatives to delegation. And the number one is notifications. Delegation being a one-to-one mapping is very powerful, but what if I have multiple clients that need to know about the recipe changes? Well, then you would use notifications. NS notifications vary again, very simple. You simply add yourself as an observer to those notifications and listen for them.

But like delegation, it's important, and we see this time and time again, to make sure that you tell the notification center if you're going away. So in this case, if we are listening to a certain notification, we need to tell the notification center that we are going away.

Sending messages to nil is not a problem in Cocoa, but sending messages to a garbage pointer is a problem, and you're going to get a crash. So again, be a responsible notification handler. There's also key value observing. We don't have time to go into it in this session, but key value observing lets you watch and listen in to particular methods and objects inside your system. It's very powerful, and core data uses that quite heavily.

And how does that pertain to our example today? Recipes and core data. Well, in this case, all those systems, notifications, delegation, and KVO, are in play. We have our NSManaged object context, which as part of core data, registers for every property in your core data schema. This is very, very powerful.

Then we have NSFetch Results Controller, and that talks to the NSManage object context to get and retrieve your recipe data. So what happens when that recipe data changes? Well, I'm going to be notified via KVO to my NSManageObject context that the recipe has changed. Like I said, Core Data automatically registers for every property in your Core Data schema. So if you change a recipe or any attributes on that recipe, the NSManageObject context will be notified.

Then, notification is sent out from the managed object context because there might be multiple fetch results controllers listening for those changes. And then your list view, in this case, is a delegate of the NSFetchResults controller, and that's going to let your list know that it needs to reload the data.

So all these notification systems, KVO, notification, delegation, are in play. And this is, again, a very typical design pattern that we use in our own applications and you should take advantage of to structure your application architecture. So we've done all this separation of model, data, UI views. Why are we doing this? Well, the most important reason is reuse.

And you see this every day inside our own frameworks and applications. Think of the people picker, UI image picker. All I have to do is instantiate one of those objects, And I have them, I simply declare myself as a delegate and present them on screen. And I immediately have that built-in functionality with very little code, and I don't have to write these objects myself. So I can absolutely reuse these every day.

And in our case, the recipe detail view controller, if I was going to stick it in a cookbook instead of a recipes, maybe I had a cookbook application. I could reuse that same recipe detail view in my cookbook application. And simply by setting the delegate, I would again notify whoever's listening, whoever that delegate object is, that the recipe has changed and update my any data or UI accordingly. And of course, this allows me to reorganize my views. Since I don't have a tight coupling to a parent, that is, that I have to know exactly what its class and structure is, I can easily reorganize my views in my application to take advantage of that flexibility.

So we've talked about application workflow and UI flow. So let's talk about... Memory Management No one wants to talk about memory management. It's not that sexy, but we have to do it every day. So first is understanding, do we even have a memory problem? And it's surprising how many application developers don't even know if they do have memory problems. So we first need to identify the problem and look at the tools we have to analyze those problems, and look at models, views, and controllers, and how they can help us debug our application if we have memory problems.

So the first step is understanding that you do have a problem. So how do we know that we've got memory issues? Well, obviously, you've got intermittent crashes. You see crash logs without a backtrace. Or surprisingly enough, lots of developers never even check the console, and you'll see low memory warnings in the console from your application in low memory situations. So it's important to look at these.

So given that we think we have a memory problem, what tools are available for me to help me debug my memory issues? Well, first and most important, we have instruments. And we have two tools inside instruments, Leaks and Object Alloc. And we're not going to talk at length about this. That is talked about in one of the other optimizing your application performance in one of the other sessions.

But what I want to talk about is that Leaks will help me find focused memory leaks inside my application. It's a very powerful tool for doing that. And Object Alloc, which I really like because it gives me kind of a memory footprint of my application. It gives you a life cycle of the memory usage. As you're building your application, you typically know where you're using memory very heavily or not. And Object Alloc will show me that footprint.

And when I see things going away inside my code, I should see that Object Alloc footprint decreasing. So I recommend that users or developers use these tools at least once a week to maintain that "We want to make sure that the user is able to access the interface to their application and make sure that they're not letting the memory system get out of hand." Secondly, we've got the simulator. And it's important to remember that the simulator can simulate a memory warning.

And what's powerful about this is that it's very tough to simulate a memory warning on the device itself. You don't want to write debug code that's going to go off and allocate memory just to force the system into a low memory situation. Use the simulator to simulate those low memory conditions and help you debug your memory problems. And it's important also to point out that you can use instruments with the simulator. It's not just bound to the device. So you can use instruments, leaks, and object alloc on the simulator as well as the device.

Also, we now in Snow Leopard, in Xcode, we have Xcode Static Analysis. I really, really want to push you guys to be using these tools. It's only available in Snow Leopard, but it really helps you resolve these retain-release problems that we see in lots of applications. And what's important to point out here is Xcode Static Analysis. You do not have to run your code. It simply analyzes your code. It doesn't build it.

It doesn't have to do anything. It statically analyzes. It's based on the Clang tool. It's very powerful. But what's important to point out here as well is that you should trust the tool, but you can get false positives. You know your code better. So you need to verify the results of the static analysis. output. Very, very powerful tool.

Next, we talked about models of view controllers. Well, how can they help my memory problems? First off, view controllers are very important basic building block, as we said, of the application. Every application is using these. And it's important to remember that you don't have to cache them. They're typically very lightweight, loaded from a nib, and so there's no need to cache a view controller, especially when it's not on screen.

And the important thing is, remember that view controllers automatically know how to respond to memory warnings. When you instantiate a view controller from the template inside Xcode, you will see this did receive memory warning. This is where you put your code. Now, what's important to remember is that now in iPhone OS 3.0, the default behavior for did receive memory warning is to unload the view attached to that view controller. And then your view did unload method will be called automatically by the system. This is very important.

First, it's important to call superviewDidUnload, and then you need to release any objects that you have persistent properties attached to. So in this case, I have a view that I'm holding on to. Well, remember that by the time viewDidUnload is called, the context of any subviews is gone, right? Your view has been unloaded.

So you've just got these little objects floating out in space. You need to make sure that you release them so that the system can then take advantage of that freed memory. And what's interesting, again, is that when memories are covered, your viewDidLoad will be called again, just like the first time you call your view controller, instantiate your view controller, and your viewDidLoad code will be called again, and you'll have a chance to set all these things up, and your outlets from the nib will be restored. So you don't have to do anything. But you are responsible at unload time to make sure you release any of those outlets.

Now, how can our model object help us with memory situations? Well, as we pointed out earlier, it's important to spread that model thin, right? You want to transfer ownership of the minimal required data set to each of your view systems. And core data can really, really help you with this. Because, first of all, it knows how to load a partial object graph. Very important in a tight memory situation.

Also, it has automatic faulting. So it can fault objects in or out of memory in low memory situations. And, of course, it already knows how to respond to memory warnings. So it does the right thing on its cache and all its data set. So, again, you can really take advantage of core data and simplify your application by using that.

So the takeaway here is that memory is important, and you should be using the tools frequently to make sure that what you are expecting out of your application is truly happening when you're running your application, that you're seeing the memory footprint that you expect. And we have the tools that help you do this, but it's also important to make sure that your architecture takes advantage of that and helps you maintain the proper memory footprint for your application. And especially as you go forward and add features, it's definitely important to take advantage of those situations, those frameworks. Okay, lastly, we want to talk about application lifecycle.

And what do we mean by application lifecycle? Well, we're going to talk about four important points here. Compatibility, implementation versus calling, handling interruptions, and just a brief bit about concurrency. Padability. One big issue we see with developers is that they have namespace collisions. Remember in Objective-C, there is no name mangling like there is in C++. So it can be easy to bump into duplicate names and have inappropriate behaviors based on that. So in this case, we have our WWDC session object, and we have another framework that's built into the system that has a session object.

We're going to call it a WWDC session object. And in our own application frameworks, you'll say that GameKit has a GK session, and so there's less chance of a name collision. You should definitely take advantage of that simple paradigm as you build your app. paradigm as you build your architecture. To avoid those namespace collisions. Also, for method names, make sure you avoid underscores.

Apple reserves the right to have all private methods use underscores. So here's what can happen. Say I have this can have cheeseburger method in my WWDC table view cell, this class I'm implementing. Well, what happens if there's a private method in UI table view cell called can have cheeseburger? Well, you can see that there's an immediate namespace collision. So what happens is if we're running That code at runtime in the internal UI kit is talking to your TableView cell, and it says, "Okay, TableView cell, can I have a cheeseburger?" It's going to call our WWDC table view cells method.

And of course, this is not what we want, and this is not what the internal frameworks expect. So avoid underscores on your base methods, because there might be an identical private method that Apple is using internally. And to help you do that, remember that Xcode has a wonderful refactoring tool that lets you change your IVARs, your method names, your entire class names, and will do it automatically. No more searching through your code and textually searching and replacing and worrying that you're going to break something. The refactoring tool takes all that into consideration and will refactor your code and your names automatically for you.

Also, as part of your application lifecycle, it's important to understand proper code paths. I see this time and time again, that people don't always understand that there's a fundamental difference between implementation versus calling. And these are totally different usages. Remember, in specific cases, you implement DrawRect. You do not call DrawRect. You call SetNeedsDisplay. You implement LayoutSubviews.

You call SetNeedsLayout. And remember that things like LoadView are there not for you to call, but for the system to call when you access the view property. You implement LoadView. You simply access the view property. And by doing that, your LoadView method is going to be able to call the view property. And by doing that, your LoadView method will be called. This is very, very important, especially things like DrawRect.

When you do call DrawRect directly, if you try and do that, not only will it probably not give you the desired results, it's actually a performance hit. I hear people saying, well, I want the best possible performance, so I'm just going to call DrawRect directly. We have a fully composited system, so you must call SetNeedsDisplay to invalidate your UI and not call DrawRect directly.

If you call SetNeedsDisplay a million times, that's going to only end up calling DrawRect once. But if you call DrawRect directly a million times, then it's going to call DrawRect directly, and you're going to have a performance hit. Again, we have a modern UI system. You'll always prefer invalidation. And the same thing for SetNeedsLayout.

If that just sets a bit that your subviews need to be laid out, and at some point the system will call you to do the right thing with your layout subviews. And this is how the... This is how the phone works, and it's a true object-oriented system. So you need to be aware about what you're responsible for implementing for what you're responsible for calling.

Next in the application lifecycle, we want to talk about interruptions. Handling interruptions is very important on the phone because you don't know how you're going to be interrupted and where they're going to come from. Obviously, we have text messages, phone calls, iCal alerts, clock alarms, and now push notifications. So it's important that you know how to handle these, and it's very, very simple. There's basically three delegate messages that you need to be responsible for.

When an interruption occurs, and in this case, I'm getting a phone call, you need to implement Application Will Resign Active. Again, you implement Application Will Resign Active, and the system will call you automatically. And this is important for you to pause and save the state of your application, because at this point, you don't know what's going to happen. You've resigned to active status, but you don't know what the user's going to do.

And let's say in this case, the user dismisses. Then you're responsible for implementing the application didResumeActive. And this will happen if they dismiss that interruption. Now, it's important at this point, depending on the context of your application, what you want to do. We recommend for most applications that they stay in their pause state.

Certainly for a game, you don't want to come back from a phone call and automatically, when you get that application did resume active, start your car again going 90 miles an hour down the road and run into a brick wall. So it's important to understand, based on your application, what its needs are, what you do when you get that resume active. The iPod application, obviously, when it gets the did resume active, just starts playing the music again because there's no need for the user to interact with that. It will just start playing again.

So we talked about if the user dismisses. Now what happens if the user accepts? Well, we're going to get our old friend, application will terminate. You're already doing this in your iPhone application code because this is the same as pressing the home button. And that's where you can also save state if you like, if you haven't updated your data on disk at that point. But like I said, this is the same as pressing home button. It's important to point out, though, that this is application will terminate. It's not application will terminate. Application might terminate or may I terminate. This is application will terminate. You must shut down at this point.

And lastly, I want to just talk briefly about concurrency. I'm going to talk more about this in Part 2, but I just want to touch on it, what's important here as part of my overall application architecture. Obviously, concurrency means performing side tasks. And the number one thing that people want to do is networking tasks. But what I want to point out here is it's really important to use asynchronous APIs when they're available, especially, as I said, for networking.

Things like NSURL connection. You do not want to use a blocking API for a high latency operation like networking, right? You don't want to say, go off and make this connection to a web server. You don't know if you're on an edge connection, a 3G, Wi-Fi. So you want to keep your application responsive. So by using the asynchronous APIs with these high latency operations, we give the best possible user experience. So always prefer those asynchronous APIs when they're available in the system.

Also, NSOperation, I'm going to talk about this much, much more in Part 2. But it's very powerful for doing side tasks, but it should be used for low latency, high demand operations, side tasks that you want to take advantage of. But it's important to remember as part of the application lifecycle, if you're going to do these side tasks, make sure you illustrate any activity to the user.

Inside UI application, we have network activity indicator visible, we've got a UI indicator view, and we've got UI progress view. So just make sure if you're going to go off and do these side tasks, that if you need to, especially if you're waiting for results, you're blocking your application, that you show that to the user.

So in summary, we want to manage our data carefully, and it impacts our architecture. We want to separate those responsibilities, stay focused one thing at a time, transfer ownership of data and objects so that we can break our application apart and reuse components. We want to conserve memory by doing those same things, breaking apart our application into smaller and smaller chunks, and we want to maintain that user experience. Whether we're focusing on data or doing side tasks, we want to maintain the user experience and be as dynamic and flexible as possible. Thanks for watching. If you're looking for more demos or code examples, make sure you check out Effective iPhone Application Architecture, Part 2.