Video hosted by Apple at devstreaming-cdn.apple.com

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: wwdc2013-216
$eventId
ID of event: wwdc2013
$eventContentId
ID of session without event part: 216
$eventShortId
Shortened ID of event: wwdc13
$year
Year of session: 2013
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2013] [Session 216] Bringing Yo...

WWDC13 • Session 216

Bringing Your iOS Apps to OS X

Frameworks • iOS, OS X • 48:13

Learn how to leverage your existing iOS codebase to bring applications to the Mac. UIKit on iOS and AppKit on the Mac share a common heritage and many similarities. Below both of them, sit many frameworks that are shared. Learn design patterns that will make the conversion easier, discover tips and tricks of the conversion process, and explore Mac-only technologies that are important to include.

Speakers: Cortis Clark, Dan Schimpf

Unlisted on Apple Developer site

Transcript

This transcript has potential transcription errors. We are working on an improved version.

Good morning. [applause] Before we get started, I'd like to do a small, informal survey. How many of you are new Apple developers? Please clap your hands. [applause] Excellent. Welcome. And how many of you have made an app for iPhone, iPad, or iPod Touch? Please clap your hands.

[applause] It sounds like about all of you. OK. And how many of those that have made apps have brought those same apps over to OS X, to the Mac? [applause] Sounds like a few of you. But it sounds like we're all in the right place today. Did you know that in the last quarter alone, Apple sold nearly 4 million Macs? Yeah, and we want your apps to be in every single one of them. And we're here to show you how to do that. Now, after you leave here today, you're going to be ready to do three things.

Number one, you're going to be able to rethink your iOS app in terms of a Mac, in terms of OS X. Two, you're going to be ready to restructure your code, just cleanly separate your model from your view and your controller so that you can maximize your code reuse. And number 3 is easy. You're going to be ready to just get started. So let's talk about your design.

Many of you may be thinking, "OK, so I have my iOS app and I'm going to bring it over to OS X and I'm going to leave everything the same because that's going to be pretty easy." I'm going to discourage you from doing that. Your users are going to love it if you embrace the things that make the Mac great. So what makes the Mac different form iOS? Well, for one thing, screen size.

If you think about it, your iPhone is on a 4-inch display, if you have an iPhone 5, or if you have an iPad, it's on a 10-inch display. But our Macs go from an 11-inch Macbook Air to a 27-inch Thunderbolt Display. And your users could have multiple displays.

So, that's something to think about. And then on top of that, your content is going to be on a window that's resizable. So, who knows how big your content will be for the user at any one point in time. So, I'm going to encourage you to use Auto Layout because that's going to solve a lot of your issues with these different display sizes. OK. Let's talk about input devices.

On iOS, your primary input device is your finger and as such, we've given you guidance to use controls and buttons that are 44 points by 44 points. Now, in OS X, your input devices are a trackpad or mouse, and are much more precise. So you don't want to make your controls unnecessarily large on OS X. It's going to look-- well, it looks out of place so keep that in mind.

What about other things? What are some other things that make the Mac different? Well, for one thing, the Mac's got menus and keyboard shortcuts and these aren't just any menus. Mac users are going to be expecting to see File, Edit, and the Window menu. And they're expecting to see the standard keyboard shortcuts for those menus. Like for instance, Cut, Copy, and Paste.

And they're going to expect to see Undo and Redo support. You may have it in your iOS apps but you may not. But on the Mac, if it's appropriate, please use that, because your Mac users will expect it. They're going to expect to be able to drag files and texts and images into, out of, and between windows in your apps.

Quick Look is a technology on OS X that allows users to see the contents of your file without opening it in your app. And we've handled many of the common cases like for PDF, and texts, images. But if you're making a custom file format in your app, it'll be great if you added a Quick Look plugin to allow users to see the contents of your file without opening your app. That would really make them happy.

Similarly, Spotlight, that's the technology that allows users to search the contents of your file. So if you have a custom file format, consider making a custom Spotlight indexer so that users can search the contents of your file. So then, we've talked about design a little bit. Let's talk about your code. Now the good news is that you can leverage a lot of existing knowledge that you already know from iOS. For instance, the design patterns, the model-view-controller, the target-action pattern, the responder chain, delegation, all of those patterns work on iOS just like they do in OS X.

A new development environment, Xcode, with its built-in user Interface Editor and Static Analyzer, its profiling tools, and all the things like the source control tools that you get from Xcode, all of those are available on OS X as well as an iOS because you're using the same development tool, Xcode.

The languages, C, Objective-C, C++, and many of the frameworks like Core Foundation and Foundation are going to be the same on iOS as they are in OS X. The resources, your images, some of your images might be different because you're going to be resizing them to make them smaller perhaps, but some of them will be the same. You'll be able to use those again.

And then, also the image technologies, this week we're talking about asset catalogues, the Xcode talked about that and that's one of the things that's available on both OS X and iOS and you can use that for this, and also the naming conventions. If you're doing a Retina Mac, you're going to add at 2X to your file names just like you do on iOS.

And localizations, most of your strings are going to be exactly the same and the technologies used to localize are going to be the same. So you're going to use NSLocalizedString method to make sure that your localizations work. So, I've outlined some of the things that are the same. So what's different? Well, let's take a deeper look at the technology stack.

So here's a big table and that has a lot of the frameworks on iOS and OS X. There's a couple of things I'd like you to notice. Number one is that a lot of the frameworks on iOS are the exact same as they are in OS X. And this is actually just a small subset of all of the frameworks that we have available. I only did one slide here.

Actually, I did two. We'll look at the other one in a second, but, anyway. The-- but yeah, so keep in mind that most of the frameworks-- a lot of the frameworks are going to be the same. Now, there are some that are different and of the ones that are different, most of the ones that are different are going to be subsets of the OS X version. So you get to keep your code the same because you're going to be using the subset part on iOS. So when you move to OS X, you can even use some new features.

The last thing I would like to point out, most of you are going to be spending a lot of time in UIKit and the news is that UIKit does not exist on OS X. But the good news is that we have AppKit. And actually, UIKit was inspired by AppKit. That's right. That means that a lot of the things will feel very familiar. And we're going to talk about some of the differences and ways that you can cope with those.

And then one more slide on technology, I want to talk about games briefly because many of you may be making games. If you're making games for OS X, there's some great news. One thing is we have OpenGL, Game Center, and SpriteKit. And if you're making a Mac 2D game, really take advantage of SpriteKit if you can because that's going to do most of the heavy lifting for you. That's already cross-platform and so you'll have an app that works on both. So, now that we've talked a little bit about that, let's go into design patterns.

Does everyone recognize that, that's the Model-View-Controller design pattern, and hopefully you're using that in your apps. If you're not, Model-View-Controller is a software architecture pattern that separates the representation of information from the user's interaction with it. And the model, we're going to talk about first, is only supposed to be used for your data structures, your business rules and logic.

And if you cleanly separate it out that way, you're going to get some benefits. Almost all of your model code is going to be reusable. Why? Because the frameworks underneath the model are cross-platform. So what that means, if you have some code and here's some iOS code, that is going to init an array, a mutable array with ten elements and we're going to add a string to it, in this case, WWDC 2013. Your OS X code is going to look like this.

It's the same, right? That's great. So you don't have to do any work there. So cleanly separate your model. Now, one thing to keep in mind is that your model code may be making an assumption that's not true on the Mac which is Macs are 64 bit and iOS, your iOS code may not be ready to handle that. So what do you for that? Well, it's really easy.

Adopt NSInteger and NSUInterger. Those are variably sized integers that are going to give you 64 bit on the hardware and we'll give you 32 bits when you need it. So, that's perfect. Now what if you really do need a 32 bit integer and not 64 bit? Like for instance, if you're doing a binary file format that's already specified and you want to make sure that it is right, well, we recommend that you use uint32-t and its cousins and that's got you taken care of. So what about platform specific code? So if I'm writing iOS only code and there may be some times that you do that, you're going to use the preprocessor macro #if TARGET-OS-IPHONE.

And if you're doing Mac only code, you would use #if TARGET-OS-MAC && !TARGET-OS-IPHONE. OK. So now that we've talked about the model, let's go on to the view. The view is any output representation of your data and it's also where you're user interface lives. So, a big part of the user interface are the built-in control set. So what does it look like on OS X?

Well here's kind of an idea of the landscape. We have a lot of controls on iOS a ton of controls, even more controls on OS X. And they overlap and there are a lot of controls in common but there are some that are different. So, you'll need to look at alternatives in some cases between the two.

One of the most used controls on iOS is the TableView, and good news, there's a TableView on OS X. So, it's called NSTableView. If you're noticing a pattern, it's just a coincidence but all the UIs and actually, yeah. So, there's some similarities between the two. They both use data sources as their delegates.

They both encourage the use of reusable cells that's going to maximize your performance. And they both animate insertion, deletion, and moving of cells. So, that's great. There are some differences too. One of the things that's different is that NSTableView actually has two different variants, that's for legacy reasons.

You want to use the view-based variant. That's most similar to iOS. The other one NSCell and I'm done talking about that. It's an NScell-based variant but don't use that. OK. The other thing to keep in mind is that you're going to get multiple columns. So, yay, that's cool.

And lastly, is this really the right control for you? It may be. If you're doing tabular data then it's the right control for iOS and OS X. But if you're doing something else, then it might be the right control for iOS but maybe not for OS X. So let's take a look at some examples.

So here on your left, you're going to see a TableView that the user selecting a region out of a whole list of regions. In this case, they've selected United States. On OS X, the appropriate control to use here would be a popup menu. So, think about that. Now, one thing about that is that you can make those with NSPopupButton or just drag them out from Interface Builder. That's probably the easier way to go.

So what about something else? OK. So let's look at this one. OK. So, here's a TableView where it has it broken up into sections. So this first section, again, you're selecting an item out of-- in this case, just two items. So, on OS X, we'd recommend using a radio-button matrix instead. And on OS X-- sorry, on iOS, we have a on-off switch in your TableView, and that would be best suited for a checkbox.

And if-- one thing else I'd like to point out. This window here can be made with a StackView which will make your job a lot easier. So check out that. NSStackView, it's a new technology for Mavericks. OK. So, what if I am doing custom view like making a custom button or that kind of things? In a lot of cases, you're going to want to overwrite UIView or NSView. So, what if-- so what's the differences? They both receive and handle events, they're both responsible for drawing, but there's a couple of differences so let's go in those.

The UIView's origin is in the upper left and the NSView's origin is in the lower left. Before you despair, we'll have some information on how to fix that or accommodate for that. The UIView always has a layer, a Core Animation layer backing it, and that has some interesting benefits. On NSView, you can have a Core Animation layer but you have to opt-in to that.

And then, subviews can draw outside their bounds on UIView but they're clip to their bounds for NSView. So let's talk about origins. I promised to show you how to do that. Here's what it looks like. In UIView, you've got your upper left origin, NSView, lower left, you're just going to overwrite isFlipped and return yes. And what does that give you? Well, that.

So, there are some controls that are actually already have the origin flipped for you in advance, so be aware, and they are NSButton, NSScrollView, NSSPlitView, NSTabView, and NSTableView. So, what about layer backed views? So we have the Core Animation layers on UIView. What are the benefits? Why would we want to opt-in?

Well, we'd get smoother animation. And if you want to do anything with CAFilters, then that's the right choice for you. CAFfilters are pretty cool and if you watched the SpriteKit Talk, then you know a little bit about that. The downsides are that they can be more resource intensive. So, we urge you to test. Try it out, see if it works better, see if it fits in within the resources you want to use, and then pick one.

So what about layer backed views? So we have layer backed views, I told you what the benefits are, and that for UIViews they are on automatically and you have to opt-in on NSViews. So, how do you opt-in? Well, in code, you would call setWantsLayer:YES. But you can also do it in Xcode.

And so in Xcode, you go into the Interface Builder portion of it and you would-- in the inspector on the right, you're going to pick the last tab, that one there, and then you click on the little checkbox next to your View and that would make it layer backed.

OK. So for iOS, your animation code might look like this. So you do an animateWithDuration, you pass it a time, and then you're going to give it an animation block. Here we're setting the frame so we're going to animate the frame and then I'm closing the block. On OS X, we're going to use animation proxies. The codes look very familiar but it's going to be slightly different.

So, instead of changing the frame on the view directly, you're going to do something like this where you call this animator proxy in the middle and that's going to make sure that your view gets its frame set and also that it will animate. If you notice here that the we're not setting the time of the animation that has an implicit duration and there's some more details on that that you can learn about.

And we'll have references to that at the end. So, what about events? So you have on iOS these gesture recognizers and they're great. So, you have the UIGestureRecognizer and its subclasses and it makes it really easy to handle events. On OS X, you can handle all those same events but we-- there's no such thing as an NSGestureRecognizer. So how do you do it?

So here's a TapGestureRecognizer. And TapGestureRecognizer, the idea here it's a lot of times you use for a simple interactions like a simple touch. So, on OS X, it would be a simple click. And so, you would overwrite the mouseUp event and handle your click there. So, pretty easy, and you could do mouseDown as well but we recommend mouseUp because it's more what the user expects. So they can cancel the event. OK. So what about long press?

Well, for long press, you could do this. It's kind of complicated but I'll just run through it real quick. You set up a timer, and it's a half a second timer that's to mimic the way that the default long press recognizer is set up. And then you're going to do something. You've set up the selector to do something, that's the bottom method.

And then in your mouseUp event, you can invalidate that timer. So, like for instance that they mouseUp before the half second was over then it would stop it. So, you'd be effectively doing a long press there. But 99 percent of the time, you're going to want to use a Right Click instead because the long press is not really going to be familiar for the OS X crowd, and so, use the right click. And you're going to want to show a menu probably.

So to help you with that, we have a method that you can overwrite which is menuForEvent and that's going to get called if you right click on something or if you control click on it, any kind of contextual click, will give you this. And with this, you're going to pass back the menu which is going to handle the interaction.

So what about dragging? Well, one thing you could do is you could set up the mouseDown event and you're going to record your drag start location and your mouseDragged, you're going to do-- you're going to move the view and then in the mouseUp event you'd clean up. And that works really well especially it will-- I should say that works really well if you're inside of a View. So if you're moving something within a View, then that works great. So-- and that's kind of what you're used to in iOS.

But what if you wanted to do something really fancy like, say drag something from one window to another or perhaps one application to another. How would you do that? Well, it's pretty simple. I'll show you how to do it. So you're going to use this for mouseDown or mouseDragged and then you're going to set up a pasteboard and in your pasteboard, you're going to clear the current pasteboard and then you're going to pass in the element that you want to have-- actually, the model behind what you want to have dragged. In this example, we're dragging an image, so we're going to just pass in one element array, that's the new array syntax-, and, pass in that image.

And then we're going to call this bad boy. dragImage at Offset event pasteboard source slideBack. OK. So what is all that stuff. So, first thing is the dragImage and that's the image underneath the mouse pointer as you're dragging. The second thing you're going to pass is the location, the start location.

And the dragOffset actually is ignored so let's not talk about that anymore. The event is the mouseDown event that you've been passed in or mouseDragged event and only use this with mouseDown and mouseDragged. The documentation-- by the way, if there's anything here that I'm saying, go look at the documentations, it's got all the stuff. But I'm just pointing you in the right direction here.

Pasteboard, so the pasteboard is what you just set up there, the source is self and then slideBack. That's when if the user cancels then whether it slides back in the place, a little cool animation there. So you can put yes or no there. OK. So, now that we've talked about the view, let's take a look at the controller. Now, the controller is the part of your Model-View-Controller system that handles user input. And it's going to mediate that input and send it to commands for the Model or View to handle.

So, what do we do-- what are some tips for migrating the controller? First off, this is the common mistake, UIViewController. There is an NSViewController but it's probably not what you're looking for. You probably want to use NSWindowController instead which is a lot more similar to the UIVIewController. So, look there if you want that. And a lot of you may be using or I would say almost all of you are using UINavigationControllers. There is no such thing as an NSNavigationController.

And the reason-- now you think about that for a second. UINavigationController, what does it do? Well, it allows you to navigate between lots of different TableViews that are stacked on top of each other. And why do we stack them on top of each other? Because we have a 4-inch screen.

So, we don't really need that on OS X. In any case, it doesn't exist on OS X so you're going to have to find some alternative. But it's not the right interaction anyway. So, the next thing that we want to point out is Bindings. Bindings is going to really help you out here with controllers because bindings is a way on OS X that you can wire up your user interface without using any code inside of Interface Builder. So that's pretty cool. OK. Next, NSDocument, NSDocument is amazing.

It allows you to do some really cool stuff and it's going to really reduce the amount of controller code that you have to write. And you may be thinking, "NSDocument, that sounds like-- is that similar to UIDocument?" Well, yes it is. In fact, they have a lot of similarities.

Both of them are responsible for saving and loading, both of them will give you undo support very, very cheaply, and both of them are your tickets to iCloud. So if you want to get to iCloud, adopt UIDocument or NSDocument or both really. And-- but there's some differences between NSDocument and UIDocument. NSDocument has some extras, some real nice things that you should take advantage of.

You'll get for free really most of them. One of them is that you're going to get-- if you set up a document-based app on OS X, you're going to get a File, Edit, and Windows menu for free and they're almost entirely work without any code on your part.

You're going to get open panels and save sheets. And, you know, when you quit your app and you haven't saved, you get that little dialogue that comes down, that's for free, you'll get that, unless you turn on auto-save and then, you don't really need it. But if you turn on auto-save, you get Versions.

Yes, you're going to get this cool UI, a time machine UI right within your app, that allows you to compare one version of your file with another one. So that's really cool. And there's a really a lot more that NSDocument can do. So, check out the documentation for NSDocuments. OK. So, I'm going to bring Dan Schimpf on stage and we've been talking a lot in abstract and he's going to show you an iOS app that we're going to bring to OS X in a second. So, take it away, Dan. [applause]

Hi, good morning. OK. I'm going to show you-- I'm first going to start off with my awesome iOS application that I'm working on some into the store, and it's a simple graphics application. And what we can do here is just tap and make a few shapes. So, I can also change what size I want to make or what shape I'm going to make. I can drag-- even drag it around and put that around top of there, like do three whole shapes.

You can even change the color, sure, let's do that. So now look I have a nice little picture of a house with my-- this is what my house looks like. OK. So, that's just a demo. That's my brand new application but I'm thinking I want to bring this application to OS X.

So, I'm going to open the project here and let's just go through some of the code. So, as you can see I've already separated my code out into a Model View and Controller. So this is my document model. Don't need to go through a whole lot of this right now but it-- but the important thing is that a lot of it-- this is all things that are cross-platform. It imports foundation, things that are on both platforms. And the view side, I have the document view itself, the thing, the canvas, and then I have the shape view which is-- stand for each of these individual shapes that I can drag around.

And then on the controller side, I have a standard controller hierarchy, an app delegate, and then I have adopted UIDocument because I want to bring this to iPod and win an Apple design award next year. And then I've got a view controller for the view that I see and then two controllers for the things that pop up.

So, this is all pretty standard. And now I want to start on bringing this to OS X. So what's the first thing I do? Well, the first thing I'm going to do is just make a new target. So I'm going to make an OS X application, so the Cocoa application. I'm going to make this Shape Art OS X. You don't have to call it-- if you don't have the OS X at the end, I'm just going to say OS X just so there's no confusion during this demo. And I'm also going to make a document-based application.

So, you can see this is made a target for me. And also because I know this is a heavy graphics application, I'm also going to add a framework. I can search the Quartz framework and it knows that this is an OS X target so it's going to only give me the OS X version of Quartz.

OK. So now, I have this basic app and because I've separated my model cleanly, I can select all of the model classes and just simply add them into my-- excuse me, add them to my OS X target. Now, if I switch to my OS X target, I can actually build and run and see what it gets me.

So here we have-- this is what you get for free. You get a whole-- you have windows, you can make-- I can make many of them, I got all of the menu bar items that actually work. And I probably don't want to shift with "my document contents there" but it's a good starting point that you get for free and then you can adapt it from there. So I'm going to hand it back to Cortis, he's going to talk more about that part.

Thanks, Dan. So, awesome. So we have this app and it does some really cool things like "your documents here". But we don't have-- where's our colors? Where's our little shapes? So let's talk about-- we're going to talk about some migration strategies. They're going to help you move over your view and controller because we've only moved over the model at this point. Now keep in mind, this is kind of a toolbox of approaches. We're going to give you a bunch of different approaches. You know your code so you should decide what's the right approach for which situation. And your apps may use several of these.

And so to help with this, we're going to talk about it in terms of a particular example. In this case, we're going to talk about it in terms of color. Now, on iOS, you may all be familiar with UIColor. It's a relatively simple class, it allows you to create colors with red, green, blue, and alpha, and allows you to set them on the current context.

Now, it turns out that there's another class on OS X called, surprisingly enough, NSColor, and it allows you to create a color with red, green, blue, and alpha and set in on the current context. Now, NSColor does some other cool things like it will allow you to set up seem like CMYK colors and patterns, color spaces. But for now, let's just focus on those two things.

OK. So, if were overwriting code that we're using UIColor, I might do something like this. UIColor redColor, that's going to make a new color for me, and then your color, aColor dot set. So that's going to set on the current context. Pretty simple. On OS X it might look like this and the only difference here is that we have a different class name in place of the UIColor.

Now, this is what we're going to call the mirrored code strategy and for purposes of talking about it, I don't know if it's really officially called that but we're going to call that. Now, just to show you a little bit more what that might look like in a more complicated case, let's look at this next one.

This is not with colors. Now, There's a fair bit of code so let me explain what it's doing. It going to create a new view, it's going to center it on its parent view and then it's going to insert it underneath all of the other views on that view.

OK. So this first bit of code is going to compute the new origin, the new X and Y. And we did that with a little bit of math and it turns out that the math for OS X is going to be the same. So that part of the code is the same.

And then we're going to create the view itself. We'll make the frame, the CGRect frame, and we're going to create it with initWithFrame. And if you notice, the OS X code is very similar but there's a couple of changes. One is that we're using an NSRect instead of CGRect, and we also are using an NSView instead of a UIView, so-- but very similar at this point. And then for this last bit, we're going to insert it underneath all the other views on that view. So this is subview, so all of the other subviews.

And we use insertSubview atIndex on iOS. On OS X, we don't actually have that API so in that case, we're going to have to call addSubview, positioned, relativeTo. And so what that does is it-- we're going to add the subview which is the one that we just made, and then we're going to position it with NSWindowBelow and that's we below something. And since we're passing nil for our relativeTo, it's going to be below everything. So it does the same thing as the iOS code.

OK. So that's the mirrored code strategy. What are some of the benefits? Well, it's going to give us a lot of flexibility. So we're going to have things on iOS, we're going to write our code completely different on iOS from OS X. In fact it can give you something completely different. So that's kind of cool but it has some downsides, right?

There's code duplication there which means that whenever we want to change something on the iOS side, let' say add a feature or fix a bug, it's going to require a change on the OS X side. So there's greater maintenance cost and greater testing cost. So when do we use this strategy? Is it ever appropriate? The answer is yes, it is, sometimes appropriate. When you're using heavily platform dependent code, when there's stuff that's really just very different between the two, then this might be the right approach.

But there are some other approaches that we can take. So let's take a look at those. One thing that we can do is that, it turns out that UIKit and AppKit are actually built upon a common framework. And so, we can drop down to that lower framework. And it turns out that that will give us code that is cross-platform out of the box. Let's look at some code.

Here we're dropping down to the Core Image framework and it turns out that Core Image has a CIColor there and CIColor has a color with red, green, blue, alpha so we can create a red color. And in this case, we're actually going to-- we're not setting on the current context. We're creating an image with that color because that's one of the things that Core Image would want to do. And so, that's the code there for doing that.

Now, some benefits to using this-- since lower level frameworks are cross-platform, we're going to get-- we're going to maximize our code reuse. It's very robust and there's a lot less maintenance because we only have one set of code to deal with and with the interface is common so all of our code calling this is going to be the same.

There are some downsides. For one thing, it's going to require that you rewrite a bunch of your code and perhaps most importantly, and I want to stress this, you're losing a lot of functionality by dropping to the low level framework. There's a reason why we're making NSColor and UIColor available. And it's not just to like duplicate work.

So, because, you know, and CIColor doesn't handle color spaces, it won't do CMYK color, it won't do patterns. So, these are all things that you're going to lose. If you ever think that you're going to need that, then probably not the right strategy. So when do you use this?

It's when the lower level framework provides the needed functionality that you need, for now and in the future. So look at it and say "Hey, is this an appropriate match?" And if it's not, then let's look at some other strategies. OK. So, from software engineering, if any of you took that in college, you may be familiar with the adapter pattern.

The idea here is that we have some common source and it's already targeting iOS. And the code is already written so we don't really have to do anything on iOS. But what if we made the OS X code work the same way? So we could stick an adapter in there and that would give us the same interface for iOS and OS X. And let me just modify this slightly. We're going to make this a little bit different.

I want to make that adapter actually across both iOS and OS X? So if we do this, it will take a little bit of extra code but it means that our iOS code-- sorry, the iOS framework and the OS X framework can change and it doesn't matter because our code, our adapter code can stay the same. And so, the code that's calling it doesn't need to change. And so, we can just change the implementation. So that's actually a nice approach.

And it would look like this in code. Perhaps, this is a very simplified, just the header file version of it and without all the interfaces that you would need for various things. But this gives you an idea. We created class called XPlatformColor and we'd base it off of NSObject, and underneath that class, we would place a UIColor as the underlying color.

And so, whenever we need to do something on the color, we'd actually call through to iOS to do that for us so we wouldn't have to duplicate that code. And on OS X, we could put this in a separate file. In this case, we're putting it in on one slide so we use the condition-- the cross-platform macros that we talked about earlier. But in this case, we're going to base XPlatformColor on the underlying color of NSColor.

So that's what that would look like. So what are the benefits of that? And so you're going to have to-- by the way, this is doing some hand waving on the rest of the interface because you're going to have things like color with red, green, blue, alpha perhaps, or a red color or whatever you want to have as your interface. You can choose, right? This is your class that you're making. So what are the benefits of that? Well, one thing, you're going to be flexible again, a lot more flexible than mirrored code.

You're going to maximize your code reuse. This is a lot more reuse than mirrored code. Why is that? Because your interface is the same. So any place that you need to color, you're going to call XPlatformColor. And all of your platform specific stuff is hidden underneath an implementation of the XPlatformColor code.

So that's nice. It's a simplified interface because you're making it. It's tailor-made for you, so that's great. And it requires less maintenance because, again, you're-- you have a common interface and unlike mirrored code where you, you know, you want to change something, you had to change in all different places. So that's great.

The downsides are, it has some downsides, it's a lot of additional code that you got to write. So-- and so, there's going to be another strategy we can talk about next that has a little bit less code, so, anyway. When do you use this? Well, you use this when you're dealing with an underlying API that's significantly different between iOS and OS X. And this is a great pattern for that. OK. So, this is a great strategy. What about another strategy? OK. So here's one that we can take advantage of in some cases and that is the adapter pattern using #define.

Now, #define is the pre-processor macro that in this case is, what we're going to do is we're going to substitute every occurrence of XPlatformColor with UIColor. And we're doing that before the compiler ever gets to it. So this happens before compile time and that's going to have some cool advantages for that. And for OS X, we would substitute that with NSColor. So every time we see XPlatformColor, it's an automatically insert that.

Now, what does that do for us and what is it not do to us? There's a couple of things. For one thing, there's almost no new code to write. You saw it there, that's it. OK. So, that's nice. It's going to give you compile time air checking. So because it's doing it before the compiler ever gets to it, it will tell you if you're using it wrong, the compiler will. So if you're using a selector that's not appropriate, it's going to tell you that.

Now, there's some downsides and the first one is key. Everyone pay attention. This is only for supported classes. Let me say that again. Only for supported classes. So what are those classes? UIColor and NSColor, UIFont and NSFont, UIImage and NSImage, and UIBezierPath and NSBezierPath. If you have a class that is not in this set of four pairs and you want to use the strategy, please don't.

You will have undefined results. So-- and the other thing to keep in mind is that even for these classes, it's got limited API coverage. So just because we're doing this #define it doesn't mean that we magically get CMYK on UIColor. We don't. It doesn't happen that way. So-- but the compiler will warn you if you try to use it so, that's good. It will say, "Hey, you-- this is an error." So, anyway.

The other thing to keep in mind is that, if you're doing cross-platform work which you obviously are because you're in this talk and that's what this is about, and you're doing archiving of your things, it's going to require some custom archiving. because if you archive, what ultimately ends up being a UIColor and you try to bring that into OS X using iCloud, that is going to say, "I don't know UIColor is," and it's going to barf on you. So, you're going to have to write some custom archiving code for that.

And that's pretty easy. What you just want to do is you want to save it in the way that both platforms can recognize. So, migration testing is my next slide. And one thing to keep in mind is all of the stuff means that if you're code compiles, it doesn't mean-- necessarily mean it's correct. So please test.

Unit tests are good, very, very good. You should use them. Xcode has some cool things in it, Xcode 5 for doing that. Manual testing is important too because there are some things that you probably can't cover in a unit test. Don't forget to send it to your users. They have different system configurations and they're going to use the software differently than you. So, do beta testing. That's why there's reason why we have the provisioning profile so you can send out your apps to those people.

And testing plans, you know, if you have a testing plan, then it means that every single time that you come out with a release and you follow that plan, it's going to mean that your software is a lot more-- well, at least it's tested, right? Now, I stress this because the number one reason why apps get rejected from the app store at least initially is because they crash during the review process. So you don't want your app to be one of those because it's going to take more time to get it reviewed.

And that's actually good news because if it crashes for the reviewers then it's not going to be crashing for your users. That would even be worse if it didn't-- so do your testing. Anyway, I'm going to bring Dan back on stage and he's going to show you how we've implemented some of these strategies to bring the iOS app to OS X. Thanks Dan. [applause]

Thank you, Cortis. I've been hard at work while Cortis has been talking and now I have a near final copy of my application. So here we are, this is an untitled document and you see instead of the toolbar at the bottom, I have a toolbar on the top that has selectors for the different shapes and the Stroke and Fill colors. So-- but the same things applies. I click, I can create things. I can even create a new document and I can even-- I can use that to make the same shape that I did before. I can drag it.

All right, two documents here. And I can change my Fill color. Let's do lemon, or a nice purple, it could be different planet. OK. So then here we have [laughter] roughly the same document here. And I can give this a name, see, "My House," saved on the desktop.

So let's say-- OK and I saved it. I have made some other changes by mistake. Let's say-- oh, and now I kind of want to see, versions in the past. So I can browse Versions and then this is entirely for free just by adopting NSDocument. And I can go-- oh, this is the one I actually wanted us to save.

Now, this is-- that's how it works. OK. So let's go back and look at the code. OK. So, I've re-organized my code a bit. I have-- I've broken all the common code out into the common source and I have as different spots for iOS and the MacOS source.

So in my common source, we have all the model bits and I was lying a little bit before. We had already done some-- a little bit of work that like of what Cortis was talking about. So here we have our platform color and I can show you, let's see, well, on a shape.

The shape has all these things. It also has a Fill Color and a Stroke Color and it's using this platform color. And again, like what Cortis is talking about, let's see, let's go down. This is about-- this my archiving code. This is when I-- how I init in from the archive. Let's hide this to easier to see. So you can see, I'm using-- when I encode it, I'm actually using a CIColor to archive it to a file because that's something that exist on both platforms.

So that's something I can use to make a consistent archive so I can open the same document on both sides. So if the models are the same, what is the controller level look like? So on the view side, it looks very similar. I've got a Document View that respond-- that corresponds to the canvas. I've got a Shape View that corresponds to each shape and these are both subclasses of NSView.

And then on the controller side, I've got a single document because there's some-- the document can serve as the controller for the whole thing because there are not other screens that could show up. And the document really only has support for-- really only need to do things like it has some undo support. And then it does-- this is the data, same code. So this takes the archiving and then it reads it.

So I can build this and I'm back to my same data and I should mention that I can also do keyboard shortcuts. So if I can do Command-Z, see the Edit Menu Flash and those shapes go away. I can also go back up here, do the redo. This is all again for free just by using NSUndoManager, in my model.

And I can use keyboard equivalence. These are custom things that I set up. I can use keyboard equivalence to change the shape. And these are things that our users are going to expect when they come to your application. So I'm going to hand it back over to Cortis to finish up. Thank you. [applause]

Thanks Dan. That is some amazing work. He's a fast coder isn't he? OK. So, like I said before, there's three things I'd like you to take home today. Number one is I want you to rethink your iOS apps in terms of OS X apps, OK? So there are some changes that you'll need to make there. Number two, restructure your code so that your model is cleanly separated from your view and you're controller. That way, you'll be able to take advantage of the maximum code reuse possible.

And three, just get started. You know, your customers are going to love it that you have an OS X app especially if you integrate your iOS and OS X app experience. So that's going to be great. If you want more information, please take contact Jake Behrens. He's awesome. He will answer your emails maybe. I think he will.

  • He will.
  • He will, he says. OK. Documentation, go to AppKit documentation at developer.apple.com/mac. For the User Interface Guidelines, this is important because this is going to show you how to make a great Mac app. So go to that one. That's developer.apple.com/ue. The Developer Forums, a great place to talk to developers. We've got real developers there. We haven't put Siri to work yet there but real Apple developers.

Some great talks to look at. So we have taken control of Auto Layout in Xcode 5. If you want to know how to do X-- Auto Layout, that's a great one to go to. There are lots of also talks from previous years that you're going to have access to on your WWDC app for Auto Layout. Introduction to SpriteKit, I made a plug for it earlier. That's going to be great if you're doing any kind of cross-platform 2D Game.

Best practices for Cocoa Animation, that's a great place to go to for information on NSStackView for core animation changes and for things about auto layout as well. And we'll give you a few-- things about animation and auto layout. And then Introducing TextKit, and then we haven't talked about that at all in this session but if you've attended some of the earlier sessions, you'll probably be quite pleased. But we didn't really talk about that but the TextKit is actually implemented on the same fundamentals as the OS X Cocoa Text.

So, all of the things that you can do is Cocoa Text or sorry, in TextKit that you've learned about, you can also do in Cocoa Text and your code is going to be the same. So, your NSLayoutManagers and your NSTextStorage, all of that is on OS X and you're code can be largely the same. Thank for coming. Enjoy the rest of your show. [Applause]

[ Silence ]