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: wwdc2005-122
$eventId
ID of event: wwdc2005
$eventContentId
ID of session without event part: 122
$eventShortId
Shortened ID of event: wwdc05
$year
Year of session: 2005
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC05 • Session 122

Add Syncing to Your Application

Application Technologies • 58:33

Mac OS X Tiger features a new, high-performance synchronization engine that you can use with your application to keep your user's data in sync across all their computers and mobile devices. Learn how to implement Sync Services to synchronize your application's data between computers and with other applications. Bring your laptop to follow along and add this new functionality to your application.

Speaker: Ken Kocienda

Unlisted on Apple Developer site

Transcript

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

Well, how do you do that? Well, you use the Sync Services API. And you use it to do, to write a little piece of software we call a Sync Client. Okay, and this Sync Client cooperates very, very closely with your application. And it will move data from your application data store In an application-specific way, over into the sync engine, the sync engine will go and put that data into the truth, merging it as necessary with other data that may already be there.

And then the sync engine will Talk back to you and say, well, here is what the truth has. Here's some information that you need to know, some updates, some deletes, some modifies, what have you. And then you, with your sync client, can react to that information coming back.

from the Sync Engine and merge that data into your application data store. It's kind of the basic workflow of what happens. And after you do that, your application data will be in sync with the truth, which is sort of really where you want to be. You want to be in sync.

Okay. So now, well, you can kind of think of some ways you might want to do this yourself. You've just got a data file. Maybe you can just copy your data file to another machine. Maybe you can come up with some simplified sync methodology by yourself. But what you won't get All of these terrific features that you get for free by using the Sync Services framework.

Here's some of the real power, the real advantage of leveraging the work that we've done to provide this API. You get this terrific stuff for free. Things like conflict management. Not only the recognition of conflicts, but you also get for free a conflict resolution user interface. You get .Mac syncing for free.

You can merge data with other clients and other devices. We'll be looking at examples of that later. You also get things like a data change alert. So if you're going to be modifying a large number of records, the user might be interested in seeing that, "Oh, gosh, all of my contacts are going to change." And yet again, this data change alert is something that you get for free by using Sync Services to implement your sync client.

And really, I think all in all, this moving data around, getting this stuff for free, got what I think is a pretty good API to use. I think that's pretty interesting just in this scenario. But wait, there's more. Because here, you've got a scenario which really sort of begins to look like What a typical user's computing experience looks like.

They may have a smartphone, they've got a .Mac account, they're using your application, they're using some system applications, and if you get all of those things talking together, exchanging data with the sync engine, That's pretty cool. And what's more, using .MAC, you can now get that information moving from desktop machine to laptop machine to desktop machine elsewhere.

[Transcript missing]

That's pretty cool. And what's more, using .MAC, you can now get that information moving from desktop machine to laptop machine to desktop machine elsewhere.

It'll really benefit your users. And I think it's a pretty cool new technology on Tiger as well. So now what I'd like to do is give you a little example of how this actually works. We have the Demo 1 machine. Now what I've done is I've written a little application over here that syncs. And that's wrong. Yeah, that's wrong. Just a moment.

Okay, so what I've done over here is I've written this little application that knows how to sync. And what does it sync with? Well, It syncs contacts with address book. So you'll see right now what I've got is I've got a number of entries in the address book, but my little demo application is empty of data. So I'm just going to come along and hit the Sync button.

It syncs contacts with address book. So you'll see right now what I've got is I've got a number of entries in the address book, but my little demo application is empty of data. So I'm just going to come along and hit the Sync button. But now let's actually look at some of the stuff that you get for free.

So let's do a real-world case. So now a user comes over into the People application and makes a change to an entry. John Doe is now John Doe spelled like you would spell it if you were kneading bread. And then over in the address book, before I sync, I'm actually going to make an incompatible change. So now over in the address book, I've got John Doe.

Okay. So now, what happens when I come over here and sync? I poke the sync button in the People application, and what's going to happen is I'm going to get this conflict resolution dialog. Again, I wrote no code in my little demo application to make this user interface come up.

The sync engine recognizes this change, is a conflict, gives me the opportunity to come over and say, "Which one do you want? Do you want Dough or Dough?" I can come over, select the one that I want, the one in the People application. No more DOLT for this whole time here now. And again, this gives me now an opportunity to sync again. And now you see that both applications are in sync with the data that I chose from the conflict resolver.

Okay. Pretty cool. Okay, can we go back to the slides please? Okay, so again, what we're going to be doing for the rest of the period is kind of looking at, you know, yeah, the slides, yeah, I didn't go through all my slides. We're going to be talking about making sync work. We're going to be talking about what actually went on during that sync session.

When I was adding and deleting and modifying, what was actually happening? Talk about making sync work. Now, really, again, to reiterate this point, if you've got this scenario here, you've got your application sitting out there now. It doesn't sync. And now you want to make it possible to interact with the sync engine and sort of join that sync ecology. Well, the thing that you need to do, the one high-level thing you need to do is you need to write a sync client. Okay, talk's over, right? That's all done. No.

But now what you need to do, right, is go and learn about our APIs, read our documentation, go out and experiment, you know, go out and use the code, make some attempts, find some bugs, fix some bugs, and so forth. But now what I'd really like to do is like what I mentioned before, is to give you some really sort of high-level ideas, things that you won't get by just going and reading the API documentation or looking at our tutorials and the other information that we have on the Internet.

As fine as it is, I would like to just give you a few ideas that you can take away with you as the high-level concepts to think about when it comes time to write your own sync client. And I describe those as data handling in your application. You need to do some work. to handle data, to convert it to and from the format that the sync engine wants to work with.

Next, you need to think about registration. You need to tell the sync engine about your client and about the kinds of data that you'll be syncing. Next, there's the real work, the real actual moving data back and forth between your code and the sync engine. And so there's session control flow.

And finally, there are a number of features, there are a number of options that the API makes available to you. And you can take advantage of these features depending on what kinds of applications you have and what specific kinds of syncing you want to do. And so these four things really sort of give us a roadmap, the things that we're going to be talking about for the rest of the session.

Okay? So now, you know, this is sort of one of these, you know, hands-on setup sort of things. And so if you go--if you've downloaded the sample code for the session, session 122, add Sync to your application, there's actually a little Xcode project in there for the people application that you see demonstrated that I'm actually going to be using for the rest of the--rest of the time.

And you can follow along. There will be actually quite a few code examples and you may wish to, you know, sort of get yourself oriented to those. But The code examples that I'll be looking at, that I'll be showing, look like this. You'll see right across the top is the file name that I'll be in.

And then the method beneath that, and then of course the code example beneath that. So if you're interested in following along, that's sort of how to do it. If not, if you'd just rather look at me, well maybe not. Maybe it'd be better if you look at code. This is sort of how it works, so you can kind of follow along. So now we're back to this, the roadmap. And first on there is data handling, so let's get right into that.

There's two things to really think about in terms of data handling. The thing that you need to do to kind of make your app, your data sort of work with and interact the sync engine is that first point, converting to and from the sync data format, if you will.

And secondly, optimizing to track data changes. Let's look at the first one. First, converting data. So now you might imagine from this People application syncing with Address Book, some names from Address Book going into that People application. Well, you might imagine that I have something like this in my little People application, a person object. It's got a couple of fields in it.

I might have something like that. It turns out, actually, the way that this is implemented in the People application is just a little record. It's just a little dictionary that has some named keys for the things that are supported by the application. So we've got a first name key and a last name key and so forth. And so your job is to go and then convert that data from your application-specific format to the format that the sync engine will understand.

So you're going to have to have this conversion step, this method or function that you're going to need to write to do this conversion. You'll see in this example, the conversion is very, very straightforward. It may be that way for your application. You may actually need to do some serious work in this step.

I've just written in the People application just a very, very simple method to just go and basically convert a dictionary from one form to a dictionary in another form. The one that my application uses on the one hand to the one that the sync engine uses on the other. It's very, very straightforward. You see sort of the one highlighted line there just sort of twiddling one sort of first name form to another. Again, in this case, very, very straightforward.

Similarly, when the sync engine communicates back to you new information, you need to then actually convert it to the internal representation that your application uses. And so, again, there's just a method, convert sync record to app record, just going the other way. Taking a dictionary, converting it from one form back to the form that you use in your code. Again, very, very straightforward.

So next. This next step, this optimization step, is really just sort of a suggestion. It's not really a requirement. This data conversion that I was mentioning before is really something that you must do, whereas this is something that it's just strongly suggested that you do, this tracking data changes. Well, why is that? Let me just, you know, illustrate it with a small example. So let's say you're in your application and you want to sync.

So if you're not tracking data changes, in other words, if you don't know what has changed in your data since you last synced, Let's take this scenario. You've synced, you've made some changes over time, and now you're ready to sync again. If you don't know what's just happened only in that period between two syncs, The only thing that you can do is actually then tell the sync engine about all the data that you have, all of your sync information. It's your only option if you don't know what has just changed or knowing only about the change. Sync session to sync session, this is what you need to do. Push all your data.

The alternative, of course, is that if you do know, well, then you can just tell the sync engine about, here's the only-- just what's changed since I last spoke to you. And as you can see here now, maybe in the case of the People application, we only had a half a dozen records. It doesn't really make that much of a difference.

But if you're syncing a lot of data, you can imagine that, well, pushing 10,000 records is not going to go as nice for your user as just pushing maybe a small handful. And so again, tracking these data changes, it's really strongly suggested. Particularly if your data set gets large, for some definition of large.

Sort of more suggested the more you get into the thousands and ten thousands of things. Okay, now here's just a very, very simple example of how the People application tracks changes. I just have a change object. It's sort of--this is in some ways you might say this is sort of like the command design pattern. I just have an object representing a change, an add, delete, or a modify.

Over here, you see this table view set object value just coming back right from the Cocoa table view there. This is the way that the application deals with the changes. And I just create one of these little change objects, tell my application to apply it, and over here, you see the key point. I actually use this to change the internal data store, but you'll see that highlighted line over there is I'm actually storing away that change object. I'll go and empty that. I'll go and empty that change store when it comes time to sync.

See, just got a little fringe benefit in the bottom there. I can actually just implement these for undo as well. So if you're not using something like Core Data, which takes advantage-- or gives you that benefit, I mean, this is a very, very useful pattern just generally. OK, but the important point is, again, that I'm storing away this change.

And again, that's just really, really very, very strongly suggested if you're going to be-- particularly if you're going to be dealing and syncing with large data sets. And so again, these are the two things that you need to think about in terms of data handling to start syncing in your app. Okay, next. We go from data handling, and now the second thing is registration. Well, what do you need to register? There are two things you need to register. There's a sync schema and a sync client description.

Now, I have to admit to you that I'm relatively new in sync technology. I've been working for a few years on Safari and just recently came over to work on sync. And this is actually something that was confusing to me in the beginning. So hopefully, if you're new to sync as well, I can sort of maybe help you and maybe save you some time on trying to get an understanding of what these two concepts are. So first, the Sync Schema. What it does is it describes data to the sync engine. In some ways it's analogous to, it's really almost like a class, a class description.

in say object-oriented programming. It's not exactly the same but it's sort of the same conceptual area. And inside of these sync schemas are entities, elements of just a data model, just a thing in the schema. And there are also relationships which are sort of referencing entities, referencing other entities in the schema. If you're familiar with databases, you'll know that these two terms would probably be pretty familiar to you, entities and relationships. And as a matter of fact, sync schemas are really just that. They're just entity relationship graphs.

And so you might be thinking, well, you know, that People application, it just sort of did some first names and last names, and that's all well and good for me, for my, you know, nice little toy example up here on stage. But I want to point out to you that these sync schemas can get to be really pretty detailed, really pretty complex in the number of entities, kinds of relationships in this. Really, the important point is that you can make your own schemas to represent your data. It's one of the things that's open about the system. It's one of the things that you as developers can come in and add to to make it work for your particular application.

And I just want to introduce one more term having to do with schemas, because I'm probably going to say it later. And I just want to make sure that you know what I'm talking about when I do say it. And that's the notion of a data class. And this is really, this data class is really, it's really just a logical grouping of entities. And, well, logical to whom? To developers or users. Well, it actually turns out to be logical to users. So you'll have a data class for contacts, for instance. And that will include things like... Actual people, groups, things like that.

So the whole sort of contact schema addresses and IM addresses and so forth. Okay, so now again to stress this point, if you have your own code, your own data, just a very simple little example, let's say you have a little calendaring application or something like that that keeps track of names and the start dates of events.

Here I've got my vacation which is actually true, it starts on 6/13. All I have to do is get through this talk. So now it starts on 6/13. Well here's how you would represent that schema to the sync engine. Just a name as well, it's going to be a string and a start will be an NSDate.

Just very simple and straightforward. Now, you may wish to go along and sort of continue on that example, go out and completely flesh that out so that it represents the data that you have in your application. But what you can also do is you can use an existing schema on the system. And here are a couple of examples of schemas that ship on Mac OS X Tiger.

You saw in the People application that application taking advantage of the contact schema and actually syncing contacts with the address book. There's actually even a pretty important point that I want to stress to you is that the People application is not syncing with the address book. It's syncing with contacts. It's syncing with the contacts schema that the sync engine knows about.

It just so happens that the address book also syncs with the contact schema and it's sort of, you know, you might even say the canonical sync client for that particular data class. But it's an important conceptual difference is that you're syncing with a schema, you're not syncing with an app.

And so, if we just take a little look at what is in that contact scheme, all the things like you might expect, contacts, groups, email addresses, street addresses, and so forth. But that point that I was just making is that you can, if you wish, come along and just sync with a portion of one of these existing schemas. Your application may sync with a little bit of contacts, a little bit of calendaring information, and then a little bit of your own application-specific information to make up sort of the recipe of what your application syncs. And this is possible. You saw an example of it.

Okay? So now, just kind of get down into the details a little bit. These schemas are defined in plist files. You can make one in Xcode. If you go to Xcode and choose New Project and scroll down that list, you'll actually see that there is a project type for a sync schema.

strongly suggested that you use the Xcode project to make it. Okay, so now back to registration. Now the second one on that item is that client description. Well, what does that do? How is that different from the sync schema? Well, see, this client description is actually what your client uses to tell the sync engine about itself. So the sync schema talks about data. The sync client really is talking about an actual piece of code that's going to be syncing.

Okay, it's also described in a plist file. But really, what's the difference between these two things? Again, that sync schema describes data to the sync engine and the sync client description, another way of thinking maybe is just a bridge between the application and the sync engine. And over that bridge is going to be going things as you've described them in that client description.

Another way of looking at it is maybe this sync scheme is what can possibly be synced. Defines the full range of options, whereas the sync client description says, well, this is what I want to sync just in this application. You may have a consumer and a pro version of your application.

Maybe that consumer version only syncs a portion of what your pro application does. But if your user upgrades to the pro version, you may want them to then have access to that full version of the schema. So again, just a kind of a little example of what the difference between these two things are. They're both described in plist files.

And here's just a sort of a little, you know, sort of naming example. You know, in the myschema.plist, this is the sync schema. You'll see that there are data classes and entities and attributes and relationships to things that are required to make that sync schema work. This is documented. We're not going to go into it in any great detail here now.

The client description, on the other hand, is again, this is the one that is actually used by the People application. You'll see there that it's just got those four columns. If you go and look at the contact schema, well, it's very, very large. This is only syncing with those four things.

Okay, but again, described in a P list file. So now if you kind of want to actually go and do the work of this registration, which I had at the sort of the kind of the splash graphic at the start of this section, it was very, very straightforward.

Registering a schema is just a couple of lines of code as you can see, and also registering a client is similarly straightforward. Of course, these are the essential steps, sort of the bootstrap steps that you really need to do in order to get going in your sync client. Okay, so that is registration. Now next, we're going to talk about Session Control Flow. Pardon me a second.

Okay, so Session Control Flow. So now you've kind of done the work to get your data ready. And you've registered, you've kind of bootstrapped the system there a little bit, telling the sync engine about your schema and your client description. And now you actually want to go do the work of syncing one time.

And here are the steps that you need to do. Starting a session, negotiating the session, pushing and pulling data, and then finishing or canceling. So let's look at these in turn. Starting a session. So this sync session is really, and we're talking about this session control flow, it really is this one complete transaction with the sync engine. Going and telling the data about your data as it stands right now, getting back from the sync engine all the new stuff that you need to worry about coming from the truth.

And so there's actually two ways that you can start a session, one synchronously and one asynchronously. Well, you say, well, why would I need an asynchronous call to start a session? And that would be a good question if you'd answer it, so I'll answer it. You'll actually notice if you think back to the People example, I actually had the Sync button in the People example, but there's no Sync button in the Address Book. So how does the Address Book know that it should sync? When I added that entry to the People application, how did the Address Book get it? Well, there's actually a notification that goes out.

When the People application started to sync, the sync engine said, I'm syncing contacts. Anybody else interested? And the address book says, yes, I'm interested. And so that's why you have this asynchronous call, so that sort of invitation can go out to other sync clients. is the first person to ask them if they want to join in. You'll actually see there, you're telling the entities that you're going to be syncing, that second argument there and that begin session in background at the bottom of the screen.

And you actually then pass an object and a selector that will get called back when the session is ready to begin. And here is that method that performs sync. If you see there at the bottom, it performs sync::. Here is actually what's in perform sync. You get You get a client in a session. Beginning the session may have failed, so you check for nil. And if you actually have a good session, you just go and do the other steps, which are on the earlier slide-- negotiating, pushing, and then pulling.

Now is a good time to actually mention that the sync session is actually, it's really a state machine. You need to do certain things in certain order, and this is documented very, very well. on the website and in your developer documentation. But it's important to point out that you can't pull then push in the same session. That will not work.

And you have to negotiate to you, you sort of have to get to an agreement with the sync engine about what's going to happen before you can do either pushing or pulling. OK, so let's talk about negotiating a little bit. Negotiating-- well, it's a little dose of the real world here. Negotiating section-- you ask for what you want, but you may not get what you ask for.

It's really up to the sync engine to tell you what kind of sync session is going to happen. Again, you can ask and your wishes will be respected as much as possible. But again, you may not get what you ask for. Here are the four different kinds of sync sessions that we'll talk about here today. So there's FastSync. We described an example of this to you before, which is just telling the sync engine about the changes that you had since you last synced.

I'll just tell you about my changes. That's it. There's Slow Syncing. I'm going to tell you about all of my records. Interestingly here, there's sort of--this is the way the deletes are done. If you slow sync and you don't tell the sync engine about a record that you told it about before, that's construed to be a delete.

Okay? There's refresh syncing which is, let's say, a scenario where you read your data file and you notice there's some corruption. You don't have all the data that you think you should have. You can actually ask the sync engine, "Hey, look, I don't have all of my records. Some of them seem to be damaged.

What I'm going to do is I'm going to tell you about all the records I do have and you give me all of the records that the truth has." Really, the important differences here is if you don't tell the sync engine about a record, it will not construe it as a delete in a refresh sync.

Okay. And then there's Pull the Truth, which is I just want to wipe out all of the data that I have and I want to replace it with what the truth has. Okay. So those are the four different kinds of sessions you can ask for. And here's a little bit about how you ask for them. So in this Negotiate Session method, if you remember that Perform Sync method, the first thing, Negotiate Session.

If we just step through those quickly, FastSync, well, FastSync is the default. So you don't have to do anything to ask for that. You don't have to make any API call. That's the base assumption. If you do want to slow sync, you tell the sync engine, well, I want to push all the records for a particular entity name. So for contacts, I want to push everyone that I have.

For Refresh Sync, well, I've reset all of my entity names. Excuse me. Yeah. Reset all of my entity names. This, both of these pass an array, as you can see, of entity names. Now, pulling the truth is actually sort of fibbing a little. That part of negotiation actually has to happen before you start your session.

It's sort of kind of such a special operation that the sync engine needs to know about that actually even before you start the session. So you'll see that background call on the very, very bottom. And previous to that, there's the check to see whether or not the sync mode that you want is pull the truth.

Okay. Okay, so that's about negotiation. What kind of sync session are you going to have? So next, once you have asked for your session, you push. And pushing is all about just telling the sync engine about your application data. Okay, so now when you get into the doing pushing, here's sort of like where you find out what you got.

from the Sync Engine, you asked for some things in the negotiation phase. Here's where you find your answer. So in pushing data for session, this line on the top is, should I push all the records for a particular entity name? And if the answer to that question comes back yes from the sync session, you slow sync.

That's what this is. That's what a yes answer from this method tells you. And you'll actually see there on the second highlighted line that what you're doing there is that I'm actually records is the data structure in the people application that contains all of the records that I have.

So I'm telling, I'm enumerating over those. And you actually then see a few lines down. If you look for the convert line, you'll actually see that that's the step where I'm actually doing this conversion, that data handling step of converting from an application record to a sync record.

And then going and telling the sync session, push those changes down at the very bottom there. Okay, so that's slow syncing. Here, should I push the changes for the entity name? Well, that's pretty clear that then this is a fast sync. And you'll see that the object that I'm enumerating over now is that mchanges object that I had before that I was storing away after I got the information back from the user after handling the change in the table in the user interface. This is where I just iterate over all of those.

And then go Add, Modify, Delete as the change object says. He was just sort of skipping down a little bit, that same method. If I'm modifying, I'm then going and converting my app record to a sync record again. And I'm pushing the changes from that record. There's actually even a little opportunity for an optimization here. If my record was particularly large, I don't even have to push the whole record. I can just push sort of the elements of the record that change. see that two commented outlines there.

Sort of the my sync change with change, sort of waving my hands here to say, you could write a method that would then go and just extract out, if you change just the first name and not the last name, the sync engine, you can get down to that level of granularity and tell the sync engine just about that.

Okay, so that's pushing. And now pulling. So now pulling changes is all about getting changes back from the sync engine. Okay, after you've pushed, you pull changes. So now there's a little bit of negotiation that needs to go along here now. Again, parts of the answer coming back about what kind of session you have. So you ask this question, sync session, should I pull changes for the entity name at all? Well, if not, then no, no pulling is to be done and you can just return at this point.

No polling. However, if that comes back yes, you can ask it, well, should I replace all the records on the client for this particular entity name? If this comes back yes, it means you're pulling the truth. Now, an important point, just something that just may not be readily apparent to you now is don't delete all your data now.

Now would be a bad time to throw away all your data. The reason for that is the line right beneath that is that, okay, I'm actually ready to pull. And you'll see that there's a before date on that line. Prepare to pull changes for entity name before date.

You may never return. Or it may return no. Now think about that. If you said, "Okay, should I replace all of my records?" Yes, great. Throw all my data away. And then this method returns no. Well, you just left the user with a nice empty window. threw away all your local data and didn't get any new data from the sync engine. Well, what do you do then? So there's actually-- you need to save that.

Save sort of the state that you want to replace all your records and wait until the sync engine says, OK, yeah, you're ready to pull now. And then you can go and delete your data. So it's kind of a, again, a sort of an interesting point which may not be readily apparent from just the API description itself.

about pulling. Okay. So when you pull data from a session, it's just kind of in some ways very, very similar to pushing data. You get back an object, you enumerate over the changes, adds, modifies, and deletes. You update your data store appropriately for all those using those conversion, converting the sync back record back to the app record things I've talked about before. That's where you would do that right in this step, pulling data. And again, you get that back from the sync engine in the form of adds, modifies, and deletes.

So that's pulling. So after you've done that, now you're ready to finish or cancel. So now cancel is about, well, the user hit the cancel button at any point during this operation. Or something went wrong. Maybe you've realized that you've run out of disk space. I mean, maybe not so common, but it's the kind of thing that could happen that might make you say, well, no, no, I as the program need to cancel this sync session. Okay? So I've actually got this method in the People application. Sync failed. As you can see, I did a very, very complete job of error handling. And it's logged there. But it's localized. I went and got the localized string.

just then did a little cleanup. The important line there is really the cancel syncing line for sync session. Sync session, cancel syncing. Okay, now finishes is really this, should not go over that too quickly, finishing is a two-part process. And let's look at what those two parts are. So now, this is even later down in the poll session part. It's the way that I wrote it.

Okay. This first part is all about accepting changes for a record. So now, when the sync engine tells you about a new record, when you pull, it gives you this identifier for it. And so you have to go back and tell the sync engine, "Yeah, I accept that change.

I've got it." And then later you'll see that then, well, Sync Session client commit accepted changes. So now why might these two steps be useful to you? Let's think about this for a second. So now let's say you know, I mean, we try to do as good a job as we can to make that sync operation go quickly.

But you'll notice if you think back to the sync example that when you push the sync button, well, we gave you a little indeterminate spinner there. And it came back after a couple of seconds. Well, let's say that I actually was pushing a lot of data. And it took many seconds.

You may not want to shut down your user interface while that's going on. You may want to keep that lively so that the user can continue to use your application while you're syncing. So let's say you change a record and you tell the sync engine about it and then the user comes in and modifies that record. Now you've got a conflict just waiting to happen.

This would be an opportunity if you can detect that. If you say, "Okay, well, I've told the sync engine about this change." And now you come to this point in the program and you say, "Oh, well, now I need to tell the sync engine whether I'm accepting a change for that record." If you can detect that difference that's happened since you started, you can tell the sync engine, "No, I'm not going to accept this change.

I'm going to actually keep what the user had, what the user put in most recently, since I started syncing." If you don't tell the sync engine that you've accepted that change, the next time you sync, you're going to get the nice conflict dialog for free. It'll give you that change again, and the sync engine will detect the conflict.

and give you the opportunity to resolve it. So all you have to do here is just a little bit of work to say, "Okay, well, I noticed that this record has been changed, so just--I'm not going to accept it. Not now." Okay? And so every record that you don't accept will be given to you again the next time.

Okay, so you go through that step, accepting and then commit your accepted changes. And then the last line, finish syncing. All done. Session done. Okay? So that takes us through the whole operation: starting, negotiating, pushing, pulling, finishing, and canceling. Okay, so now I'd like to do a little bit of a demo to, no, I don't want to do that yet. Let's do the demo for Session Control Flow.

Okay, we're back in the People application again, and just to make sure that we are actually in sync, so I pressed the Sync button. You'll notice on the bottom there, I've got a little pop-up button that right now says Fast Sync. So I'm just telling the sync engine about my changes.

You'll see if I pop that up, I've got some of the other sync modes there that we've talked about-- Fast Sync, Slow Sync, Refresh Sync, and Pull the Truth. So let's actually give this a workout. I'm going to go and delete an entry. from the People application and then come down here in Refresh Sync.

This again sort of models, it's like, well, maybe I lost that record. The data file got corrupted right at that point. So if I refresh sync, you'll notice that, well, I'll get that record back. The sync engine just says, well, you didn't tell me about this one. Here it is again.

Okay, you can also then, let's just say I delete all my records, I can come down here and pull the truth. And similarly, I'll get them all back. Now, you may be wondering, as I did, what the difference is between refresh and pull the truth. Now, the differences in some ways are subtle, and I don't know if I really want to get into it all that deeply right now.

If you really have interest in that, I'll give you just a little. We do have a lab session tomorrow where we can get into that in real detail. But let me just give you a little bit of a taste of what you might want to do with refresh, sync, and pull the truth.

This example was given to me by a friend just recently. So let's say you've got your phone and you notice that, oh, man, my phone, it's all garbled now. My information isn't there. So I've lost all my records. Man, I'm going to have to come back and pull the truth next time I sync, so make sure I've got all my entries back on my phone.

But before you get back home, let's say this happened to me. Angelina Jolie stops me on the way out of the conference center today, and she says, "Ken, I was in your sync session. I loved it so much. We need to have coffee sometime. Just want to know more about syncing." So I get her phone number down in my phone now. So now I've got one entry in my phone. It's a pretty darn important one. I don't want to lose that one now. I want to give her a call back later.

Okay? So now, pulling the truth would be bad because pulling the truth says, "Well, I just want to throw out all my records and replace them with what the truth has." That would be bad. I would lose Angelina's phone number, and she'd just have to spend more time with Brad Pitt, which would really be compared to me.

I don't know. So now let's actually see if I can kind of work up a little example of that. So now let's say I delete a bunch of records from here. And actually, let's say you can delete all the records. And I add back Angelina. Jolie, if I can only type.

OK. And I pull the truth. Well, you'll see what will happen is Angelina gets clobbered. That's it. It's gone. I just replaced my application store with what was in the truth. If I do this again, and I add back Angelina, And instead of pulling the truth, I just refresh sync.

You'll see that Angelina is still there, along with all of the records that got deleted before. It's just, again, just a little sort of example of what the difference is between these two sync modes. Okay? And then naturally, Fast Sync is just all about, again, just telling the sync engine about changes that you had. You can see over here, I've got seven records. I delete one and Fast Sync and what I've got back over here is now six records. Just all about changes. Pushing that delete. Okay? OK? OK, let's go back to the slides.

Okay, so that's all about Session Control Flow, showing you the different kinds of sync modes that are available. Okay, so now the last sort of high-level idea, is Featured Decisions. Now there are many, and I can't cover them all now, but I've picked out A few interesting ones. Things like record filtering, record formatting, responding to sync alerts.

These are things you may wish to do. That's why the question marks are there. Things you may wish to do when you are writing your sync client. So let's take a closer look at what some of these are. Record filtering. Well, record filtering is all about ignoring records. There may be in your application some records you're not interested in dealing with.

Now, I actually made a filter for the People application. And the way you do this is just with a little hunk of code that conforms to the iSync filtering protocol. You'll see that at the top. In this example, here's a last name filter. And what this actually does is this one method here at the bottom should apply record with record identifier. What it does is it says, "Well, in my client, my People application, I only want to deal with records that have a last name. It doesn't have a last name. I just don't want to know about it.

I'm not interested." We'll see an example of where you can use this later. You may wish in your application to say, "I'm not interested in records that are of a certain, you know, too big or were created before a certain time." You can put whatever sort of check that you want in there for that record. Okay. Okay, so record filtering, they're set up before starting a session. And here's just how you do it.

Okay. Before you start your session, you just go and set your filters. Just very, very simple. One line of code, create that object, set the filter. You'll see as an alternative, you can just clear any filters you may have previously set by just passing an empty array. Very, very straightforward. Okay. Before you start your session, you just go and set your filters. Just very, very simple. The case where your application stores data in a different format than the truth stores it.

Okay, the very, very simple example of that is, let's say you have a device that can only store maybe 24 characters for an entry, for a name. Yet you may have some friends with very, very long names. The truth will continue to store those, but you want to store that clipped version on your device. Record formatting lets you keep those in sync even though they don't look the same anymore. The sync engine can detect that this thing, even though they look different, they are actually the same.

Okay. You'll notice this, if we go back to that Pull Data for Session slide, when you're going through and doing that sort of two-part finish-up process, Okay. You'll notice this, if we go back to that Pull Data for Session slide, when you're going through and doing that sort of two-part finish-up process, So that's where you do that, right when you're accepting records. Accept it, but here is my little alteration to it. Keep track of that, please.

Okay? Here is just a, you know, a little bit of code that would format first names to be, you know, no longer than 16 characters in length. Really pretty simple, straightforward. So when I'm converting a sync record back to the app griper, jumping back to that data handling step, here's a place where you can put in your formatting, record formatting.

So record formatting sync alerts. Now I've already mentioned sync alerts a little bit earlier. Sync is starting elsewhere. Do you care to join? This is again how the address book knew to sync with the People application even though it doesn't have a button. There's actually a couple of ways to do this, and again, I can't get into all of the different possibilities and permutations.

I will say that there's one way we'll talk about right now, which is setting a Sync Alert Handler. It's just an object and a selector that you set on the client to say, yeah, when syncs start happening, please call me. Tell me about the entity names that are going to sync.

And you'll see there at the bottom, the little implementation of the Sync Handler is the exact same thing that happens. Um, when the user hits the Sync button in the People application. So you'll still get the same dimming, it's just sort of just the People application just works that way when you sync.

Again, this is sort of glossing over a lot of details. There are more options here. Come to the lab period tomorrow if you have particular interest in this. Okay, so that's responding to sync alerts. Let's take a little look at doing that, at what some of these features, how they actually work.

Okay, so now I'm actually going to come over here and create a company in Address Book, Apple Computer. And I'm going to sync. So you'll see now that I'll get a new entry over here with Apple Computer. Well, great, but Apple Computer does not have a last name.

And so if I just come over here and go to the Options menu and say, well, yeah, now I use record filtering. So I'm not interested in records that don't have a last name. Apple computer doesn't have a last name. It doesn't-- you'll also notice that the address book doesn't delete that. It's just that the People application is just saying, look, I'm not interested in that.

I'll give you one more quick example, since I'm running a little short of time, which is record formatting. If I just delete all of my records and come back and pull the truth, you'll notice that my name, for instance, is now clipped. In this case, it was clipped to six characters to just-- my name is only eight, so 16 wouldn't really be a very good demo. So you'll see again that that's just the way that you can-- Filter Records. And coming over and fast syncing. Everything will just be good. You're in sync. The sync engine knows that these different representations of the data are actually the same.

Okay, so that's just a little look at some features. Okay, if I can go back to the slides now. Okay, so a little bit about features. And so there, Done talking about features. Again, these are the four things that I would like you to take away with you today.

If you're going to be making your sync client, here are the four things you need to know about data handling, registration, session control flow, and feature decisions. This would be just, I think, a good way to sort of now start looking at the API documentation we have, the tutorials we have, very, very nice examples that let you sort of get into this technology. Okay? And again, pay heed to these four things and I think that'll be a good way for you to get started. So that's it.

But there's one more thing, and that's Synchro Spectre. Now SyncRespector is a developer tool that I think you'll find very, very, very useful. If you haven't downloaded the sample code yet, I strongly suggest that you download it if you're going to be doing syncing so that you can get your hands on SyncRespector.

Now SyncRespector is a tool that we're making sort of available to you now in a kind of a WWDC developer release form. We would love to get some feedback from you on whether you like the tool, what other features you'd like to see in the tool, and so forth. I think it's really essential if you're going to be doing syncing. I'd like to show it to you just very quickly.

So over in your package, just right in there with the people example is the Sync Respector app. And if you start it up, it gives you a wealth of terrific information about the clients that you have registered. Here you see we've got the address book client. We've got the people client registered.

It tells you information about its registration, what it's registered for, when it last synced. It tells you a little bit about what kind of sync mode it's eligible for. tells you about the contents of the Truth database. I mentioned that to you earlier today. You'll see that there's actually, there's my entry in the Truth.

tells you what kind of entity it is, what its record identifier is. This terrific debugging tool over here, call history. These are all of the sync sessions that have happened with detailed information about what happened in the sync session. All of the sync API methods that got called with arguments and results.

So you can go and-- oh, my sync didn't work. What happened? If you've got the Sync Respecter preference on to enable call history, you will generate This call history, like you're looking at now, it's really just an invaluable tool if you're trying to sync and things don't go perfectly the first time.

Okay, so again, the Synchro Spectre tool is available right in your package with the People application. And if you're really interested in learning more about Synchro Spectre, again, come to the lab tomorrow. Okay, so back to the slides. Great, the developer tool. So that is really and truly it. So thank you.

Just a little sort of late additions there, some more information. Naturally, you can go to the developer.apple.com website for sample code. We've got another really, really nice example that someone on the team made, a more sort of complex, in-depth example that uses stickies that you really, really may be interested in looking at.

Again, come to the lab tomorrow if you're interested in that. I should say you could just download it from the sample code and come to the lab if you're interested in talking about it. Just a little sort of late additions there, some more information. Naturally, you can go to the developer.apple.com website