navigate site menu

Become a member and get unlimited access to every course in the library. Try it free for 7 days

iOS 4 App Development New Features

iOS 4 App Development New Features

with Simon Allardice

 


In iOS 4 App Development New Features, Simon Allardice shows developers how to take their existing iOS SDK development skills and quickly get up to speed working with the new and improved features, frameworks, and tools found in iOS SDK 4 (formerly known as iPhone SDK 4). This course covers creating applications that use multitasking features, working with the built-in calendar, and exploring new ways of working with video. Learn to integrate ads into an application with iAd, and create apps that work successfully across the growing range of iOS devices. Exercise files are included with the course.
Topics include:
  • Multitasking in iOS4
  • Using the Event Kit framework
  • Multithreading with blocks and Grand Central Dispatch
  • Using iAd
  • Playing and recording video from an application
  • Detecting device capabilities
  • Upgrading existing projects

show more

author
Simon Allardice
subject
Developer, Mobile Apps
software
iOS 4
level
Intermediate
duration
2h 42m
released
Sep 01, 2010

Share this course

Ready to join? subscribe


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:04Hi, I am Simon Allardice, and this is iOS 4 App Development New Features.
00:09In the next few hours, we will take your existing iPhone SDK dev skills and
00:13quickly ramp them up to the work with the new and improved features, frameworks, and
00:17tools found in iOS 4.
00:19We will see how to create applications that use the new multitasking features,
00:24delve into the new frameworks to easily work with the built-in calendar and
00:27with motion events, and explore new and better ways of working with images, audio, and video.
00:32We will even cover how to integrate ads into your application with the
00:36iAd framework and create apps that work successfully across the growing
00:41range of iPhone devices.
00:43iOS 4 is a great update just for regular uses of the iPhone,
00:47but for app developers it opens up huge possibilities for creating applications
00:51that just weren't possible on earlier versions of the iPhone OS.
00:55Let's get started building these apps.
00:57Welcome to iOS 4 App Development New Features!
Collapse this transcript
Prerequisites
00:00When developing apps that runs on iOS 4, we are still developing using the iPhone SDK.
00:06That hasn't changed.
00:07The core skills are iPhone SDK development skills, and I expect you to have these.
00:12You know Xcode.
00:13You know Interface Builder.
00:14You're good reading and writing Objective-C.
00:16You are familiar with memory management and delegation and how to interact with
00:20the frameworks necessary for iPhone SDK development.
00:24If you need to first learn these skills or even just brush up on your knowledge,
00:28take a look at our iPhone SDK Essential Training course.
00:31Although it was written on an earlier version of the iPhone SDK, it's still the
00:35same core knowledge: the language, the tools, and the process.
00:39But if you're ready to go, then lets start exploring what's new for developers
00:42when working with this version of the iPhone operating system.
Collapse this transcript
1. Introduction to iOS SDK 4
What's new in iOS 4 for developers?
00:00So what's new in iOS 4 for developers?
00:03Well, to begin with, the name is new.
00:04We talk about iOS 4 instead of iPhone OS.
00:08But if we are developers, that doesn't mean we change to use the iOS SDK,
00:12because at this point, Apple still call our developer tools the iPhone
00:16SDK, not the iOS SDK.
00:18That might change in the future, but right now we'd say that we use that iPhone
00:22SDK 4 to develop apps for iOS 4, and do make sure that you have the latest
00:27version of the iPhone SDK downloaded from developer.apple.com.
00:31Now there is nothing different about installing that SDK.
00:34We still use Xcode and interface builder. And you'll be forgiven for thinking
00:38that if we are developing for iOS 4, using the iPhone SDK 4, that must include Xcode 4.
00:44But no, as of right now, July 2010, the version of iPhone SDK 4 includes Xcode
00:51version 3.2.3, and your version of Xcode needs to be that, or higher.
00:57Now as ever, we deal with a lot of different areas when developing iPhone apps,
01:01there are the tools that we use: Xcode interface builder;
01:04there's the language of Objective-C, and all of the different frameworks for working
01:08with specific areas; wrapping it all up in the infrastructure, the process going
01:13in and the background, how your application runs.
01:15So let's talk about those pieces. First off, the tools.
01:18They haven't really changed.
01:20There are a couple of nice additions in Xcode to make it easier to provision
01:24your testing devices.
01:25We will cover that later.
01:26There's the language. The language hasn't changed either, but there are a couple of
01:31new features that almost feel like a language change.
01:34There is something called blocks.
01:36We can now use a block to create a chunk of reusable code;
01:39it's almost like having a function without having to name it.
01:42Now many, if not most programming languages support this, but they sometimes have
01:46different names for it.
01:47In C#, JavaScript, or PHP, you might hear this block idea as being called an
01:53anonymous function or a lambda.
01:55Smalltalk calls this idea a block, as does Ruby.
01:58And Objective-C takes a lot of influence from Smalltalk,
02:01so we are going to call these blocks.
02:03Now if you have never come across anonymous functions, lambdas, or closures is
02:08another name you'll hear here, don't worry about this.
02:11We will see how to use blocks later in the course.
02:13They are very convenient in situations like error handling, callbacks, and
02:16delegation. They are going to make your life a little easier.
02:20And the idea of frameworks, well, in iOS 4 we have new frameworks and
02:24improved frameworks.
02:25We'll go into several of the new frameworks in this course, the frameworks for
02:29working with calendar events,
02:31a new framework for dealing with motion data instead of having to deal with the
02:34Accelerometer directly,
02:36there is a new framework for dealing with images in video,
02:39there's even a specific framework for delivering banner ads in your application
02:43by connecting to Apple's iAd service.
02:46Improved frameworks include better movie players and AV foundation, and even
02:50some changes to the foundation in UIKit frameworks.
02:53And then those infrastructure: how does this all tie together?
02:57And multitasking. Your applications no longer completely exit when a user hits
03:03the Home button on the iPhone 4.
03:06And of all the changes in iOS 4, this is the big one for developers, and this is
03:11the big feature, even if you don't care about it.
03:14This is the big one because you have to know how to deal with this new feature.
03:18Some of the other stuff you can just ignore.
03:20If you are writing an app that has no video, you can just ignore all the new
03:24cool video player classes, and it would never be a problem.
03:27You could ignore the calendar functionality in iOS 4, or the CoreMotion framework
03:31in iOS 4, and just not use them.
03:34But you can't ignore multitasking.
03:37Any app you build against iOS 4 is a multitasking app.
03:41It's not something you opt into;
03:43it's the default behavior.
03:44Now you might think, "Well, so what?"
03:48What it means is the life cycle methods we are used to don't work the way they
03:52are used to, and that can really trip you up.
03:54As you might imagine, we will go into multitasking quite a bit in this course.
03:58Now along the way from iPhone OS 3.1 to iOS 4.0, we picked up a lot of the
04:04features built into iPhone OS 3.2.
04:07This was the version of the iPhone OS that never ran on the iPhone devices,
04:11but only on the iPad.
04:13It had things like gesture recognizers and custom input views, and now we have those too.
04:18For more in developing on 3.2, see your developing iPad applications course.
04:23As you can see, the developer changes are significant, and we are going to work
04:27with most of them, but here is this thing:
04:30you already know that lot of the new features in iOS 4 are targeted at the end user:
04:34folders, Bluetooth keyboard support, working with playlists, that kind of thing;
04:39do make sure you're familiar with those, also.
04:41It's really easy for developers to become so focused on their own app and their
04:45own favorite features,
04:46they almost forget how a typical user interacts with this device.
04:50You need to make sure you're an expert user of this device, not just an
04:53expert developer on it.
Collapse this transcript
What's new in the development tools?
00:00With all the new features in the iOS 4 operating system and the new iPhone 4
00:05device itself, you might think that there would be significant changes to
00:09the developer tools.
00:09But no, there aren't - or at least not yet.
00:12On the initial release, version 4 of the SDK, comes with version 3.2.3 of Xcode.
00:19But Xcode 4 is coming, and Xcode 4 will be a major, major change to the developer toolset.
00:26But as of right now, July 2010, I'm still on Xcode 3.2.3, which really does not
00:31have a lot of new stuff in it when compared to Xcode 3.2.
00:35One nice addition, however, is the changes to the Organizer window.
00:40It's now a lot friendlier and if you plug in a new device, you will be able to
00:44choose to use that device for development straight from Xcode, without having to
00:48spend a lot of time in the provisioning portal web site.
00:51It's something celled Automatic Device Provisioning, and in fact, you will see a
00:57check box for it in the Provisioning Profiles part of your organizer window.
01:01In fact, if you hit Refresh, what it's going to ask you to do is give your
01:05credentials for the iPhone Dev Center, the way you normally log on to the web
01:09site and fetch any necessary information from the web site.
01:14Now we still do have to spend some time in provisioning.
01:17It's still a somewhat unpleasant part of iPhone development, so any help there is welcome.
01:23Other than that, there are some additions to instruments that support multitasking
01:27features, and there is a new instrument called Automation, which helps you create
01:32automated task on the iPhone by using JavaScript.
01:35But the general developer toolset hasn't changed very much.
01:38We are really all waiting on Xcode 4, and you will hear much more about that at
01:42lynda.com when that arrives.
01:44But now we can go ahead and create iOS 4 applications using Xcode without having
01:50to learn any major new section of XCode or instruments or interface builder.
Collapse this transcript
Understanding the device improvements
00:00Sure, most of the iPhone devices out there in the world can run iOS 4, and they
00:06don't all run it the same way.
00:08But before we talk about the differences between the devices, let's set the bar
00:12first with the classic iOS 4 device, the iPhone 4, released in June 2010.
00:18Sure, there are a lot of great things about this device, but as developers, we
00:22have a different interest than just the typical selling points.
00:25Sure the width is great and the glass is terrific, but we're interested in
00:29things that can or will affect our functionality.
00:33First off is the Retina display, the better display than 960 x 640 pixel display?
00:40Previous iPhones are of course 480 x 310.
00:44Now this can have an impact on the graphics in your application, but as we'll
00:47see, for typical apps you can kind of forget about the resolution details and
00:52have it just work, on either the iPhone 4 or an earlier device.
00:56You certainly don't need to worry about the resolution difference like you do
01:00when going from the iPhone to the iPad.
01:03Now, there's the camera situation.
01:05We have the new five megapixel still camera with LED flash on the rear, which is
01:10even capable of taking HD video in 720p,
01:13and the new front facing camera used for the FaceTime video calls or self portraits.
01:19Now, a lot of people assume that these are cameras that are just duplicates of
01:23each other, but they are very different.
01:25The front facing camera is optimized for the FaceTime video calls and has
01:29much lower resolution.
01:31Photos taken with this camera are only VGA, 640X480 pixels.
01:37So you have a five-megapixel camera on the rear and a 0.3-megapixel camera on
01:43the front, certainly something to be aware of if you're planning to integrate
01:46photos and/or video taking in your application.
01:49But what else? What can't we see?
01:52Well, there's the processor.
01:54The iPhone 4 has a faster A4 processor, same as in the iPad.
01:58There's memory. Regardless of whether you have an iPhone 4 with 16 gig or 32 gig
02:03of storage, this has 512 megabytes of RAM, twice as much as the iPhone 3GS and
02:09even the iPad, four times as much as the iPhone 3G.
02:13Now this is great for this device.
02:16But the impact is deceptive if you favor testing only here, as having more
02:21memory and a faster processor is forgiving to the developer in a way that's not
02:25always useful, because your apps may run very nicely on this device and
02:30terribly on earlier devices, so more than ever, test critically on older
02:34devices you plan to ship on.
02:36Now you can, of course, write an app that only runs on the iPhone 4.
02:41Apple, for example, released the iMovie app that only works on this device, as
02:45it's too demanding to run on earlier devices.
02:48But Apple is intentionally pushing the envelope there to showcase new
02:52features on the phone. So what else?
02:55Well, we have a gyroscope now built into this device, along with the
02:58accelerometers that we've always had, and the compass that's been there
03:02since the iPhone 3GS.
03:04The end result is more accurate and more usable motion data.
03:07Now as developers, we even have a new framework to make it easier to measure and
03:12to react to motion within our apps.
03:14So those are the main device improvements to be aware of as a developer.
03:18And it's going to be your choice of whether to require them, to cater to them, or
03:22even to ignore them.
03:23Now certainly you need to be aware of the differences in the way iOS 4 is
03:28implemented on different devices.
03:30We're going to cover that next.
Collapse this transcript
Exploring iOS 4 support across the different Apple devices
00:00In the past three years, there have been eight different iPhone devices, not
00:04even counting the different memory sizes.
00:06The current device line up, as of July 2010: we have the original iPhone, the
00:11iPhone 3G and the iPhone 3GS, three generations of iPod touch, the iPad and the iPhone 4.
00:18When we take about iOS 4 Support, well, let's take care of the easy ones first.
00:23The original iPhone, released in 2007, is not supported at all by iOS 4.
00:28On the other end, we have of course, the iPhone 4.
00:31That's given, it fully supports iOS 4.
00:34The iPhone 3GS released in 2009 can be upgraded to iOS 4 with full support,
00:41including multitasking.
00:43Obviously, there are some hardware differences and the processor and memory are
00:46less, but we get all the features.
00:49Next, here's the challenging one.
00:51The iPhone 3G from 2008, you can install iOS 4 on this and get most of the iOS 4
00:57features, but it doesn't support multitasking.
01:00There isn't enough memory on the iPhone 3G to support having multiple apps in the background.
01:06So even after upgrading to iOS 4, when you hit the Home button on an iOS app
01:11running on a 3G, it will fully exit the way it always has on iPhone OS 3.1 and earlier.
01:17It also doesn't support custom wallpaper on the Home screen.
01:21Now the iPod touches - well, this becomes tough because there's three
01:24generations, but it's made easier because they all correspond to a different
01:28version of the iPhone.
01:30The first iPod touch cannot be upgraded to iOS 4.
01:34The second generation, late 2008 iPod touch, can be upgraded to iOS 4, but
01:40because of hardware limitations, does not support multitasking, custom wallpaper
01:44or being connected to a Bluetooth keyboard.
01:47It's very much like the iPhone 3G.
01:49The third generation, 32 and 64 Gig iPod touch from late 2009 and onwards does
01:56support iOS 4 fully, including multitasking;
01:59it's like the iPhone 3GS.
02:01And here's the surprise for a lot of people, the iPad.
02:05It does not run iOS 4, at least not yet, not in summer 2010.
02:09iPad Support is still several months away.
02:12The assumption is that it will be fully supported, but right now it cannot be upgraded.
02:17So here's the summary.
02:19The original iPhone and the first gen iPod touch, no support for iOS 4 and none expected.
02:25The iPad, support is expected later in 2010.
02:29The iPhone 3G and the second gen iPod touch, this supports iOS 4, but with
02:35multitasking and custom wallpaper removed for performance reasons.
02:39The iPhones 3GS and the iPod touch 3rd gen, full support, but slower devices than the iPhone 4.
02:45Now of course, even when devices can be upgraded, there will remain many devices
02:50that will be operating on the old OS, with people either choosing not to
02:54upgrade or just not connecting their device to iTunes and never being prompted.
02:59But as you can see, if you're building apps that push the new features, you'll
03:03need to consider the spread of support.
03:05Bear in mind, you can specify that only certain devices are supported when
03:09publishing to the App Store and write code inside your app to detect the
03:13existence of the camera or video support.
03:16That kind of code is becoming more important than ever.
Collapse this transcript
2. Multitasking in iOS 4
Understanding multitasking concepts
00:00So with multitasking, your applications no longer completely exit when the user
00:05hits the Home button on the iPhone.
00:08I've said that this is the key feature for developers in iOS, 4 simply because
00:12you must deal with it in one way another.
00:14You don't opt into multitasking;
00:16it's the default behavior in iOS 4.
00:19If you build your project to run against iOS 4,
00:22it is assumed it supports multitasking.
00:24But let's cover a couple of key concepts here.
00:28First, what Apple means by multitasking may not be what you mean by multitasking.
00:33It certainly does not mean that your app just runs all the time.
00:38That would be a far too uncontrolled state of affairs for Apple to allow.
00:43There is a very short list of what your app is allowed to do in the background.
00:48Really, the first change for developer is not how your application starts;
00:52it's in how it exists, or rather that is doesn't.
00:56In iPhones 3.1, you open up an application by tapping the icon.
01:02Your user uses the application, they press the Home button, and your app exists.
01:08In that exit process, the OS will call, applicationWillTerminate method in your
01:12app delegate, and you'll have your save state, or your cleanup code there.
01:17But you have to be quick about it because you have about five seconds to exit
01:21before iPhone OS decides you're taking too long and just dumps your process.
01:25In iOS 4, however, your application is launched the same way,
01:30your user uses it, the user then presses the Home button, and your application
01:35does not completely exit when the user goes back to the Home screen, but it
01:40moves to a background state and applicationWillTerminate is not called.
01:45Your app has disappeared from the iPhone screen, and it has entered that
01:49background state, more of a suspended state than an actively running one.
01:53If the user taps your Apple icon to run it again, your app moves in the
01:57background state to the foreground state.
01:59They can also double-click the Home button to get a list of the applications
02:04that are in the background.
02:05Re-launch it that way, and this cycle continues.
02:09And this is the key difference that we don't just have Application Lifecycle
02:13events for starting the app and ending the app, but also for moving to the
02:18background and moving to the foreground, and those methods are
02:21applicationDidEnterBackground and applicationWillEnterForeground, and these
02:26could be called many times between the first applicationDidFinishLaunching
02:31and your applicationWillTerminate.
02:34However, your app can still be requiring to exit all the way out, either because
02:40iOS 4 itself decides it needs the memory, or the user can also exit your
02:45application by double-clicking the Home button to see the list of apps, then
02:49holding down and tapping the Minus button.
02:52So the old applicationWillTerminate is still an essential method.
02:56And of course, if you're running on iPhone 3G that doesn't support
02:59multitasking in iOS 4,
03:01it's just like running on iPhone OS 3.1;
03:04your app will just call applicationWillTerminate and exit.
03:08But if you've transitioned to the background, okay, what is your application
03:14doing in the background?
03:15Well, by default, nothing.
03:18Oh sure, your app is taking up a little bit of memory, but next to no processing cycles.
03:23So if you had started a long running calculation or a long running network
03:27operation, those are not just going on in the background.
03:31That's not what happens.
03:33If your app needs to perform an operation while it's suspended in the
03:37background, you must write code to ask permission to do that.
03:42And there are five things your app can do in the background: three very specific
03:47things and two generic ones.
03:50Specifically, your app can: one, play audio -
03:53you have a background application playing audio, say over a network string;
03:57two, react to location changes, for say, creating a navigation app with prompts:
04:03three, you can keep a voiceover IP connection alive to make calls over your
04:07Internet connection.
04:08Now, these three things require you to create a key in your info.plist file that
04:14says, "Yes, I play background audio," or "Yes, I respond to location changes."
04:19And without those entries, nothing will happen in the background.
04:23But here's the deal.
04:23What if you look at that and think, well, I don't want to do one of these things;
04:28I want to do something else.
04:29What if you want to run a long running operation, a complex calculation
04:33or rendering a file?
04:35Well, unfortunately, you can't just continue to run whatever you want in the background.
04:40But when your app is shifting to a background state, you can request time to
04:45finish a long running operation.
04:47Requesting time does not mean you get free rein on the processor.
04:52The time you're going to get depends on what device you have, what else is going
04:56on, because the OS can throttle your process back or even terminate it.
05:01Even when you're running a task in the background, there's a property called
05:05backgroundTimeRemaining that you can query to see how impatient the OS is
05:09becoming with you and how many seconds you have left to run.
05:12And finally, number five;
05:14you can create what are called local notifications.
05:17These are effectively like having alerts from your app while it's running in the background.
05:22Those can be pushed to the user at a specific time, so your app could be
05:26suspended in the background and still be sending messages to the user.
05:30These are the things you can do.
05:33But the list of what you can't or shouldn't do is, of course, much larger.
05:38However, some of the main ones are: Don't so any graphical operations,
05:43particularly not OpenGL calls.
05:46If you try and execute code that draws on the screen when your application is
05:50suspended in the background, the iOS 4 will terminate your app instantly.
05:55Don't do significant network operations.
05:58Aside from allowing voiceover IP in specific circumstance, the OS does not want
06:02you to be making network calls, so doing large downloads in the background is
06:07unfortunately not feasible.
06:09You also want to save your state when moving to the background,
06:12just as a best practice. Again, the OS could be dumping your app.
06:16If you have large objects taking up large amounts of memory, release them.
06:21All of these are very common things we'll have to deal with;
06:23there are a few more guidelines that we'll explore as we go forward.
06:27But the answer to, 'what should my app do in the background' is always as much
06:32as necessary, as little as possible, and spend more time making sure your app
06:38can go from a background to the foreground and become active and responsive,
06:42quickly and efficiently.
06:44Let's take some of these concepts and see how to implement them.
Collapse this transcript
Responding to activation events
00:00The easiest way to understand the code you need to support multitasking is
00:04simply to see what Apple now gives you in a standard Xcode project.
00:09So if I create a new view-based Application for the iPhone, I'll call this
00:14one SimpleMultitasking,
00:19expand this, and then in my Class's folder, I'm simply going to select the
00:23implementation file for the AppDelegate.
00:25Get myself a bit more space here.
00:28If I start coming down to see the methods that have already been provided, we
00:32have the standard didFinishLaunchingWithOptions, where a lot of the work is done
00:37to set our initial application up.
00:39Then below, we have applicationWillResignActive as a placeholder with nothing in it.
00:45We have applicationDidEnterBackground, applicationWillEnterForeground,
00:49applicationDidBecomeActive, and applicationWillTerminate.
00:54Of course, applicationWillTerminate is the very common method that we put in all
01:00our safe state code in a typical iPhone SDK 3.0 application.
01:05But between ending applicationWillTerminate and the beginning
01:09applicationWillTerminate, we have these other four.
01:12Let me just shrink this down so we can see them all at the same time.
01:18Now the applicationWillResignActive and applicationDidBecomeActive are not new.
01:23You may or may not have used them, but they've been there since you could first
01:26code for the iPhone.
01:27Your application becoming inactive is what happens when you, say, get a phone
01:32call or an SMS message while your app is running.
01:35So if you're in a game, it gives you a chance to pause.
01:38But the two that we're interested in are applicationDidEnterBackground and
01:43applicationWillEnterForeground.
01:46But of course, we want to understand these more in the general flow of the application.
01:51What's the best way to do this?
01:52Well, let's add some NSLog messages, because it might not work exactly the way
01:57you're expecting it to, if you're looking at this right now.
02:00So I'm going to quickly add a few NSLog messages to these methods, just with the
02:05name of the method in them.
02:08So after adding a simple NSLog to every one, I'm going to Build and Run this.
02:14It's going to open up the Simulator.
02:16I've got it at 50% right now.
02:18It really doesn't matter, because there is no application here.
02:20I'm going to open up the console, so we can see the message that appears.
02:25So I can see that, immediately, I've had the didFinishLaunchingWithOptions and the
02:30applicationDidBecomeActive.
02:32They've both been called.
02:34Now one thing to notice: if I just go back to my code here and just collapse
02:38some of these methods, so we can see them all together,
02:41here is while I had didFinishLaunchingWithOptions and
02:46applicationDidBecomeActive, I did not have the applicationWillEnterForeground.
02:51That's not called the first time the application loads.
02:55So what can I do next?
02:56Well, really, the deal is that I need to exit this application.
03:00So I'm going to click the Home button on the iPhone Simulator.
03:04We see over here on the console that we had applicationWillResignActive and
03:09applicationDidEnterBackground.
03:12So what happens if I try and launch the application again?
03:14Well, I can go to the regular screen on the iPhone, and click it.
03:18We get applicationWillEnterForeground, applicationDidBecomeActive.
03:22Going back and doing that multiple times, we're cycling between
03:27applicationWillResignActive, applicationDidEnterBackground, when it goes into the
03:33suspended state, then WillEnterForeground, and DidBecomeActive.
03:37We can just continue going.
03:39This is regardless of if I'm using the icon on the actual screen itself or if
03:44I double-click the Home button to launch it from the list of the currently
03:49running applications.
03:50That's applicationWillEnterForeground, applicationDidBecomeActive.
03:51Now the last thing that I could do is, after exiting this and going from the
04:00background to a suspended state, I could double-click the Home button, click and
04:05hold on the application name, and click the red Minus button to quit it all the way out.
04:10Now notice that if I fully exit the application, it does not seem to call
04:16applicationWillTerminate.
04:19So back in the code, if I look at this, we've gone through all of the
04:22others multiple times, and I'm switching between the DidEnterBackground and
04:26applicationWillEnterForeground, and the associated DidBecomeActive and WillResignActive.
04:32But what's an important thing to understand when you're running this kind of
04:35application is, what really is the difference between a background state and a suspended state?
04:41Now up to this point, I've talked about your application being in a background,
04:45or suspended state, as if they are the same thing.
04:47Well, in fact, as far as Apple is concerned, there is a very specific difference
04:51between an app being in the background and an app being in a suspended state. The deal is this:
04:58when your application is running, here we have gray screen application and the
05:02user presses the Home button, the application moves to the background, and
05:06applicationDidEnterBackground is called, and it's here.
05:10You could actually perform some background operations.
05:13You could play audio, do a voiceover IP, request some time to perform a long operation.
05:19But if you're not doing any of those things, and we're not in this example, your
05:24application moves from the background instantly to the suspended state.
05:28Okay, so what's the difference?
05:30Well, when your application is in that background suspended state, it can re-launch,
05:35we can go back to the Home screen,
05:37we can launch another application,
05:39but if you fully terminate the application, even specifically by going to the
05:44red Minus button, applicationWillTerminate will not be called because the
05:49application is suspended.
05:51It will simply be purged from memory.
05:53However, if your application was actually performing some behavior in the
05:57background, such as playing audio, doing voiceover IP, then it will be
06:02considered as being in a background state, not a suspended state, and
06:06applicationWillTerminate would actually be called.
06:09Now for some people, this can be an issue because it might seem almost random.
06:13Well, when is applicationWillTerminate called? It seems sometimes like it's
06:17called and sometimes like it's not.
06:18It's really, really very specific.
06:20Is your application actually doing anything in the background?
06:24That's going to specify whether applicationWillTerminate will be called.
06:27Now one last thing to be aware of:
06:30this applicationWillTerminate method is still very important, because if
06:34you're running on a device that doesn't support multitasking - the iPhone 3G, for example-
06:39when you exit, it won't go to the applicationDidEnterBackground.
06:42That's not supported.
06:44It will immediately call applicationWillTerminate.
06:47That does mean it often is not out of place to have the same save behavior being
06:52performed from both applicationWillTerminate and applicationDidEnterBackground.
06:58So certainly make sure to test your app behavior on all levels of device.
Collapse this transcript
Requesting time to finish operations
00:00Probably the most complex thing you can do with multitasking on the iPhone is
00:04just to generically request time to finish a long running operation when your
00:09application is suspended.
00:11And it's not that requesting time is so complex;
00:14it's really all to do with the idea that you don't know how much time you are
00:17going to have, and the iPhone OS itself doesn't know how much time it's going to give you.
00:22But let's go through this.
00:23I'm going to create a new project called RequestCompletionTime, and save that.
00:29Now the question is, when do I start a long running operation?
00:34Well, there are really two answers to this.
00:36I could be running the application and continually requesting operations to
00:41happen that might themselves need to continue while the application is
00:46suspended, or I could do it when the app moves into the background.
00:50For our purposes here, I'm going to choose the latter, which means that in my
00:54AppDelegate, I'm going to put some code into the applicationDidEnterBackground.
00:58That means when the application is moved to the background, now we are going to
01:04request some time and start off a long running background process.
01:10Long running is bit of a hand-wavy term there.
01:14How much time do you have? Well, I don't really know.
01:17I'll show you how you can find out, but certainly it would be a good guess to
01:21say imagine that you have less than ten minutes.
01:25So this is certainly not a place that you are going to attempt to download two
01:28gigabytes over a 3G connection, for example.
01:31Now before I start creating a background task, I'm going to just declare a
01:36variable up here, just at the top, called the UIBackgroundTaskIdentifier, and I'm
01:44going to call it backgroundTask,
01:45just so it's available all over place if I should need it.
01:51Then in applicationDidEnterBackground, I'm going to tell the operating system I'm
01:56about to begin a background task that may need some time to finish.
02:01The way that I do it is by calling the beginBackgroundTaskWithExpirationHandler,
02:05which is a method of the UI application.
02:08Now I'm just going to complete this first block here because it's likely to
02:13look a little strange, particularly if you haven't used blocks.
02:17Let me open this up to show a bit.
02:20What is happening is the argument that is actually being passed into this method,
02:27last from the opening carrot up at this top right section here, down to the
02:33closing square brace,
02:34what we are really doing is constructing a block of code that we are passing
02:39into this method saying, "This is what I want to have happened if the task is
02:44about to run out of time."
02:45This is what our expiration handler is.
02:48This code will actually not be executed when the code is reached by the
02:52compiler, even the program.
02:54It's really telling the program, hey, for future reference if you ever need to
02:58call the expiration handler, this is what happens.
03:01Now we are going to be talking explicitly about blocks a little bit later on in the course.
03:06Count this is a little bit of exposure to see them.
03:08Whenever you this carrot symbol, you are looking at the new block feature in Objective-C.
03:13Now the thing is here I'm going to quite a bit of work for code that I hope
03:19never, ever, ever gets executed, because this is my expiration handler.
03:24What it actually means is the OS has said, "I realize you have asked for some
03:27more time, but you are about to run out of time.
03:30So I'm going to give you one chance to tidy up anything you are doing and if you
03:35don't, I'm going to terminate your application."
03:38The thing is any task that we decide that we want to execute as a background
03:43task must have a matching end background task call.
03:48If it doesn't, the OS is very likely to terminate the application.
03:52But we are really not doing anything here.
03:54This is just us saying "In the worst case scenario, this is some cleanup code."
03:59So continuing on from this, what I'm going to add then next is to actually start
04:03the long running task itself.
04:05I'm doing this by calling dispatch_async.
04:07And I'll talk about dispatch_ async in just a second here.
04:12This is going to be my long running code. Rather than have network calls or
04:16calculations and essentially going to emulate something that takes, in this case 15 seconds,
04:21now what I'm going to do is to sleep for five seconds and do a few NSLog messages.
04:27One of the interesting things is that during this long running background task I
04:31can keep asking what's my backgroundTimeRemaining,
04:35if I am a little paranoid about having plenty of time available, now we are
04:39going to be NSLoging this during this process while it's going on.
04:45Then if I am done with all my background process, I could actually call
04:50application endBackgroundTask and say, great I'm done. I'm finished.
04:54I don't need to do any more.
04:56Fortunately, if we want to go by best practice, I wouldn't really just do
05:00this here, that line.
05:01So I'm going to delete that.
05:03What I'm more likely to do is kind of emulate this process up here, and that's
05:08because I want to make sure that the background task is getting marked off as
05:12invalid, and there is no kind of butting of heads that, say accidentally the
05:17expiration handler had not kicked off just as I was about to kick off my proper
05:21ending of the background task.
05:23The way that I am going to do this is by doing another little code here, another
05:28dispatch_async, and duplicating the code that I had a little bit earlier.
05:34Again, I have to make doubly sure that I am always going to call
05:37endBackgroundTask for anything that I am trying to do in the background;
05:40otherwise, my application is going to get terminated.
05:45Now what is this dispatch_async?
05:47Well, this is a new feature of iOS 4.
05:51This is part of what's called Grand Central Dispatch.
05:55This is something that, even though it doesn't look like it right now, will
05:58actually make the process of doing multithreaded code very, very easy indeed.
06:03What I am actually having to write here is some of the more complex code you
06:07will ever have to do involving Grand Central Dispatch.
06:10Now as you are looking at this and thinking, good lord, this is an awful lot of
06:14stuff to do some very basic, basic behavior.
06:18I agree, completely, with you.
06:21Do bear in mind that if you need to do this a lot, most of what you will be able
06:25to do is kind of boilerplate a lot of this code, just changing the important
06:30stuff for your own needs, making sure that the work you are doing is actually
06:34happening correctly.
06:35And just making sure that should you ever need to use your expiration handler,
06:39because you didn't get enough time to finish, that you are tiding up whatever
06:43things needs to be done.
06:44But at the moment, if you are looking at this and some of these carrot symbols
06:48are looking a bit weird, and this all dispatch_async is looking a little odd,
06:52just count this as kind of forward exposure.
06:54We are going to get both into blocks and Grand Central Dispatch a little
06:58later in the course.
07:00So what I'm going to do now is at the end of this I'm actually going to just
07:04do an NSLog message.
07:05Reached the end of ApplicationDidEnterBackground. I'm done.
07:10Why am I doing this one?
07:11Well, because what I want to prove to you is what's actually going to happen
07:15when this code is executed.
07:17We should be able to hit the Home button after the application is running, and
07:21we are going to jump into applicationDidEnterBackground.
07:24We are going to run immediately through all this code to set up the expiration handler.
07:29We are going to run through this code to start kicking off our work on another
07:35thread in the background, and I should immediately get this message going out,
07:39and our application move into the background.
07:41Then what should be happening is I should get this background work going off and
07:48having my NSLog messages kick out every five seconds or so for 15 seconds.
07:53So let's see if that is indeed what is going to happen.
07:57I'm going to switch to my simulator here, save and build this application, and
08:02click build and run.
08:05Now the application itself doesn't do anything.
08:07While it's running, I do not have any user interface elements.
08:10I am going to open up my console here, just to have it open when I exit the application.
08:18There we go! I can see I got to the end of ApplicationDidEnterBackground.
08:22Within a couple of seconds, I want to see a message here.
08:25Time remaining is 594 seconds.
08:27Then it's down to 589 seconds, and it should be about 584 seconds,
08:33at which point we are done with our long running operation, and silently our
08:38application will now be moving from the background state to the suspended state,
08:43and this is exactly what I would expect to see here.
08:46So I can see that in the simulator what happening here is I am getting about 600
08:51seconds, which are about 10 minutes or very close to that.
08:55That is what happens in the simulator, and if you run it in the device, you will
08:59often find about 10 minutes on average, too.
09:01That can be affected by what other applications are running on your machine,
09:06how much memory you have got, how many applications have been opened at the same time.
09:10So it's not something you can count on being 10 minutes.
09:14That may change down, or even up when new devices come along.
09:18But this is the process that you need to use if you want to request generic time
09:24in multitasking to finish off some long running task for your own applications.
09:29Again, if you are new to the blocks and new to this dispatch_async, we'll be
09:34covering that a little later.
09:35It's a good example of some of the more interesting things that you can
09:40do with iOS 4, will actually require you to have some knowledge of both blocks
09:44and GDC.
Collapse this transcript
Using local notifications
00:00What I am about to talk about is not officially part of multitasking, though it
00:04is new in iOS 4.0, something called LocalNotifications, and they can feel a little
00:10bit like multitasking, because it is the idea of sending messages to the user
00:15even when your application isn't officially running.
00:18It's quite similar to the available Push Notifications that you might get from
00:23say applications like Facebook.
00:25They are going to pop up messages even when application is not running.
00:28Let's go ahead and see how they are done.
00:30I have a very simple view-based application, where the one button on, my classic
00:35one-button App, and right now it's hooked up to a scheduleNotification method
00:40here called IBAction, and it doesn't actually have anything in it.
00:44These are actually very simple to create, but they have a couple of impacts that
00:49are worth knowing about.
00:50So I am going to actually allocate a new local notification:
00:54it's UILocalNotification.
00:55You don't need any special frameworks or import statements to make this work.
01:00And then I am going to set some information about it, which is basically when do
01:04we want to this to fire?
01:05We can set it for pretty much anytime in the future, though there is not much
01:08point for setting it for years in the future, as the iPhone OS will only keep
01:13track of about 64 of these before it starts dumping them.
01:17So I am going to do something very simple that says, this notification is going
01:21to fire off - meaning it's the fire date - will be 15 seconds from whenever this
01:27code is called, just so we can see the impact of it, but you could schedule this
01:31for the equivalent of an alarm call for some date in the future.
01:35You can also put recurrences on it to that kind of thing.
01:38I am then going to set some details about it, that it's going to pop up a
01:42message saying, "Missing you already!" that it will open up a button that allows
01:47you to open or view something, which really is taking us to open the application,
01:52so I am going to live that at View, and then what I am going to do is set the
01:56badge on the application icon.
01:58What this mean is the little circular red icon that will say, one, or two
02:02or three, if you have a number of events that you meant to review, always
02:07like looking at mail, when your mail says if you got four or five or six mails to read.
02:11I am just going to say one, because I am not imagining that this application
02:16will have any other options than one, and then I am going to gather together any
02:21custom data that I needed to save with the notification, and I just do this by
02:25creating an NSDictionary, full of whatever values I want to have in it. In this
02:30case, I will have some value of ABCD1234 for a key called yourKey, and this is
02:36just the idea of packaging together some custom information that you might want
02:40to save for this notification, if that's important to you. This is optional.
02:44You don't have to do it.
02:45And then I am going to go ahead and schedule the notification.
02:48This is all we need to do.
02:49It's a call to UIApplication that says scheduleNotification and pass in that
02:55object. Then I can actually go ahead and release it.
02:59So I am going to save this, and I am going to build this.
03:02Build has succeeded, and let's take a little look at this.
03:05I am going to click Build and Run, and this does work in the simulator, so I am
03:08just going to open this up, 100% here.
03:11I will click the button to schedule a notification.
03:13It shouldn't matter now if my application is running or if it's not running.
03:17It could be fully active, it could be in the background, or it could
03:21be completely closed.
03:23What will happen is when that notification hits, will pop up the
03:28LocalNotification message, the top of the message, the headline is the name of
03:32the application and we get our choice to View, which means open the application,
03:37or just Close the message and dismiss it.
03:40You will also notice that the badge has been applied to our icon in the
03:44background here on springboard.
03:46So I could click Close.
03:47I could click View.
03:48One of the issues here, if I click View, we are going back to the application.
03:52It's just restoring from the background, and I go back here.
03:56We have still got that badge because there is nothing automatically that's
03:59actually going to take it off.
04:00So I do need to do a little bit more work to actually deal with this, because
04:04there is really a couple of things I want to take care of.
04:07One is making that badge go away when we reenter the application.
04:12But the issue with that is, well sometimes we might be opening the
04:16application from scratch, where it's already completely terminated and
04:20completely closed - maybe they restarted the phone - and sometimes it's just
04:25restoring from the background.
04:27So there is a couple of different ways of dealing with that.
04:29Let's go ahead and see that.
04:31I am going to jump over into my applications AppDelegate, and what I am going to
04:38find here is my application DidFinishLaunchingWithOptions. This is the classic
04:43DidFinishLaunchingWithOptions method. This will be called when the application
04:48first launches from being totally closed,
04:51not running in the background - completely closed on the device.
04:54Now what I am going to do, just before we have the return YES statement, is I am
04:59going to add a little line of code here that actually says reset the badge, so
05:03if we open up from scratch, it sets it back to 0, and if it was 0 already, no big
05:08deal. Then what we are going to do is ask a little question, try to find out,
05:12did we launch because of that notification?
05:16Now we can tell this by examining our launchOptions. Of course, this is the
05:21applicationDidLaunchWithOptions, and I am looking here to see, did I have a
05:25LocalNotificationKey.
05:28I will try and get that object, and if that object is not nil, then I can say
05:33okay, I am going to create an Alert view that comes out with the message that
05:37says, you came back, the app was obviously closed.
05:40message is "Nice to see you again!"
05:42and just cancelButtonTitle, nothing special there.
05:45Show the alert and then release it.
05:47But this code can prove to us that we will accept any custom information about
05:51that local notification if our app was completely closed. And what this should
05:56alert you to is that the local notification part is not really multitasking.
06:01It's not our app that's doing it.
06:03If our application is completely closed, there is nothing really in the
06:07background to be able to pop up that Alert view, and indeed it isn't
06:11really multitasking.
06:12What happens is when you schedule this local notification, you are telling the
06:17iOS operating system to handle, and it's keeping its own little database of
06:21those notifications.
06:23However, the issue is this code will not be called where in the application did
06:28finish launching with options, and this wouldn't be called if we were just
06:31restoring from the background, if we just had been suspended.
06:36So what I also need to do is add another block of code here, a different method.
06:42In this case, it's going to be the application:
06:44didReceiveLocalNotification, passing in a LocalNotification.
06:49I am going to reset the badge number back to 0 again.
06:53I am going to do something very similar if the object exists. In this case, I am
06:59actually going to see, was there any customInfo from the dictionary.
07:02If you remember in my View Controller, I created just an NSDictionary and gave
07:06it some dummy data in there, and then this time I am going to actually pull that
07:10data out to prove that we can get to it.
07:13I am going to then construct an Alert view that actually gives another message
07:16that says the app was running when this alert view popped up.
07:20I'll pop out that message of the custom information that I retrieved and then
07:24just a Cancel button title of OK, nothing special here.
07:29Show the alert and release it and close that.
07:32Save and build this application, build has succeeded, and I am going to go
07:35ahead and Build and Run.
07:40So it opens up in the Simulator.
07:41I am going to press button to schedule a notification.
07:44I am going to exit the application.
07:46Not only that, I am going to double- click to go to the multitasking interface
07:51and select the Minus button to make it completely go away.
07:54So our application is totally closed at this point.
07:57Right now, I wouldn't expect to see a badge number until now.
08:01Our LocalNotification pops up, our badge number is increased and is now number 1 in
08:06the back, and if I click this View button, I should see the message saying that
08:10the application was closed.
08:12Welcome back, but the application was closed.
08:15So we open up, You came back!
08:17(App was closed) nice to see you again.
08:19Okay, let's schedule another notification, and this time, I am just going to go
08:24back to springboard and give it a few seconds.
08:26It wouldn't really matter if my application was fully active or if it was just
08:31in the background here; the same behavior would happen.
08:34In this case, we get the badge increased, we get the LocalNotification, but when
08:38I click View, this time around it should say the application
08:41was running and should pull any custom data out of that dictionary object, in
08:46this case ABCD1234, and that looks correct.
08:50So I am going to click OK and exit out of the application.
08:54Now of course, if you want to take it a little further, you will find that
08:58there are different abilities of the UILocalNotification to obviously schedule
09:03multiple LocalNotifications, and because of that to also cancel all
09:07LocalNotifications that this application may have created, but this is the core
09:12of how we create, manage, and reacts to UILocalNotifications on the iPhone in
09:19iOS 4.
Collapse this transcript
Opting out: Making an app that doesn't need multitasking
00:00So what if you want to avoid this whole multitasking idea?
00:04Well, first, do remember that for most applications you won't really be doing
00:08anything in the background anyway, and your app will move to the background and
00:12then move to this suspended string and do nothing.
00:15It really doesn't take a lot of effort to add the applicationDidEnterBackground
00:20and applicationWillEnterForeground methods, and it is recommended by Apple that
00:24you support multitasking.
00:26But yes, if your application really doesn't lend itself to being suspended, and
00:31you want to make sure that it terminates and exists all the way out when the
00:35user presses the Home button, that's possible, and it's very simple.
00:39So I am going to show you an existing very simple application here.
00:42We've just got straightforward NSLog messages for these different
00:46application delegates methods.
00:48So we can see that whether they are working or not.
00:52So if we run, this just using the simulator, right now it is
00:56supporting multitasking.
00:58If I open up my console, I can see that I've got the
01:02didFinishLanchingWithOptions, applicationDidBecomeActive.
01:06If I come back out, we're resigning as the active application.
01:09We're entering the background, and as I open it up again, we're entering the
01:13foreground, and so on.
01:15Same kind of stuff that would just continually go on, and on, and on.
01:21So I will quit out of that and go back into Xcode.
01:24All I am going to do to effectively turn off multitasking is go into my
01:29info.plist file, come down to the bottom of it,
01:33it really doesn't matter, but just press Return, and what I am looking for, up at
01:38the top here, is Application does not run in background.
01:42When that's selected, it becomes a Boolean.
01:45It's just a little check box here that I can check.
01:47Yes, the application does not run in the background.
01:51Technically speaking, this key, if I wanted to look at it as plain text - I'll
01:57save it first - is called UIApplicationExitsOnSuspend.
02:03But you can edit this file, whether you like to edit raw XML or whether you like
02:07to use it as a property list.
02:09It doesn't really matter.
02:11So I am going to save that and click Build and Run again.
02:14I'll open up my Console.
02:17Now you can see here that I have the didFinishLanchingWithOptions has been
02:21called, as has applicationDidBecomeActive.
02:25But now if I press the Home button, what we are going to see is I'll get
02:29the applicationDidEnterBackground, but I immediately also jump to the
02:33applicationWillTerminate, which was not being called, if we were
02:37supporting multitasking.
02:39Now the way the user interface works on a multitasking device is even if you say
02:44you don't support it, if I were to double-click the Home button, I will see
02:48that still there, and it will open back up.
02:51But it's just to make the UI consistent, whether you're supporting multitasking
02:54or not. That application did exit all the way out, and the memory was purged from it.
03:01And one interesting thing to take from this is even when you've checked that
03:05value, that you're saying we don't run in the background, you will see that the
03:09applicationDidEnterBackground method is called.
03:13Interestingly, the applicationWillEnterForeground is never called if you have
03:18that check box checked that the application does not run in background.
03:22So if you do have an application where you really need to turn that off, that is
03:25imply the way to do it, but again, bear in mind that Apple does make it a strong
03:30recommendation that all apps in the App Store should support multitasking
03:35really just to that level of the fast applications switching - allowing it to go
03:40from the foreground to the background and back to the foreground again.
Collapse this transcript
Playing audio in the background
00:00As one of the things that we can now do with multitasking is allow our
00:04applications to play audio in the background.
00:07I am now going to show you how we can take an existing application that plays
00:10just some simple environmental sounds, and I am going to convert that so it will
00:15play those songs in the background.
00:16So right now a very straightforward app.
00:18It's got one Play button on, loads just some environmental sounds, and
00:25starts playing them.
00:26In my viewDidLoad is where I have the code to do this.
00:29It's loading in rainstrom.mp3, creating an instance of AVaudio player, and just
00:35getting that set up and ready to play.
00:37I've got the normal Delegate method here: audioPlayerDidFinishPlaying
00:41to reset the contents of the button, and just a playPause Toggle method here,
00:46that we will switch it on or off.
00:48So to covert this into one that supports multitasking and supports it well,
00:53there is actually two things that I want to do.
00:55First is to just get audio playing in the background, which it won't do right now.
01:00Right now, if I press the Home button, it will just stop playing.
01:03But second, even after that's done, I also want to allow our app to respond to
01:08the Play and Pause controls that the iPhone will give us when it's in the locked
01:12or in multitasking mode.
01:14These are referred to as Remote Control Events.
01:17We want to allow a different UI to send events to us that we'll respond to. So what do I do?
01:23Well, when I am setting up this player in my viewDidLoad, there are a couple of
01:28other things I am going to add.
01:29So, after I get done with the player, I am going to add a line here to set the
01:33category of the audio.
01:35And we do this by calling a method of AVaudioSession, sending our category to
01:41AVaudioSessionCategoryPlayback.
01:43Now there are several available types of category.
01:46We've got Ambient, we've AudioProcessing, PlayAndRecord.
01:49And you might think that the one we need is Ambient, because we are going to
01:53play an Ambient noise, but it's really more about, what is the application doing?
01:58For example, if it was doing voiceover IP, we might need PlayAndRecord.
02:02These choices are more about, does the iPhone silence other audio that might be
02:08playing, or attempting to play, while your app is running?
02:10But what I am going to use is AVaudioSessionCategoryPlayback, a very common one to do.
02:16Then after that, I do need to one more thing here, which is I am going to say
02:21that I want to receive those Remote Control Events, that either the iPhone can
02:26give us when it's locked or in the double -clicked Home button Multitasking mode,
02:32so we call beginReceivingRemoteControlEvents there.
02:35But we're not actually doing that because there are a couple of other things we need to first.
02:40So after viewDidLoad is done, I am going to add a little code in here, to first
02:44say, canBecomeFirstResponder.
02:47We're wanting to make sure that our application is announcing itself to the
02:52world and saying, yes, I can do this.
02:53I can respond to events that the user might do by touching the screen.
02:58We're then going to provide a little note here saying, not only can I do that, I
03:03want to do that. So in viewDidAppear I'm calling self BecomeFirstResponder.
03:08This call wouldn't really work if I did it in viewDidLoad; that's a little too early.
03:12So viewDidAppear is good.
03:14We're saying we're supporting being first responder, and then we are becoming
03:17the first responder.
03:18After that, what I am going to do is support the
03:21remoteControlReceivedWithEvent, so that those remote control events from the
03:27Pause/Play button can be sent through to us.
03:30And I am going to ask what is the event Subtype?
03:33There are actually multiple event subtypes that in am going to use.
03:35The most common one here for audio is this one, which is the
03:39UIEventSubtypeRemoteControlTogglePlayPause. Bit of a mouthful there.
03:45And the thing that I want to show here is there are multiple ones here:
03:48RemoteControlStop, RemoteControlNextTrack, BeginSeekingForward,
03:52BeginSeekingBackward.
03:54And we do have RemoteControlPause and RemoteControlPlay, but bear in mind the
03:59usual interface, when the iPhone is locked, is it's the same button;
04:03it's a toggle button, not an individual Play and Pause button.
04:06So we want the TogglePlayPause here.
04:09That should do it for our code, but there is one super-important thing that we have
04:14to do here to actually allow our application to support playing audio in the
04:19background, and it's nothing do with code.
04:21What we need to do is go in to our plist file, and I am going to add in a
04:26new entry, so I am going to click on the last row here and then just click the Return key.
04:31And the one that I want to find here is the Required background modes key.
04:37I am going to select that.
04:39It's actually an array, so after I have clicked off, I'll get the little
04:42disclosure triangle over here.
04:43I need to expand it.
04:44And it can have multiple items, because in each of the elements of the array, we
04:50can say either the App plays audio,
04:52it registers for location updates, or provides voiceover IP.
04:56We could do three entries and support all three of these, but I am only
04:59interested in one, which is the App plays audio.
05:02So I am going to save the Property list file and build this application.
05:07It says Build Succeeded.
05:09Now I could go ahead and just click Build and Run, but unfortunately it would do
05:12me very much good, because this behavior is not supported in the simulator.
05:18So I am going to have to run it on my device and just take a couple of
05:22screenshots to kind of show the impact that this is going to have.
05:25So I am going to select the device from the dropdown and say Build and Run.
05:32It takes a few seconds and installs on my physical iPhone device.
05:36I am going to press Play to make sure it's working, which it seems to be
05:40working just fine.
05:42Then I am going to hit the Home button.
05:45And right now, this is actually working. If I want to take a quick screenshot of the device,
05:50I have this running, but I have gone back to the Home button.
05:52If I double-click to move into Multitasking mode, I'll actually see it running
05:58in the background, but the audio was still playing.
06:00This is a fairly short app, so I am going to back to it, press Play again.
06:06It's only got 30 seconds of audio.
06:10And then I am going to move into the Multitasking mode with the Pause keys. Press Pause.
06:16It pauses my audio.
06:18Get ready to press Play again, and it will play again and keep on going.
06:25And even the Remote Control Events on the actual locked screen will send its way
06:30through to the application as well.
06:33So this is the core of what we have to do.
06:35Probably the single most important thing is this actual item in your Property list,
06:40that App plays audio as a background mode.
06:43But after that, we are making sure that we set the category of the audio
06:48properly, because if you don't, you may say that you are supporting
06:51background audio, but it's not counting it as the right kind of category to
06:55actually play in the back ground.
06:57And then the optional but very useful ability to begin receiving Remote Control
07:01Events and then reacting to those events, and that allows you to tap into this
07:05whole audio multitasking stuff.
Collapse this transcript
Upgrading existing projects
00:00Let me show you one way I might convert an older, non-multitasking app into an
00:05app that supports multitasking.
00:07I'm going to open up a simple application I actually created in my first iPhone SDK course.
00:12This was an app that demonstrated how to load application settings that had been
00:17changed using the Settings app on the iPhone itself.
00:20Now right now, it's to going to fail, because up here I see that I've got Base SDK missing.
00:25Now this will depend a little bit on what versions of the SDK you have installed.
00:29You can always check by holding down your Option key and clicking here to see
00:33what I've got, but unfortunately as I can see here, I'm currently compiling
00:37against the iPhone 3.0, which is missing.
00:40I don't have that SDK anymore. Not a problem.
00:42I want this to be supporting multitasking anyway.
00:45So I do want this to go against the 4.0.
00:48So I'm going to right-click or Ctrl+click the actual name of the project itself
00:52and go to Get Info, where I then want to make sure I'm on the Build section of
00:57my information about the project.
01:00Down here where it says the Base SDK is 3.0, which is missing, I can either go to
01:053.2, that would really be relevant for the iPad, or in our case a 4.0, and that
01:09should do the trick.
01:11Now right now, up here it's actually going against the device. I want it to go
01:14against the simulator for right now.
01:16So if I save that and then go ahead to my Build menu and just say Build and Run,
01:20it's not very exciting.
01:22In fact, you're not really seeing very much here.
01:25Let me just scale this up a little bit.
01:28It's actually trying to load in some information from the Settings application,
01:33such as name and a background color.
01:35Now if I look at that Settings application, I'll see that I have a section here
01:41for this app, called SettingsSave, where I can put in a name, such as Simon, a
01:47Large Font toggle, whether it's on or off, and down here that actually is a
01:51Favorite Color, so Green, for example. I'm going to back.
01:54Come out of the Settings and reload this application.
02:00Unfortunately, those new settings are not being loaded.
02:03So what's going on here?
02:05Well, the deal is that right now I do have the right kind of code that's
02:11actually going against the defaults database and loading in these settings that
02:16have been specified there.
02:17Now if you haven't done this before, the way that you really specify external
02:21settings is you can do it in your resources, what's called your Settings.bundle.
02:29We have a series of items and a property list that name, for example, the fact
02:34that we've got a ToggleSwitch called a Large Font that has a key of big_font.
02:39Now this is not what I'm trying to explore right now.
02:42What I'm really interested in is the idea that in the ViewController, this code
02:47has been written to load in those preferences, but it's only happening in
02:51viewDidLoad, and that was perfectly fine if our application started from scratch
02:56every time, but it's not fine if we're multitasking.
02:59We'll never pick up any changes.
03:00So this code will never be called, except the first time the program loads.
03:04So I think, well, I do still want this code to be called the first time
03:09the program loads, but I also want it called whenever the app will enter the foreground.
03:15So what I'm going to do is just take this Settings code here and extract it out
03:20of viewDidLoad, taking everything but the call to super viewDidLoad.
03:26I'll just create a simple method right here, called loadSettings, and paste in my
03:35settings code here, so we can call this a couple of times.
03:37So in fact, what I'll do is when viewDidLoad is called, I will just say, self
03:42loadSettings, and then what I want to do is make sure that that code will also
03:48be called whenever I'm going to restore this application from the background, so
03:54whenever it's moving to the foreground.
03:56Now normally what we'd expect to see is our ApplicationWillEnterForeground
04:00method, but that's in the application delegate, and I want to do this in
04:03the ViewController.
04:04So what I'm going to do instead is I'm going to set up a notification center,
04:08and I'm going to say I want to be notified when that notification happens, when
04:12the application will enter foreground.
04:15The way that I'm going to do this is just create an NSNotificationCenter.
04:19So I create an NSNotificationCenter, the default center, the usual way of creating this.
04:25Then I'm adding an observer to this class.
04:27I'm saying that my selector is the method called loadSettings, and the
04:31notification I'm interested in is the
04:33UIApplicationWillEnterForegroundNotification.
04:37Now because I'm now formally subscribing this loadSettings method to that
04:43notification, I do have to make sure that the method's signature up here can
04:48take an NSNotification object,
04:51even if in this case I'm not really going to do anything with it, but I need
04:55that signature to match.
04:57So we've extracted this code out that will read those settings and change
05:02the user interface.
05:04We'll call that once when we do viewDidLoad.
05:07Just to make sure that I can call it properly, I'll just pass in a parameter
05:11of nil, because it's expecting something.
05:14Then I'm subscribing to that UIApplicationWillEnterForegroundNotification.
05:16Well, let's see what happens.
05:21I'm going to save this, compile this code, build has succeeded.
05:24I'll click Build and Run.
05:26Because I'm using a small resolution, it's forcing the iPhone simulator down into 50%.
05:31If I want to scale it back up, I can do that.
05:35I can see that I seem to be reading something from the Preferences pane, but if
05:38I exit out of that, I'm going to go back to the Settings pane.
05:43I'll say change the Favorite Color to Blue.
05:47Come back here and change the name to Second Test.
05:53Come out of Settings. Go back over.
05:56Load it back up, and what happens?
05:58Well, we were expecting to see blue, we're expecting to see a different name here.
06:02So what's the problem?
06:03Well, the issue here can often be that I'm doing it a little bit too quickly.
06:09When I'm in these Settings application, and I'm actually reaching in here and
06:13changing some of this information,
06:16it's affecting that settings database, what's called the defaults database.
06:21The issue is, at the back here in my code where I grab hold of that
06:25NSUserDefaults object, it might be just a little bit out of sync with what's
06:30actually been set in that Settings application, simply because different
06:34applications can reach in there and read and write to it.
06:38So what I'm going to do is after I grab that object called defaults, I'm going
06:43to call synchronize, and it will force it to re-sync and hopefully grab the latest data.
06:47We'll test that again. So I'll run this.
06:52It's picking up those new settings of the blue background.
06:56Let's just do a simple check that I could go into Settings, change the
07:00background to green, come back out, reload the app, either by selecting it
07:07from the springboard or double- clicking here and selecting from the
07:11multitasking part.
07:13You see that it immediately changes to the green background.
07:16In fact, if you'd watch very closely, you would have seen kind of a bit of a
07:19flash there, that the app seemed to zoom in and then changes.
07:23It zoomed in on blue, and then changed to green.
07:26That's because the iPhone took a screenshot of the app in a blue state when it
07:31went to the background, and it was using that screenshot to animate the
07:34application before it then changed the user interface. Not really a big deal.
07:39I'm obviously doing a very, very significant change to the UI, which would
07:42be unusual in most applications between going to the background and going to the foreground.
07:48So in this particular example, I didn't really worry too much about saving state
07:53and using the ApplicationDidEnterBackground method, as I didn't really care.
07:58All my changes were really about that
08:00ApplicationWillEnterForegroundNotification, because really the state of my
08:05application is being saved from the outside.
08:07It's being saved in that Settings application, but of course, if you're
08:10more interested in the saving state, then you can either use the
08:15ApplicationDidEnterBackground method in your app delegate or if you're
08:18interested in calling it from say your ViewController, you can use the
08:22NotificationCenter to subscribe to that notification and do that exactly the same way.
08:28Now we have an application that's gone from the old, very incompatible 3.0
08:33version of the SDK with just a few simple changes, ready for the 4.0 SDK.
Collapse this transcript
3. Using the Event Kit Framework
Introducing the Event Kit framework
00:00In iOS4, we now have a programmatic way to access events in the built-in calendar
00:06database, and even to edit or create those events from our own applications.
00:11Now, to do this, we have two new frameworks, but luckily they're both pretty small.
00:15We have EventKit, which contains the classes we used to programmatically work
00:20with events, and we have EventKitUI, which is a very small framework; it's really
00:25only two view controllers.
00:28This is there because Apple don't want 1,000 different ways to display or edit a
00:32calendar entry, so they're providing a couple of user interfaces for doing this.
00:37Now, Apple aren't intending these frameworks to be used to make a full-fledged
00:42replacement for the Calendar app.
00:44They're just trying to provide what's often been requested, a way to make an
00:47appointment or alarm or to check existing events for a user.
00:52That's really the big issue here: what do you actually want to do?
00:55Do you want to get a range of events,
00:58say, tell me what's coming up in the next week or the next month or the next year?
01:02Do you want to create an event?
01:04Now, bear in mind, if you use these frameworks to create an event from your
01:08application, and the calendar on the device is linked to, say, an exchange server,
01:13the event you create will sync back to that server, just the same way as if the
01:17user had manually created the event using the iPhone Calendar App.
01:22You can, of course, edit or delete events, and because the user's calendar is
01:27often synced to an external source, the events could also be being updated while
01:32your app is running, so you can also register to be notified of changes, so that
01:38your app always has the most up-to-date information.
01:41So, we're going to explore a couple of these different options for using
01:45EventKit. Now there's one thing to keep in mind.
01:49Technically you could use EventKit to create a whole bunch of events as soon as
01:54your application begins.
01:56However, there is an official message from Apple, don't ever create an event
02:01without telling the user, whether that's using the Apple UI for adding an
02:06event, or whether you are popping up an alert or a model-View-Controller, there
02:10needs to some interaction that the user gets to say yes or no, this event is
02:14actually being created.
02:16So, while you could do it programmatically, Apple are likely to bounce your
02:20app out of the app store if they find you're secretly creating events in the background.
02:25So, let's go ahead and see how to work with the classes in EventKit.
Collapse this transcript
Creating calendar events programmatically
00:00Although it's recommended that you use the provided Event Kit UI view
00:05controllers to create, edit, and display your calendar events, let's first see
00:10how to create those events purely programmatically, using the Event Kit framework
00:14to get a handle on how it works.
00:15So, I have a very simple project here, and it's just got one button on this
00:20view-based application that itself links to an IBAction method called
00:25createEvent, and I'm going to add everything here.
00:28Well first off, if I do want to work with the Event Kit framework, I better link to it.
00:32So I'm going to come to my Frameworks folder, right-click and say Add >
00:37Existing Frameworks.
00:38I'm going to find the EventKit.framework.
00:41We don't need EventKitUI right now, and click Add.
00:45Next, in this ViewController here, I'm just going to put an import statement
00:49to tell it that yes, we want to use EventKit.h, and now I can go ahead and
00:56start working with this. So, what do we do?
00:58Well, I'm going to create the event in here, and there's several steps that
01:03we need to work this.
01:04First off, we need to grab something called the event store object.
01:08This is really creating an object that allows us to connect to that calendar database.
01:14It's called the EventStore.
01:16Using the EventStore, we can then create events, we can save events, we can edit
01:20events, all sorts of things, but that's step one.
01:23Next, we want to actually create a new event object itself.
01:27It's the EKEvent, and we're using that EventStore that we created on the previous line.
01:33Now, if I'm defining an event, I do have to have a couple of fields that are
01:37essential, things like the startDate and the endDate and the title.
01:41So what I'm going to do first is just create a couple of date objects to hold
01:45the start date and end date.
01:47For this example, I'm just going to set them both to today, this date right now,
01:51because I'm actually going to make this event an all-day event, so we can keep
01:55it as the same date for start and end.
01:58Now that I have those,
02:00I can go ahead and start setting some properties of this new event object.
02:04There are certain things that are required, such as the title.
02:08We need to give it a start date, we do need to give it an end date, and I'm
02:11also going to set the property of allDay, which is a Boolean, and we're just
02:15going to set it to Yes.
02:17Now, one of the questions you might have is well, where does this event get created?
02:21Well we haven't saved it yet, but we do also have to tell the event, well, you
02:26might have multiple calendars to deal with, so we're first going to tell it that
02:31the events calendar should be whatever the default calendar is on the device.
02:36So, if it's set to connect to Exchange, it's going to be that one;
02:39if it's set to connect to calDAV, it's going to be that one.
02:43You might only have one calendar in your calendar app, but this is the idea of
02:47explicitly saying we're saving to whatever the default one is.
02:50Now, before we save this event, one thing that I do need to do is create a
02:55pointer to an NSError object.
02:57The reason that I do this is that on the following line, I'm actually going to
03:01save the event, and the method that we call is on the eventStore object at
03:06saveEvent colon, span colon, error.
03:09saveEvent means that we are actually just passing the event that we have created
03:14and set all the properties of in the previous lines, span is something that's
03:18really not that important for this event.
03:21It's really more impactful when we're working with events that have recurrences,
03:26and I want to say that if I'm perhaps editing one, I either want to edit just
03:29this event, or I want the span to cross multiple recurring events.
03:34For right now, I can just put in the EKSpanThisEvent, and then we're passing the
03:39pointer to the NSError that we just created in the previous line.
03:42So if there is a problem when creating it, that error object can actually have some values in it.
03:47Now this line should do it.
03:50It should actually save to that calendar database, to the event database.
03:54The question is we probably want to do a bit of tightening up here and actually
03:58ask, well, did we get an error come back?
04:00And if we did, we of course could deal with it.
04:02I'm going to make the assumption that we didn't, so I'm just going to do a
04:05little check for that, test for errors.
04:08If we have no errors, I'm going to create a new UIAlertView object with just
04:13some messages that event was created, how about that, and a button they can
04:16dismiss. And the real reason I'm doing this here is that Apple strongly
04:20recommend that you never create events programmatically without giving some kind
04:25of feedback to the user, and this is very much very obvious feedback, but we're
04:30following the spirit of the law, if not the letter, so
04:33we'll create that, we'll show the alert, and then after it's shown and the user
04:37dismisses it, we can release it.
04:40Well, seeing as we're really done with the other objects we've created too, we
04:44can release those as well, which are the startDate and endDate and actually the
04:48eventStore itself for the ones that we used alloc and init with.
04:52So, I'm going to save this, I'm going to build it, and see what happens.
04:55The build has succeeded, and now I'm going to run it.
04:57Well, there's the question, what do I do here?
04:59Well, unfortunately if I use the simulator, we're going to be in for a bit of a
05:03problem, because the simulator doesn't have a calendar app.
05:07So there's not really an easy way to check whether this worked.
05:10So, instead, I am going to run this on the device, I'm going to click Build
05:14and Run, and I'm just going to take a couple of screenshots to prove that this
05:18is going to work here.
05:20So, what you can't see it, the app is actually running on my device.
05:23What I'm going to do is just open up my Organizer window, which right now is
05:27pointing to my iPhone 4 that I have, and I'm going to take just a quick
05:31screenshot, I'm going to capture that, which is the app with the Create Event
05:35button, I'm going to tap that button, going to do another capture, and you can
05:39see that it's popping up a message that says the event has been created, and the
05:43question might be, well, go prove it.
05:45Well, I'm going to dismiss that, I'm going to leave the application, go over
05:48to my calendar app, do another capture, and I can actually see that on my
05:53month view there I've got the all-day Title for new event has actually been added on there.
05:59So it's reached into my calendar database and added that event.
06:04Now, as we'll see, the recommendation, and that's a strong recommendation from
06:08Apple, is that if you're generally just adding events one at a time, you probably
06:12want to use the standard user interface elements that Apple provide, but
06:17certainly if you want to say create multiple events and you're just popping up a
06:21message to the user asking if this is okay, this is certainly one way you could
06:26go about doing it, is just programmatically adding them.
Collapse this transcript
Using the Event Kit UI components to add and edit events
00:00So now let's see how to create an application that actually uses the EventKit UI
00:04view controllers to allow us to create events.
00:08Once again, I'm back to this idea of a very simple, very
00:11straightforward application.
00:12It's got one button on it right now that is calling an IBAction, and there's no
00:17code in that, and we're going to create the event there.
00:20Well, we're using both EventKit and EventKit UI here, so I am going to just add
00:26a link to those frameworks.
00:27Let's do that second one.
00:36So I have both EventKit and EventKitUI showing up in our Frameworks folder.
00:41Next, I want to do an import statement.
00:44And EventKitUI is really the only thing that I have to use in my code here.
00:52So, what do I do in my IBAction?
00:54Well, I am going to start off with the same eventStore object;
00:58we need to grab hold to this object to represent the link to that event database
01:04on the backhand here.
01:05But instead of creating an event object programmatically, we're going to create
01:10the EditViewController.
01:13This is part of EventKitUI and looks almost identical to the built-in calendar app.
01:18In fact, you'd be hard- pressed to tell the difference.
01:21So we create the controller, we're going to set its eventStore to the
01:25eventStore object I just created, we're then going to set the controller's
01:30editViewDelegate to self, to this ViewController object. That does mean that
01:34we'll have to do something to respond to that in a moment, and it's really
01:37because we're going to pop open this ViewController, and we need it to be able
01:41to notify us when it's done.
01:44I'm going to present that ModalViewController as animated.
01:47That's the classic way of making this appear, so that your users will be
01:51comfortable with seeing it, and it looks like the standard iPhone calendar event
01:56creator, and then I'm going to release that.
01:59Now, really the only thing that might take a little bit more explanation is this
02:03idea here, the idea of the editViewDelegate.
02:05What does that mean?
02:06Well, it actually does mean that we need to create a delegate method here.
02:10Now I'm going to write it right now, which is the delegate method for
02:13EKEventEditViewDelegate.
02:16Let me just split that onto a couple of lines here, can see it, and all that it
02:21is the eventEditViewController colon did complete with action, and we're going
02:27to just dismiss the ViewController away.
02:30However, because I am saying I'm being the delegate for the
02:32EKEventEditViewDelegate, I do need to go and officially support that in my
02:39header file, so I'm going to go back to my ViewController header file over
02:42here, and say that yes, I'm going to support that EKEventEditViewDelegate.
02:49That's what I'm going to do.
02:50Now, the issue is if I compile this, it's probably not going to know what that
02:54is right now. Can't find it.
02:56So, I do need to add an import statement over here, and build succeeded.
03:05It understands the delegate protocol, and then over here we have all the
03:10necessary code to do it.
03:12So, let's see how this one works.
03:13Now, just to show the effect of it, I am going to run this on the simulator,
03:18click Build and Run. Because I have a small resolution, it will pop up at 50%,
03:24but I'm going to just scale that up a little bit, and click the button.
03:30You see how what is popping up here is essentially identical to the
03:34built-in calendar app.
03:36We have the ability to add a Title, and a Location, we can say whether it starts
03:44and ends, we can set whether it's repeating.
03:47We can even set an Alert here.
03:50And then I can say Done, and the actual view controller itself will take care of
03:55adding that event to our calendar.
03:58I don't have to manually, or programmatically, create the event object itself.
04:05So with just a few lines of code, you can see how we can use the built-in user
04:09interface view controller to very simply support an almost identical behavior
04:14within our own applications to the built-in calendar app.
Collapse this transcript
4. Blocks and Grand Central Dispatch
Introduction to blocks
00:00A new language feature in iOS 4 is blocks, and we use blocks to group our code
00:05together into reusable chunks.
00:07Now you might first hear that description and think, okay, and then a few
00:11seconds later think, but surely that's what we do with functions and methods.
00:16Yes, functions and methods do allow us to group code together into reusable
00:19chunks, and there are similarities, but blocks are used for different reasons.
00:24So, why do we use them in the first place?
00:25Well, the first and main reason is that you are going to have to.
00:29Many of the new and the updated APIs in iOS 4 use Blocks.
00:33If you want to use the Assets Library, Grand Central Dispatch, new audio and
00:37video features, the Game Kit,
00:40you are going to have to use these.
00:41Blocks as not some weird esoteric feature that you get to ignore.
00:46If you are going to work with iPhone development, you'll be about as able to
00:50avoid blocks as you would be able to avoid using integers.
00:54We are going to see and use blocks several times in later parts of this course.
00:58Now, the other reason is that they make your life easier.
01:02Blocks allow you to write less code, more readable code, and easily allow you to
01:06tap into powerful techniques in iPhones development; things like multithreading
01:10and callbacks become so much easier using Blocks.
01:15This is why blocks are common in other languages.
01:18In fact, Objective-C is a little late to this party.
01:21Other languages have had blocks or their equivalents for years often under names
01:26like anonymous functions or closures or lambdas.
01:29Well, this is all a little bit out there, but abstract.
01:33So how do we actually do this?
01:34Let me show you a simple example of the syntax.
01:37We are talking about blocks being reusable code chunks, and let's take one
01:43of the existing ones.
01:44Let's say we've got a function - and this has nothing to do with the Block right now -
01:47a typical function. It's got a function that's created, it takes a variable, it
01:51gets returned, and it's called by some other piece of our code.
01:55Now, that function itself is going to have the return type, in this case an integer;
02:00it's going to have a name, in this case myFuntion; and it's going to take
02:03arguments, in this case one integer.
02:06Then we've got the body of the function, which could be one line.
02:09It could be a dozen lines.
02:11it could be a thousand lines.
02:12So, this is your common function, and when we think about a reusable chunk of
02:17code, we think about something like this: either a function or a method.
02:22If we want to see its direct equivalent using blocks, we'll see something like
02:27this, and you'll quite commonly see this shown as an introduction to blocks.
02:31I don't think it's all that helpful, and I'll explain why.
02:33Yes, a block can be created like this where we actually have the official return type here.
02:39We have the name of the block -
02:40in this case we are calling it myFirstBlock - and it's got the caret symbol before it.
02:45We'll talk about that in a second.
02:47Here, we've got something that says arguments, but in fact, in this particular
02:51format, we'll have another section that say arguments.
02:54It doesn't look like we've really won anything. It's more code.
02:58It's kind of slightly more annoying to look at because of the caret symbol.
03:03The issue is when you often see the full declaration of what a block can be,
03:08it's giving you a lot of optional stuff:
03:11things that you would have to do for a function, but you actually don't have to do for a block.
03:15One of the things that we are actually looking at here is really two blocks,
03:19which is why you are seeing two carets.
03:21Effectively, we are seeing the first part here being a block variable, that we
03:25are naming it, and we are saying it has a return type, and it has parameters.
03:31But on the right-hand side of the Equal sign, we are seeing the block literal, which
03:34is what is the block?
03:37In fact, the block literal part is the most important part of this.
03:41An analogy I can make is, say you are working with string literals where we can
03:45do something like this, where we can create a string variable, NSString *message
03:51and set it to the values of a string literal.
03:53But for the most part, we are going to use string literals, and we find string
03:57literals more useful, when we can just use them.
04:01We call NSLog just passing in the string literal;
04:04we didn't have to make a variable based on that.
04:07In the same fashion, if we go back to our block declaration, while this is the
04:11official full declaration of a block, what we can often do is just dump the
04:17first part of it, and say we don't actually need the block variable.
04:20We are just going to use the block literal directly.
04:23Now, this will typically be embedded in some other code, but if you are seeing
04:27that caret symbol, the first symbol that we see here, on a US or UK keyboard,
04:33this is found by holding Shift and the number 6, Shift+6 -
04:36if you are using a different international keyboard, you may have to hunt for
04:40it - but the caret symbol is what tells us this is a block.
04:44Once you see this symbol, you know you've got a block.
04:47So, your first exposure to blocks is likely to be seeing them being used in some
04:52call to one of the new API features.
04:55This, for example, is a call to a new method in the Assets Library Framework,
05:01and the entire thing is just really one statement, one line here, calling
05:05assetslibrary enumerateGroupsWithTypes, and it's actually using two blocks here as arguments.
05:11The first one is usingBlock call on, and then the block just begins with caret symbols.
05:16It says it takes two parameters, and then within the opening and closing braces
05:21we can have a bunch of code written here.
05:24Then there is a second one here being passed as this last argument.
05:28This is a failureBlock.
05:29What are we actually doing?
05:31Well, what this allows to do is, inline, when we are calling this method, we can
05:36say, what happens when this method is called?
05:40If you've ever found yourself having to go and create an external method, name
05:45it, and then pass the name of that method as a selector to yet another method,
05:50that's a good place where you might want to use a block.
05:53What this would allow us to do here is write, inline, the code that we want to
05:58happen in different conditions to this method call, instead of worrying too much
06:02about callbacks and all sorts of stuff.
06:04It makes it much easier to read and understand by keeping your code inline.
06:09Now, while blocks can be passed directly as arguments just by using that caret
06:14symbol where it's permissible, you can also create blocks as objects.
06:18They can be created, and they can be named.
06:21In this example, what I am doing here is creating a block, and there is actually
06:25a type here, called the ALAssetsLibraryGroupsEnumerationResultsBlock, which name
06:30just rolls off the tongue there.
06:31But what you'll find is a lot of the new APIs in iOS have their specific
06:38blocks actually named.
06:39So, I am creating one called listGroupBlock, I am setting =^.
06:45This takes two parameters.
06:46I am going to put in whatever code I want to be called when this block is executed.
06:52I am then going to create another block here, called failBlock, and this is what
06:57might happen when an error occurs.
06:59When this code is written, and when this code is actually first executed,
07:04nothing happens, except the blocks are created and defined.
07:08So, I'll now have something called listGroupBlock, and I'll have something
07:12failBlock, and a little later on in my code
07:15what I can then do is make another method call and actually pass in these blocks
07:20in as arguments to that method call.
07:23Now, you'll find you first need to learn blocks, so that they you can use them
07:28to pass into methods and newer updated frameworks in Cocoa.
07:32Now, as you get more comfortable with blocks you'll likely to create even your
07:35own methods that take blocks as arguments.
07:38I find most people learn blocks best by just starting to use them, recognizing
07:44the caret symbol as the immediate red light that goes off that says, here I've got a block.
07:49Then rather than going deeper into the syntax immediately, which if you'd like
07:53to, you can do yourself by looking at the Apple developer documentation,
07:57we are next going to explore how to use these blocks with one of the new
08:01features in iOS4, something called Grand Central Dispatch.
Collapse this transcript
Introduction to Grand Central Dispatch
00:00Grand Central Dispatch, or GCD, is something new in iOS 4 for iPhone developers.
00:06If you read the official documentation from Apple about it, you'll see all sorts
00:10of phrases that it provides systemic, comprehensive improvements in the support
00:14for concurrent code execution.
00:16At the end of the day, we use Grand Central Dispatch because it makes
00:20multithreading easy.
00:22Your question right back on this might be, well, why do we care that
00:25multithreading is easy?
00:27The end result, no matter how you spin it, is that we want to have a more
00:31responsive user interface.
00:33We want our applications to feel more professional.
00:36Really, what we're trying to do is make the apps able to do multiple things at once.
00:40Now, of course, here we're talking about multithreading, not multitasking.
00:45Multitasking, which we have in iOS 4 as well, is the idea of multiple
00:49applications at the same time.
00:51We're talking about multithreading, the ability for our application to do
00:55multiple things at the same time.
00:57You still might be thinking, well, why is this important?
01:00Well, the issue is that it's all about queues on our machine.
01:06We have a main queue, and that performs tasks one after the other, in order,
01:12whether it's updating the UI, performing calculations, connecting to a
01:16database, whatsoever.
01:17We can, with GCD, easily create a custom queue, take some of these tasks off,
01:23and make them run on their own.
01:26The operating system will take care of all of this, making sure it happens
01:31responsively, and making sure it happens smoothly.
01:35One of the key situations here is the ability to make sure that our user
01:38interface stays responsive, even while things go on in the background.
01:43So, how would we use and work with Grand Central Dispatch in our
01:46iPhone applications?
01:47Well, essentially, there are two steps to it.
01:49Step one, you create a new queue, you give it a name, you give it whatever is
01:54meaningful to you, that this queue would be for networking, or this queue is for
01:58long running calculations.
02:00Then you simply create blocks and drop them into the queue. That's step 2.
02:04Step 3 is nothing. That's about it.
02:07Okay, so, there is a little bit more advanced parts of this, if you want to get deep into it.
02:13But for most people, most of the time, the whole process of using Grand
02:17Central Dispatch is:
02:18make a new queue in your application, and add blocks to the queue - let iOS take
02:23care of everything else.
02:26If you are someone who has programmed multithreaded code before, you'll know
02:29it's a fairly unpleasant thing to do. But I'm serious
02:32when I say that Grand Central Dispatch doesn't just make multithreaded code easier;
02:37it makes it easy.
02:39For the most part, we're going to be interested in two commands that we're going to execute.
02:44One is to create a new queue.
02:46There is a dispatch_queue_create.
02:50The way that we use it is essentially to create a variable, in this case called
02:54myQueue, and I give it a label.
02:56That's pretty much it.
02:58I've said here myQueueName.
02:59This could be a descriptive label for what this queue is being used for.
03:03The reason we give it a label is if we want to see it in debugging
03:06information later on.
03:08When I show an example, I'll show that the typical label that we give it
03:12is actually Reverse-DNS notation, but you can put any text in here that's
03:16meaningful for you.
03:18This is how we create a queue, so I've now got a queue called myQueue, and then
03:22I'm going to use the other most important command in Grand Central Dispatch,
03:27which is dispatch_async, and this simply takes two parameters:
03:33the name of the queue that we're dispatching to, and then a block.
03:37I can see the caret here, with the curly braces that contain everything that we
03:41want to do asynchronously, which in this case is just passing in a command to
03:46run a long running operation method.
03:49So, we do have to use blocks to be able to use Grand Central Dispatch, but
03:53between those two, and learning a little bit about them, you might be amazed
03:58at the amount of stuff that you can do with creating your own multithreaded applications.
04:02Well, I've talked for a while about how easy this is.
04:05I've shown you a couple of the keywords. But to prove it actually
04:08is significantly easy.
04:09In the next module, we're going to go through and show exactly how to convert an
04:14application from single- threaded into multithreaded.
Collapse this transcript
Multithreading with blocks and Grand Central Dispatch
00:00In this example, I'm going to use Grand Central Dispatch and blocks to take an
00:05application that's currently not very responsive with the UI and make it
00:09multithreaded, with just a few lines of code.
00:11So right now I have this application
00:13here, I've got a date picker on there, I've got this button that says complex
00:16operation, and if I hit the button, the actual UI is going to lock up for a few
00:21seconds while it goes and does a big complex operation in the background.
00:25Trying that one again, I can actually see that as I hit that button, any UI
00:29element locks up, the button itself is not responsive anymore, until after a few
00:34seconds it comes back.
00:36This is not good behavior.
00:38Your users aren't going to like it.
00:39It doesn't feel professional.
00:40It doesn't feel useful.
00:42So let's deal with that.
00:44First, I'll explain what's actually happening.
00:46As you might expect, this isn't a super complex application.
00:50I have a button here, I have a label, and I have a date picker.
00:53The date picker isn't even hooked up to any background code.
00:57It's just to show that even the simplest user interface element will become
01:01non-responsive if your main thread is actually blocking.
01:05So back in the code, no huge surprises here,
01:09what's happening is that the button is calling an IBAction method called
01:13doSomething that itself calls a longRunningOperation.
01:17And longRunningOperation is remarkably complex here.
01:20It's going to call sleepForTimeInterval:
01:235 which means it go to sleep for 5 seconds and then change the text of the message label.
01:29And that's all that I have going on here.
01:31There is nothing else in the ViewController header file, apart from those
01:34declarations, and that's all that's in the implementation file.
01:38The only extra thing I have is an import to the stdlib.h, so I can use
01:45arc4random, random number generator, but that's it.
01:49We don't have anything in here to do with threading at all.
01:52So I'm going to use Grand Central Dispatch, and I don't have to link to any new
01:56framework, but I do have to do an import statement here which is #import
02:01<dispatch/dispatch.h>.
02:06And then I'm ready to go.
02:07Because what we want to do with Grand Central Dispatch is use its queues, I'm
02:11going to just define one queue that I want to use here.
02:14Obviously, we have the main queue we can always work on, but I'm going to have
02:18one custom queue for myself here, which would be a dispatch_queue_t, called myQueue.
02:27I'm just defining here, so it's global across multiple methods and whatever
02:31functions I might have.
02:32And the question is, where do I create it?
02:34Well I could create it in a whole bunch of different places, but just for our
02:38purposes, let's make it and viewDidLoad.
02:41I'm going to say myQueue =, and I call dispatch_queue_create.
02:49And this takes two arguments, a label and an attributes list, which right now
02:54the attributes list isn't being used.
02:56They're both actually optional, but the recommendation is you give it a label,
03:00and we don't have to use the at sign here;
03:02it's just a string of characters.
03:04That could be anything that you want.
03:06Give it some meaningful name.
03:08It could be something like networkqueue.
03:11In fact, the recommendation is that the format you use is reversed DNS, based on
03:16the name of your company, so I could do com.lynda.
03:21and then something meaningful for my application, which here is my Grand
03:25Central Dispatch Test.
03:27And if I had multiple queues, I might even say I had a networkqueue, and I had a
03:31calculationqueue. These are just useful names.
03:34Why do we want these labels?
03:36Well, because if we were debugging later on, and we've issues with the queues,
03:40this is going to show up in instruments, it'll show up as debugging information,
03:44and let us know where an issue might have occurred.
03:47And after that, I can just say NULL. I don't need that.
03:50So this will actually create the queue object.
03:53They're pretty light weight, so I don't really worry about having this guy
03:56created for the lifetime of the application.
03:59So the question is, what am I going to do with it?
04:02Well I haven't anything yet, but here is the call that's giving us the issue right now.
04:07Where I called longRunningOperation, it's hanging for 5 seconds before it manages
04:13to get some data back and then actually update the message.
04:17So here is the way I'm going to make it work.
04:19To actually call this on another queue, all that we do is type in
04:26"dispatch_async", and it's going to ask for two things:
04:31What queue am I sending this to, and what am I sending to the queue,
04:34which is, what queue is it,
04:35the first parameter. And what's the block?
04:37We have to use blocks to do it.
04:40So my first parameter is just myQueue, and then the second one is just a block.
04:45I could have created it separately before as a block variable, but more
04:49typically, I'm just going to use the caret, and then I'm going to use my open
04:54braces to define the actual block itself.
04:57Bear in mind, this is just the same, so I end the statement.
05:00And all I'm going to do is copy the code that I want to execute and paste
05:05it inside the block. That's it.
05:07We will now take this call to longRunningOperation, and we'll wrap it in the block.
05:12We'll dump it in the other queue, and Grand Central Dispatch will take care of
05:16executing it on the other queue.
05:18So let's go ahead and build this.
05:20Build has succeeded.
05:21I'm going to go and run it now.
05:24So I can play around with this UI.
05:26I'm going to click the button, and the UI is actually still responsive.
05:29I haven't got a result back yet.
05:32And it's taking a few seconds.
05:33I thought 5 seconds would do it.
05:35I don't seem to have a result yet.
05:37I do eventually get a result, but this is not quite what I was expecting.
05:41What's the problem here?
05:42Well, here's the issue.
05:44We've solved one part of it, which is that our UI is still actually responsive.
05:49We're not blocking the entire application.
05:51That's a good thing, but it's not quite as quick as we'd hoped.
05:54The issue is actually back here.
05:57We're calling longRunningOperation on that other queue, which is fine, but I've
06:03got to look it what it's doing.
06:04We're sleeping for five seconds, and then this second line here is updating that UI label.
06:11Well here's the thing.
06:12You're not meant to update user interface elements from any thread other
06:17than the main thread.
06:19And it's not that you can't, it's not that it's going to crash;
06:21it's just not reliable.
06:23You don't really have an awful lot of control about how quickly things are
06:26updating to the main screen.
06:28So this line needs to be executed back on the main thread, and we might think,
06:34okay well, how do we do this?
06:36So we're going to then call longRunningOperation and immediately have
06:40another one being called?
06:41Well here is the great thing.
06:43I can dispatch_async within this call to actually put this one back on the main thread.
06:49So I'm just going to do another dispatch_async.
06:51Now, I'm not going to send this to myQueue because that's the new one, the
06:58custom queue that I created.
07:00I can actually get hold of the main queue by just calling a function called
07:06dispatch_get_main_queue().
07:10That takes parentheses here.
07:13And then it's asking, well, what's the block that we want to pass in?
07:16Well again, we'll do the same format.
07:18The block is just using the caret and then the contents of the code that we're
07:21going to execute will be content in curly braces before the line ends.
07:26To make this one a bit more readable, let me split it up onto multiple lines.
07:32Grab the line that updates the user interface, and paste it in there.
07:39Get a little ugly in terms of code right now, but it should do the trick.
07:42I'm going to then build that, the build has succeeded,
07:46and go ahead and Build and Run.
07:50And what should happen now is before we click the button we have a responsive UI.
07:54I'm going to click the button, the UI is still responsive, but within a few
07:58seconds we should actually get our result back, and it's actually quicker than last time.
08:02That was about five seconds, which is about right.
08:04Might not be exact.
08:05We're still dealing with multithreading applications.
08:09But this is how we can use Grand Central Dispatch and blocks to very simply,
08:14very easily turn our application from single-threaded into multithreaded without
08:20even saying the word 'thread' anywhere in our code.
08:23Very simple stuff, very powerful stuff to do.
Collapse this transcript
5. Using iAd to Integrate Advertising
Introduction to iAd
00:00One of the completely new frameworks in iOS 4 is the iAd framework, where you can
00:05build an advertising into your applications by allocating a section of your
00:10application screen for those ads.
00:12Now, you could, of course, do this yourself. If you had a willing sponsor and if
00:16this ad was just an image that linked somewhere, you could create a button, put
00:20an image behind it, and respond to a touchdown event.
00:23But the idea here is that you're really allocating this area for Apple, and you
00:28have no idea what's going to go here.
00:31Apple is going to sell the ads and deliver them into your application.
00:35You'll get paid based on the amount of times user see and touch the ads.
00:39So you might do this as say a revenue stream for a free application, but it does
00:44mean you need to carve out some space in your user interface to serve the ads, or
00:48at least in some parts of your UI.
00:50You don't have to do this in all of it.
00:53You most typically have a banner view that shows one of these ads.
00:57The user can, if they want, tap the ad.
00:59If they do, the typical model is they'll go fullscreen into an ad with
01:04additional content, while your app pauses and waits patiently until they're done,
01:09and go back to the application.
01:11Now, the idea is that you'll get 60% of the ad revenue involved.
01:15Now, as money is involved here, step one of this entire process has nothing to
01:20do with programming; instead, you must log on to your iTunes Connect account and
01:24provide all kinds of financial and banking information if you haven't already
01:29set that up by publishing a commercial app on the App Store.
01:32Check the developer portal for the current step-by-step on this.
01:36Step two is allocate an area of space for the banner in whatever view
01:42controller you want ads in.
01:43We'll use the new AdBannerView class to handle the banner.
01:47You can do this programmatically, or there is one you can drag and drop
01:50in interface builder.
01:52Now, as you might expect, this is an Apple control.
01:55It's capable of delegation.
01:57There is got to be some communication going on between the BannerView and your application.
02:02Now, while most of the process of loading ads is taken care of on the Apple
02:07side, step three is building in code to deal with ad-related events.
02:12There aren't too many delegate methods from this, but the three most common ones are:
02:17There is a bannerViewDidLoad method.
02:19So if you're creating the banner view programmatically, you'll wait until
02:23successful load message before you make it visible.
02:26There is a didFailToReceiveAdWithError method, say a banner ad tries to load
02:32something, and you have Airplane mode on.
02:35Now, when the user taps a banner view, you'll get the wonderfully titled
02:39bannerViewActionShouldBegin:
02:42WillLeaveApplication, which is a Boolean value in the second argument here.
02:46When this is called, the user has tapped the ad, and we're about to do whatever
02:52the banner ad wants to do.
02:53That might just be just show content, but then might be go to
02:57another application.
02:59If this willLeaveApplication parameter is yes, it's because another app is
03:04used to serve this ad.
03:06For example, the user touches the ad, and it takes them to a web page in Safari.
03:11In which case, your app is going to move to the background right after this
03:15method is called, and it's time to pause any activity and perhaps save state in the app.
03:20Now, you do get the opportunity to reject that banner ad behavior by
03:24returning no from this method, but if you're not going to do what the ad
03:28wants to do, you won't get your 60%.
03:30Now, the ads that will be placed here can be customized to be relevant to your application.
03:36Again, check iTunes Connect for the latest information on what advertising
03:40services are available at any given time.
03:42Now, Apple's iAd network can provide test ads while you're developing and
03:48testing your application.
03:49It even provides errors once in a while to test your error handling.
03:53And in the next few movies, we'll see exactly how to accomplish all of this.
Collapse this transcript
Using iAd banner components
00:00If you want to see the simplest way of getting ads in your application, there's
00:04actually an AdBannerView control in the Library and Interface Builder, and
00:08there is really not much to it.
00:10I'm going to create just a simple project here.
00:13I'll call it AdTest.
00:14It's a view-based application, and once Xcode is open, I'm just going to open up
00:19ViewController in interface builder.
00:21I'll go to my Library, and I'll scan it and find the AdBannerView, and I can
00:30just drag that onto my view, either at the top or the bottom, or wherever it make sense.
00:35This can be marginally useful when I'm laying out a demo interface, because we
00:40can use it to remind ourselves by looking at the attributes of it, of the height
00:45and width of the Ad BannerView control.
00:47By default, it's going to be 320 x 50 when it's in Portrait mode, and it's the
00:53most common mode, obviously.
00:54Now, technically, if you've got the iPhone 4 Retina Display, it's using more
00:58pixels, but it scales.
01:00We don't have to care.
01:01It can also be set to 480 x 32, but that's if your View itself is actually in the
01:08landscape orientation, or most commonly what you're going to do is just use both
01:16selecting the AdBannerView and allow it be both 320 x 50 and 480 x 32.
01:20I'm just going to save that and go back into Xcode.
01:26One of the things I do need to do is make sure that I link to the iAd framework;
01:31otherwise, it's going to be a real short trip here.
01:33So I'm going to right-click on Frameworks, click Add, and find
01:37Existing Frameworks.
01:40Find iAd, double-click it. There we go.
01:44Save, Build and Run.
01:46Now, when the AdBannerView is created, it attempts to connect to Apple's
01:52servers and load and add.
01:55Let me just open that up a bit bigger, so we can see it.
01:59We're seeing here a Test Ad from Apple.
02:02While you're in development, this is all you'll see.
02:05It's only when you start to configure your app for publication to the app store
02:08by using iTunes Connect, you'll get a chance to see some real ads.
02:12So a Test Ad appears. We can click it.
02:16Our own app is covered with the ad.
02:18We can view the advertisement, or we can take a look at it.
02:22We can close it back down, and Apple takes care of animating it away and we return
02:27to our main application.
02:29Now just closing this down, what we can see when we're running this is there's
02:34a bit of a lack when this app is first loaded before the ad actually appears
02:39in the ADBannerView.
02:41This is something we just have to live with if this is how we're dealing with
02:44this control, by just dropping it onto our UI. But here is the deal: I really only
02:50find it useful to work with the AdBannerView this way when I'm creating a rough
02:56demo of a user interface, and I want to see how the AdBannerView plays with the
03:01other controls that I might be positioning on the UI.
03:04When I build the real app, I do prefer to programmatically work with the Banner View.
03:09It is pretty easy to do, and I can do things like animate this AdBannerView
03:13onscreen only after an ad is loaded.
03:16In fact, one of the downsides of just dropping the AdBannerView into your
03:20application and using it that way is if anything does interfere with an ad
03:26loading, such as the network having problems, Apple really don't like this.
03:31Some people have actually reported there apps being rejected, if they have the
03:36ad placeholder with just a blank space there.
03:39So we're going to see how to work with this programmatically and take care of
03:42that event, and others, next.
Collapse this transcript
Responding to iAd lifecycle events
00:00So, let's see how to work with banner ads in code.
00:03I'm going to create a new view-based application.
00:06I'll call this AdProject.
00:11Maximize it to give it some space.
00:13The first thing I'm going to do is make sure that we are linking to the iAd.framework.
00:17There is not much we can do without it.
00:20Now, all of the code I'm going to write is actually going to be in my ViewController.
00:29I'm going to create an instance of the ADBannerView, and start working with its
00:33different Delegate methods.
00:35Now, because I'm going to work with its Delegate methods, I better go and say
00:39that I'm going to do that.
00:40So, first in my header file here, I'm going to import the iAd header file.
00:46Then I'm going to say, yes, I will implement the Delegate protocol for the
00:50ADBannerViewDelegate.
00:52Once that is done, I'll save it, and jump over to the implementation file.
00:56The first thing I really need to do is actually create the ADBannerView in the first place.
01:00So, I'm going to come down to our viewDidLoad here, uncomment that, and actually
01:06put in the code to create it.
01:10I'm going to create the ADBannerView right at the bottom of the screen.
01:14This is the line I'm going to use to do it.
01:16So, by allocating and initializing it with a position, where it's 460 pixels
01:22off the top - now, bearing in mind that we already have the Status Bar, which is 20 pixels -
01:26that adds up and pushes it all the way down.
01:29so the first line of pixels is just below the bottom of the screen.
01:33So, we can't see it.
01:34I'm going to have to write some code to make it animate up after an ad has
01:39actually loaded into it.
01:41Then I'm going to set its ContentSizeIdentifier to 320 x 50.
01:45This is the classic portrait orientation.
01:48That's all I'm interested in supporting here.
01:50I'm then going to say that this banner is Delegate is self, meaning
01:54this ViewController.
01:55So, here is where I'm going to write the code for the Delegate methods.
01:58Then I'm going to just add it to the current view.
02:01That should take care of actually creating a banner, and the actual banner ad
02:06itself will take care of loading its own ads from Apple's servers.
02:10The issue is, of course, it's invisible.
02:12So, what I need to do is actually add some code to show it.
02:16The way we're going to do it is this.
02:18We're going to implement the bannerViewDidLoadAd method.
02:23I'm going to create an animation block here.
02:25What this is going to do is just change the position of it by -50 pixels.
02:30That's going to move it up.
02:31We've got a beginAnimations call, and a commitAnimations call.
02:35That's all we're doing in the middle. Close that.
02:38I'm going to save it.
02:39Then I'm going to run this and see what happens.
02:43Our app loads into the simulator, and the ad loads and then animates up from the bottom.
02:49Looks pretty good!
02:51I'll admit that the rest of my application isn't looking that exciting, but it
02:54seems that the test ads are being loaded correctly.
02:57I can just watch that all day long and think how fantastic it is.
03:01The problem is we're shortly going to run into an issue.
03:04There is the issue.
03:06The ads get loaded every 30 seconds or so.
03:09It tries to load another ad.
03:11Even though you didn't see a visual change with the ad, another ad was loaded,
03:16and the bannerViewDidLoadAd Delegate method was called, and it shifted up again
03:22by another 50 pixels.
03:23It could keep on doing this.
03:25This is not what I want.
03:27So, I'm going to have to add a line or two of code to make sure that it only
03:31gets animated if it was off the bottom of the screen.
03:34So, going back to the code, what I'm going to just do is, up towards the top here,
03:39I'm going to create a Boolean variable to hold that value.
03:43Let's call it bannerVisible = NO.
03:48Then down in my bannerViewDidLoadAd I'm going to ask, if it's not visible,
03:55we'll execute this block.
03:59I'll then set bannerVisible to YES, and close that block.
04:06So, that should take care of that.
04:08Now, the problem is this:
04:10this leads us into the idea that because ads are attempted to load multiple
04:15times, every 30 seconds or so, it could also fail multiple times, and maybe the
04:19first one loaded, but the second time it didn't, or the third time it didn't, or
04:23the fourth time it didn't.
04:25So, we could have it animate smoothly out from the bottom of the screen, and
04:28then 30 seconds later, it could be empty and look all inelegant.
04:33Well, the way that we take care of that is by adding another method here.
04:36I'm going to do the opposite one.
04:38This is the bannerView:
04:40didFailToRecieveAdWithError.
04:40I don't really care about the error.
04:44I just care about this method.
04:46If that happens, I'm going to ask, is the banner ad visible?
04:50If it is, set up another animation block, move it back down 50 pixels, and then
04:56set it back to being invisible.
04:58I'm not going to run this and test this.
05:01You could test this yourself just by opening up the application, allowing the
05:05first one to load, and then say, turning off your Internet access.
05:09Then what you'll see is it'll try once to load an ad.
05:12If that fails, it'll keep the old ad around.
05:15Then it'll try again.
05:16If it can't load another one, it'll animate right back off.
05:20So, let's run that application. The ad loads.
05:24We've got it. We could tap it.
05:27We get the actual advertisement going fullscreen over the top of our app.
05:32Then I could close it and go back down.
05:33Now, here is the thing:
05:35What if I was doing something really important in my app -
05:39okay, I've got a gray screen right now, but it could happen -
05:42What if I was doing something really important at the time the user tapped here?
05:45Well, is there any way of finding out that that user has tapped?
05:48Well, of course, yes, there is.
05:50So, going back to the code, what I'm going to do is implement another one of the
05:56Delegate methods, which is bannerViewActionShouldBegin:willLeaveApplication.
06:03As soon as the user taps the ad, but before the actual main advert is showing,
06:08we'll get this called.
06:09We get the opportunity to do anything really important.
06:13We also get the opportunity to say no, I don't want the ad to be shown, although
06:17you want to be careful with that.
06:19So in this, I'm just going to do an NSLog here.
06:22Pause anything necessary.
06:23Maybe I've got an animation going on that I want to pause.
06:26But after that, what I'm just going to do is say return YES.
06:30This is basically saying, yeah, go ahead and show the actual advertisement. I could return NO.
06:37If I return NO, the ad will not be shown.
06:39I'll just stay in the app.
06:41But of course, you won't get any money, and
06:43if you're doing your ads for a revenue stream, this is not something that you
06:46want to return NO on very often.
06:49But you might do it if your app is doing something super, super important.
06:53Now, the second parameter here of willLeaveApplication is a Boolean value.
06:59It's basically saying, when the user taps the ad, do we stay in the app and just
07:03show that little overlay ad, or do we actually go to another application,
07:08meaning do we go to Safari and open up a web page?
07:12If the willLeave parameter that gets passed in is YES, then as soon as this
07:18method returns, our app is going to move to the background, using the classic
07:22multitasking willMoveToBackground method.
07:25It's going to just end up in the suspended mode.
07:29If the willLeaveApplication parameter is NO, what that means, instead, is we're
07:34just going to overlay our application with the temporary ad.
07:38The user is going to read it.
07:39They're going to click the Close button, and go back to our application.
07:42Our application has not moved to the background; it's still there.
07:46In fact, if that will be the most common way of doing it, what I'm then going to
07:49do is do the flip side of this.
07:52What happens when we come back to our app?
07:54Well, we've got another method here called bannerViewActionDidFinish.
08:00This would allow us to do any restarting of any animations or
08:04anything important.
08:05So, I'll just log a message here, "We now resume our normal operations."
08:09That should do the trick.
08:10Let's save and compile this, build succeeded.
08:13I'm going to run this.
08:15The app opens. The ad loads.
08:18Let me open up the little GDB here and just clear this Log off, so we can see our messages.
08:25I tap the ad.
08:26We get the message, "Pause anything necessary."
08:28I also see this message a lot.
08:30It doesn't seem to interfere with the actual generation of the ads.
08:34I know many people are actually getting this message about shouldAutoRotate,
08:38but it doesn't seem to be anything that we're doing.
08:40I'm going to then close this down.
08:42I would expect to see the message, "Normal operations are resuming." There we go!
08:47Back to the application.
08:48So, we're not moving to the background; our application stays alive while we're doing this.
08:55This is the core of working with ads on the iPhone.
08:58Once you've got your app signed to a distribution, you can actually start seeing
09:02the real ads, and start making some money.
09:04Up until that point, we'll just be seeing Apple's test advertisements.
Collapse this transcript
6. Working with Audio and Video
Introduction to the Assets Library framework
00:00The Assets Library is a new framework.
00:02It's a way to interact with the photos and videos stored on the device.
00:07Now, an Asset Library might first sound like a generic way to manage all media
00:12assets, but it's not.
00:14This is not about audio, and it's not about vector image in graphic files.
00:19It's just the things you have in the Photos application: photos and video,
00:25either the photos, and video taken by the iPhone, or albums copied or synced to
00:30the device using iTunes.
00:32If you, or your users manage, photos with iPhoto on the Mac and sync those
00:37back to the device, you can get to those albums, things like events, faces and places.
00:44So the same way that the Event Kit framework lets you get at things that you'd
00:48create in the calendar, the Assets Library can be viewed as a way to get to the
00:52things you'd see in the Photos application.
00:55It can also be used to save from your app to that library.
00:59Now because there's a potential risk in allowing an application access to the
01:04location information stored in your personal photos, your users will have the
01:09ability to deny your app access to see this data.
01:12As with Event Kit, the Assets Library is not something every application will
01:17need, but it's a good example of the way Apple are opening up device a bit more.
01:22So you have the ability to really start to integrate your apps into the calendar,
01:26into the photos application.
01:28Even if you're not immediately intending to use these things, being aware of the
01:32ways Apple are opening up their programming APIs to do this is useful, so you
01:38understand their programming model to do it.
01:40For example, you can't use the Assets Library without understanding the new
01:44language construct called blocks.
01:47So if we want to use it, what's the process?
01:49Well first, we create an object to represent the entire library of all photos and video.
01:55This is called an AL, Assets Library.
01:58This library contains groups.
02:01The groups contain the individual assets, the photos and the video, but what are these groups?
02:08Well, the main one will always be the classic saved photos album.
02:12This is the one you see as camera roll if it's on a device with a camera.
02:16If you sync photos onto your device with iTunes, you can also get to groups that
02:20represent events and faces and places.
02:23There's even a group that represents everything.
02:26So some groups contain photos that you would find in groups.
02:30As on iPhoto on the Mac, if you have a photo that's in an event, that same photo
02:35could also be in a place group.
02:38So do bear in mind that the same photo can appear in multiple groups.
02:42You can filter these groups so that you're only looking at photos, or only
02:45looking at video, but at the end, accessing your assets is all about
02:50grabbing the library, enumerating through the groups and then enumerating
02:54through the assets.
02:56If you have the address of an individual asset, you can get directly to it.
03:00They all have an individual URL address, but the only way to get that address is
03:05either that your app created the asset in the first place, or that you've already
03:10enumerated through those assets and picked an asset URL.
03:14So we're going to see first, how to access some core information about the Asset
03:18Library and the things inside it, and then when we later go into video, we'll
03:22see how to save into it.
Collapse this transcript
Using the Assets Library in your application
00:00I'm going to go ahead and create a simple application that will go through the
00:04groups and the assets in our Assets Library, and get some information about them.
00:09So I'll begin with a very straightforward view-based application.
00:12It's got one Get Asset Library Details button that is hooked up right now to an
00:18IBAction method called getStats, and that's all that I have done.
00:22Well, first thing that I need to do is if we're going to use the Assets
00:24Library framework, I better make sure my project knows about that Assets Library framework.
00:29So I will add it in here.
00:32Then in my ViewController implementation file, and that's where I'm going to put my code,
00:36I will put an import statement to the AssetsLibrary header file.
00:42So what I'm going to do in this method, when that button is pressed, I want to
00:46count the number of groups and count the number of assets.
00:49So I'll create a couple of integers, just to hold those values.
00:53I may have to come back to those integers in a moment. We'll see why.
00:57Next is the most important step.
00:59If I'm going to actually use the Assets Library, I need to instantiate an object
01:04to represent the library.
01:05This is all we have to do, because there is only one on the machine.
01:09So I can just call alloc and init on the ALAssetsLibrary object.
01:13Next, I have to prepare it.
01:15I have to say, okay, I'm going to put together a call here, but I'm going to
01:19tell it what groups I'm interested in.
01:21There is actually an ALAssetsGroup type enumeration that we can use here, which
01:27could be GroupAll, GroupEvent, GroupFaces, GroupLibrary, which is everything.
01:32So I'm going to say GroupAll, which includes all groups.
01:36Do bear in mind that when you're enumerating through the groups in the library,
01:40you may get the same photo in multiple groups.
01:44An example would be if you're sorting your photos by faces and organizing them
01:49that way. Well, the same photo that has the face of Bob may also appear in the
01:54group that represents an event on a particular date.
01:56Now if I say here that I'm going to create something that represents all groups,
02:02I'm expecting that the actual number that I'll get is actually bigger than the
02:06number of the actual photos.
02:08Now next, what I have to do is create a couple of blocks.
02:12Now the first one that I'm going to do is a block that will be used to
02:17enumerate through the groups.
02:18What's going to happen is every group that exists, this block will be called.
02:23The way that I do this is I'm creating an
02:25ALAssetsLibraryGroupsEnumerationResultsBlock, which I'm using the caret here for this block.
02:32I'm going to create a little code here.
02:36I'll explain that in just a second.
02:39What this is actually going to do is say I'll be called for every group that exists.
02:44Well, I'll actually be called once more than that.
02:46So I'm going to first check is the group object equal to something?
02:49If there is a group, and it's not a null object, I'm going to add one to my numberOfGroups.
02:55I'm going to find the numberOfAssets in the group and add that to my total.
02:59I'm going to then write a little NSLog message out here.
03:03What I can do is grab hold of the name of the group by using this format.
03:08It's the valueForProperty and then passing in this value that represents an enumeration.
03:14We can grab the name of the group.
03:16We can grab the type of the group.
03:17We can grab the ID of the group.
03:20Now this code won't be run at this particular point.
03:23It is, of course, a block that begins with caret here and ends down here, but
03:29we're going to be passing this into a method call, and it will be called
03:33repeatedly in just a moment.
03:36Next, what I'm going to do is create another block, which is the failure block.
03:39What happens if when we're going to through these groups, something goes wrong.
03:43And this failure block just has an error object passed into it.
03:47I'll just do an NSLog at that point.
03:49Nothing very spectacular here.
03:52With those created, what I can do is now call the enumerateGroupsWithTypes
03:57method of the assetsLibrary object, passing in the block list group
04:02block, which is the first one, and the failureBlock, if that's going to be necessary.
04:07This will actually cause all those blocks to be executed.
04:10It'll actually call them on another thread, which may give us a problem in a
04:14moment, but let's imagine that that happened with this line of code.
04:18All those blocks got executed, and we went through all the groups and counted up all the assets.
04:23Well, next, what I'm going to do then is just create a little message that will
04:28be, there are so many groups with so many total assets and just create a string.
04:33After that, I'm going to create an AlertView to just pop up the information.
04:39The stats to the assets are this message.
04:42I don't need a delegate object, because I'm not doing anything other than
04:45popping up a little alert view with an Okay, cancelButton. That'll do it.
04:51I'm going to show the alert.
04:52I'm going to release the alert.
04:54Then I'm going to release the only other object that I actually manually created,
04:59which was the assetsLibrary.
05:01Now because this button could be clicked a couple of times, I better go and just
05:07undo numberOfAssets and numberOfGroups and make sure they're back to 0.
05:10So I'm going to save this.
05:13Now, what will I do next?
05:14Well, here is the deal.
05:15I could show this in the simulator, but I don't have any photos in the simulator.
05:20Even though I can get a couple of photos into the simulator, it's not really
05:24going to be a very good example.
05:26So I am actually going to use my device and just show a screenshot or two as I'm running it.
05:33So I'll go ahead and click Build and Run to put this on my device.
05:38I'm getting a build failed here.
05:41What's the problem?
05:42Yeah, here is the issue.
05:43I'm getting a message here: Increment of read-only variable numberOfGroups.
05:47Now what's the deal?
05:48While I did create these two integers up here, and I'm trying to add to them in
05:55the actual blocks, and that's not allowed, because the way blocks work, these
05:59are kind of considered constants at this point.
06:01Now there are a couple of ways I could do it.
06:03One is I could take both of these integers and move them outside of this method,
06:09make them global variables within this class, and that would work. Or, another way
06:13of doing it is I can say __block in front of these to tell object to see, hey,
06:21these variables I want to be able to use inside a block.
06:24So let's try and compile that one.
06:26Now build has succeeded.
06:28So I'm going to go ahead and click Build and Run.
06:33While I'm doing that, I'll just open up my console.
06:36It's popping up on my device.
06:37You can imagine what the interface looks like.
06:39There's just one button on it.
06:40I'm going to touch the button.
06:42Now, I can see here that in my Console, it's gone through a bunch of these
06:48groups, and it's giving me the name of the group is, Camera Roll, Photo
06:50Library, Santa Barbara.
06:52I've got certain ones that are dates.
06:54I've got other ones that actually represent faces in there.
06:58So it seems to be pulling the groups out, but I've hit a problem, which is
07:02looking on my device - I'll just flick over to the Organizer, so I can
07:05show you a screenshot - is the actual alert message says There are 0 groups
07:10with 0 total assets.
07:12Now I think, oh, that doesn't seem right.
07:15In fact, the message is telling me it's gone through a whole bunch of groups.
07:18So what's the problem?
07:19Well, I might think, well, maybe it's something to do with those variables again,
07:23but we're actually having an issue with blocks themselves.
07:26I'll show you what I mean.
07:27I'm actually on my device. I am going to press that button again.
07:32If I take another screenshot, it actually seems to be working this time.
07:36So what's the deal?
07:37This looks about right.
07:38There are 45 groups with 571 total assets.
07:42Do remember that the same assets may appear in multiple groups.
07:46So I'm going to go back over to my code here and just stop that.
07:51The problem that we're having, and the reason why I got the pop-up message
07:56saying there are no groups and there are no total assets is this: that we
08:01created the two blocks that are being used to enumerate through those groups and
08:05if necessary put out an error message.
08:09The issue is when I first called it, when I first said go and loop through all
08:14the groups, that was kicked off on another thread.
08:18The problem was we didn't come back from it quick enough, and we jumped straight
08:22ahead to creating the message and outputting the AlertView.
08:26But unfortunately, it did it so quickly that the count was still 0.
08:30Now, one of the reasons that happens is because the first time your application
08:35tries to access the Assets Library,
08:37it's a little slow about it.
08:38In fact, it goes and checks if you're allowed to do that.
08:42The first time you actually run this application on a device, you'll find that
08:45the device will ask, are you allowed to look at location information?
08:50So we're running into an issue where it was a little slow the first time.
08:52Now how do I deal with that?
08:54Well, here is the interesting thing.
08:57Up here in the block that's being executed, this method will be called for every
09:02group that exists, and it will also be called one more time, where the parameter
09:08that gets passed in is actually nil, at the end of the enumeration.
09:13What does that mean?
09:14Well, it means that I can actually say, well, if there is a group object, I'm
09:18going to add to my totals here.
09:20But if there isn't, then I'm done.
09:23I'm actually at the end of the enumeration.
09:25So there would be a suitable place for me to put that error message.
09:31So I'm creating an else block here.
09:32I'm going to come down, copy the code that I had to create the UIAlertView to
09:39both create it, show it, and release it, and come up and paste that into the
09:45statements block here.
09:47Save and build, build has succeeded.
09:50I'm now going to open up my console, just to clear it out, so we can take
09:55a little look here.
09:56Click Build and Run.
09:57I'm going to tap the button once.
10:04I see the groups popping up over there.
10:07If I take a look at my screenshot, which I'm going to capture again, it tells me
10:12there are 45 groups with 571 total assets.
10:15Of course, this is not the most useful application in the world.
10:21What we're really trying to go through is the idea of how do we start to work
10:26with the Assets Library?
10:27The fact that because we don't the individual URLs of each of the images that
10:33are in each of the groups, we do have to enumerate through them, we do have to
10:37understand blocks, and we also have to understand the behavior of blocks.
10:41So this will be a good starting point.
10:43Later on the course, we'll see how we might do things such as create assets and
10:48save video assets back into this library, but this is how we begin to work with
10:52the Assets Library framework in Xcode.
Collapse this transcript
Playing video in your application
00:00When the iPad was released earlier in 2010, Apple did release a 3.2 version of
00:06the SDK, which had some unique classes in it for playing video on the iPad.
00:11Now that we've got the 4.0 release of the SDK, those also work on this
00:15version of the iPhone too.
00:16So, if you've done some iPad programming with video, you may have already have
00:19seen what I am about to talk about.
00:21But if not, you may find this quite useful for playing video in your own applications.
00:26So, I have a very simple view-based application, with one button on the view that
00:31is hooked up to my buttonTabbed - (IBAction).
00:33Now, what I am going to do first, because I am going the media player framework,
00:38well, I better go and add it.
00:40So I am going to add the Existing Framework that is MediaPlayer and although the
00:46framework is media player, the actual class that I am interested in here, and I
00:50am going to create a variable of, is the MPMoviePlayerViewController.
00:58It's not recognizing it right now because I really do need an import statement here.
01:02I am just defining an instance of it, which I will instantiate in just a minute
01:09in my implementation file.
01:12So, if I jump over into my implementation, I have the skeleton of the
01:17buttonTabbed method, which is where I am going to put my code.
01:20Well, first off, I better get some video into my application.
01:24Well, luckily, out here on the desktop, I have a suitable video file, in this case water.m4v.
01:29I am going to drop it in Resources.
01:32You can either have the file included in your application's bundle, if it's just
01:36a small amount of video, or you can provide a URL as well.
01:40It really doesn't matter.
01:41In this case, for convenience's sake I want to actually have the physical file.
01:45So, now it's under Resources and copied into that location.
01:51What I am going to do is basically create a path to that location by just using
01:58the NSBundle mainBundle method pathForResource.
02:01So, this is me just grabbing a path that I can then use in a moment.
02:05After that, I am going to allocate a new instance of that
02:09MPMoviePlayerViewController that I had declared in my interface, and I am
02:14going to initialize it with the path that I just created, creating a file URL from that path.
02:21So, I have got two lines of code.
02:22It might be a little annoying to look at, but this will do the trick. Well, then what?
02:28What I am going to do is actually present the player.
02:31Now, this is really the cool thing about this new MoviePlayerViewController.
02:35In earlier versions of the iPhone SDK, we had a control to play video.
02:39It was the MoviePlayerController.
02:42This one is the MoviePlayerViewController.
02:44One of the benefits that we have of having it being a real view controller is we
02:49have the ability to animate it to present it mode-ly or in this case there is
02:54actually a method called presentMoviePlayerViewControllerAnimated.
02:59What you'll get from using this method on our view controller is to present it the
03:04same way that an application like YouTube application would do it.
03:09With these three lines of code, I am pretty much ready to go.
03:12Now, I haven't actually released the control yet, which is correct.
03:17I wouldn't want to;
03:18it might be still being used, but I am going to go ahead and run it anyway and see what happens.
03:22Now, I've got the small iPhone simulator, so it's going to look a little odd.
03:27But when I press this button, view should pop up and immediately get the video playing.
03:39If I rotate it, it would go into fullscreen mode, and everything would work just fine.
03:43Now, the issue here is what I don't want to do is just call player release at
03:49this point, because if I did that, we are going to stop playing this video,
03:54but we could get some odd behavior happening, depending on if I'm moving around
03:57resizing it using somewhere else.
04:00So, the correct way to do it, which is a little bit more complex, before we start
04:06working with that, what I am going to do before I call
04:10presentMoviePlayerViewController is I am going to write some code here that's
04:14actually going to create a Notification for the PlaybackDidFinish.
04:20Now, this looks a little bit complex here. What I am actually doing is using the
04:24default notification center, adding this class as an observer and saying, when
04:30that movie player has finished playback, I would like it to call me back and
04:35find a method called movieFinishedPlaying.
04:38This is the proper way to subscribe to a notification that that movie has
04:44actually finished in the movie player.
04:46Well, I don't actually have a movieFinishedPlaying method, so I am going to add that next.
04:55Pulling myself off because I don't need to be notified anymore, and then I
05:00can release the player.
05:02It's kind of an interesting thing that it seems more complex getting rid of the
05:06movie player than it is actually loading it up with video and playing it.
05:10But this is the suggested way that we deal with this view controller object.
05:15Now, while working with this new object is a better object than the one we have before,
05:19you might not be terribly impressed if you have been working with video in
05:23previous versions of the SDK.
05:25Indeed, there are real benefits to having this movie player be a true view
05:29controller for something like the iPad, where you have a much bigger screen.
05:33You have all sorts of opportunities to embed it inside other view controllers,
05:38which aren't quite so blankly on the iPhone, but this is the recommended object
05:42that we should use for this kind of playing, and this is the one that I wanted
05:46to bring you up to date on.
Collapse this transcript
Recording video in your application
00:00Continuing my tradition of one-button applications, I am going to take this one
00:05to show you how we can take some of the classic controls that have been around
00:09since early versions of the SDK, such as the UIImagePickerController, tying that
00:14together with some new classes and some new frameworks, like the Assets Library
00:18framework, in order to take video and save it to our photos and videos library
00:24directly from within our own application.
00:27So once again, I have a pretty classic view-based application with one button
00:31that says Record on it.
00:32That right now is just hooked up to a ViewController with an IBAction
00:37called recordVideo.
00:39That IBAction is defined here, but doesn't have anything in it yet.
00:43The only other thing that I have actually defined here is I am declaring a
00:47UIImagePickerController, and making it a property, and that's all I have done so
00:52far to this project.
00:54Now, there is a couple of things I have to do to start things off here.
00:58Now the ImagePickerController has some powerful delegate methods.
01:01So I do need to make sure that I am implementing that Delegate protocol.
01:06So I will say UIImagePickerControllerDelegate. And it gets a little worried if
01:11we also don't say it's a NavigationControllerDelegate as well.
01:15Now, I am going to be using a couple of frameworks in the process of creating
01:21the ImagePickerController and saving to our own photos library.
01:25So I am going to go to my Frameworks location here and add Existing Frameworks.
01:31I am first going to add AssetsLibrary, which probably makes sense from the two
01:35assets library movies that we have already done.
01:38What I am also going to add might seem a little puzzling, but it will make sense in a moment.
01:42I am going to come down and find the MobileCoreServices.framework.
01:48The reason for this is that when we are actually trying to restrict our
01:52ImagePicker down to video, we need an enumeration which is actually defined in here.
01:58If it wasn't for that, I wouldn't need that framework.
02:01So that's my header defined.
02:03I am going to switch over into my implementation file here, and I am going to
02:07do a couple of imports on MobileCoreServices.framework that I just imported,
02:15and on the AssetsLibrary.
02:20So I have got my synthesize statement in here, and I have my placeholder here
02:25for recording video.
02:27So what do I do next?
02:28Well, here is where I am going to start writing some of the code that we need to do.
02:32So first, I am going to create the ImagePicker.
02:34I will see if it exists.
02:35If it doesn't, I will instantiate it, a new instance of the
02:39UIImagePickerController, and then just set its Delegate to self, meaning this
02:45current ViewController.
02:47After that's done, what I am going to do is ask, and this is good code here.
02:50I am going to check if the camera is available.
02:53I am going to ask here the isSourceTypeAvailable:
02:56UIImagePickerControllerSourceTypeCamera.
02:59This is not new stuff.
03:01This has been around for a while now, since older versions of the iPhone SDK
03:06where we could ask what's available.
03:08So, for example, if you only had an iPod touch, you might only have the photo
03:12library available, so the camera call would return no.
03:17So if that is available, we are going to continue on a little bit further, and
03:21we are going to say if that's true, find the available media types, and this is
03:27the way that we do it.
03:28I have broken this onto two lines to make it more readable, but we are going to
03:32get an array of media types by calling the availableMediaTypesForSourceType.
03:38What SourceType do we have?
03:40We, by now, know that we have the camera.
03:44What does this mean?
03:45Well, it's basically going to come back with an array of values that represent,
03:49we can take pictures,
03:50we can take video. And who knows, in the future, whether we are taking 3D or
03:55whatever we might be taking.
03:56But after this, what I want to do is ask if video is actually one of
04:01the available types.
04:02Was that array that was returned contain the actual field that represents it
04:08which is kUTTypeMovie.
04:11This is actually the reason that I had to add the link to MobileCoreServices
04:16because this enumeration is actually defined there.
04:19So we are asking, what mediaTypes are available? And after getting that
04:24array back, because it could have been say an iPhone 3G that has a camera
04:28but can't take video.
04:30So if that is just movies are available, I am going to restrict the source type to camera.
04:36I am then going to restrict the media type to video, and this is the way that we do it.
04:40The picker both has a sourceType.
04:42It says we are going to use the camera, and not only are we going to use the
04:45camera, we are restricting the media type to kUTTypeMovie, and the way that we
04:50do it is by essentially creating an array with basically only one entry in it
04:55that says it's kUTTypeMovie.
04:57We have now finished that one, and if there was no video support, here is where
05:03we could do a message if we saw fit.
05:05Let me line those up a little bit and make them hopefully a bit more obvious. There we go.
05:12There is quite a lot of code being added here, but hopefully it will begin to make sense.
05:17So after that, we have restricted it to the camera.
05:21We have restricted it to only taking video.
05:25Then we can present the picker.
05:27Just a call to presentModalViewController passing in the picker that we have
05:31created, and now we have configured.
05:34It will then show this to our user.
05:36It will allow the user to start taking video.
05:38It will give the user the opportunity to either preview the video, to delete it
05:42if they don't like it, or to retake it.
05:44But we have to continue on and do a little bit more code about what
05:49happens after that.
05:53One of the simplest delegate methods, and the most important ones for the
05:56ImagePicker, is the ImagePickerControllerDidCancel.
06:00So they saw the ImagePicker and decided not to use it, and all we are going to
06:04do here is dismiss that ImagePicker, and then release it.
06:09The most important one that we want is well, what if they took some video, and
06:13then said, choose, this is the one that I want.
06:16Well, here is what happens.
06:18We get the ImagePickerControllerdidFinishPickingMediaWithInfo.
06:23Bear in mind in some programs, I might have to ask things like, is this a
06:28picture that I am getting, is this video that I am getting?
06:30I know, because I have configured my ImagePicker that if we go back into this
06:34method, we have just got video.
06:36So what I am going to do is grab the URL of the recorded video.
06:40It will be passed into me as part of the info object here.
06:44So I will do an info objectForKey, and the key that I am interested in is the URL of it.
06:50I am actually going to write that out as NSLogs, so that we can take a look at it in
06:54a moment. What is the temporary URL of a video before we save it?
06:58Carrying on, I am going to use the new AssetsLibrary.framework to help me save this.
07:04I am going to be saving this not into the sandbox of my own application, but I
07:09am going to be saving this into the regular saved photos library that I can get
07:14to through the photos application.
07:16We get a handle on that library by just instantiating the
07:19ALAssetsLibrary object.
07:21Now, this ALAssetsLibrary framework, being one of the new ones, uses blocks a lot.
07:26So when I am actually saving this video, it's going to have a completion block
07:31to handle what happens after the video is saved.
07:33So I am going to create that here which is an
07:36ALAssetsLibraryWriteVideoCompletionBlock. That takes two parameters:
07:40an error object, and an NS URL.
07:42I am going to make the assumption that when we get called, we will have saved
07:47that file, and we will have another NSLog message saying Success!
07:51The new URL is so and so.
07:53Now, this code is not being called yet.
07:55We are just creating this block, and we are going to pass it into a call to the
08:00ALAssetsLibray object.
08:03So that's where we do it;
08:04saving the video here.
08:06We call writeVideoAtPathToSavedPhotosAlbum, passing URL that we had grabbed up
08:12on the first line here, and then passing in the completionBlock to say what
08:17happens when it's been saved.
08:18Once we are done with that, we can release the assetsLibrary, and then we
08:23can dismiss the picker.
08:24I am going to save this.
08:27I am going to build this project;
08:30build has succeeded.
08:32Now, of course, what I can't do is test this in any meaningful way on the simulator.
08:37So I am going to run it on my own device, and just take a couple of screenshots
08:41to prove whether it's working.
08:44So I will click Build and Run.
08:45I will open up my console, so we can see any messages that we get.
08:52It's installing on my machine.
08:53I have got the one button has come up, and I am hitting record.
08:57It's passing a message out here, which has nothing to do with me about using a
09:01two stage rotation animation.
09:02We can just leave that alone.
09:04What I am actually going to do with this, I am going to flick over and see my
09:09Organizer here, and just take a quick capture of the screen, which is now my
09:13camera pointed at the screen I am about to capture.
09:17I am going to take some video.
09:19I will take about five seconds of video here, and stop it.
09:25Now what will happen, if I take another capture of the screen here, is that the
09:30screen itself is going to throw up the video that I have taken, allowing me to do a
09:34quick trim of it, and allowing me either to Retake or Use.
09:37This is all controlled by the ImagePickerController itself;
09:41I don't have to bother about this.
09:43The issue is I am going to hit the button that says Use, and that should
09:47call the method of my AssetsLibrary to actually save it back into my saved photos library.
09:54I hit that button, and I get dismissed and just taken back to the regular part of my screen.
10:00So if I come back over and see my console, I should have my messages here that
10:06will actually tell me two things:
10:09One was the first message saying that the temporary URL was, it gives me a file
10:15path with a created name with a unique ID added to it.
10:19Then we pass that URL to the AssetsLibrary, and said, save this properly,
10:24and now the new URL is in the assets-library location with an asset.MOV with a unique ID in it.
10:32So it seems to have worked just fine.
10:34Of course, at this point, you might be taking that URL and saving it as a piece
10:39of data in this actual application, so we can bring it back later.
10:43But this is the method that we can do to fairly easily start to take and save
10:48video from our own applications into the photo library.
Collapse this transcript
7. Creating Apps that Run on Multiple Devices
Detecting device capabilities
00:00Even if you're intending your app to be only used on iOS 4, do remember to do
00:05runtime checking of the device capabilities.
00:08It's very easy to assume that everyone has an iPhone that's configured the same as yours.
00:12The main things to check are camera and multitasking support, because they vary the most.
00:17If you're working with the camera, you do, of course, have the
00:20UIImagePickerController, and you can ask a lot about the hardware based on this.
00:24You can find out what kind of camera is available, if a camera is available at all.
00:29Of course, if you have the iPod touch, there is no camera;
00:32there's only access to the saved photos roll.
00:35Even if you do have a camera, you don't know whether you can take video on it.
00:40So you can ask the availableMediaTtypesForSourceType, does it have video, does
00:44it have still images?
00:46Beyond that, you can ask things like is the flash available for the camera
00:49device, if that makes a difference to you, and even things like the
00:53videoMaximumDuration, how much video can I take if I'm building that into my own application?
00:59When it comes to multitasking, there is an isMultitaskingSupported Boolean on
01:04the device, which you can look at, though it doesn't exist on pre-iOS 4 devices.
01:09So, in some cases, first you have to check for the existence of this Boolean
01:14before you can check to see what it is.
01:16Apple's official suggestions for how you do this is that you're first going to
01:20grab hold of the currentDevice, you're going to create your own Boolean called
01:25backgroundSupported, and you'll do something like ask if the device
01:29respondToSelector colon and then passing in the at sign selector
01:33isMultitaskingSupported.
01:35This is really asking, does this Boolean variable exist at all before I ask what
01:41the value of it is, and if it does exist, we can set that to our
01:45backgroundSupported area.
01:47Now, this is a pretty good model for quite a few of the capabilities that may or
01:51may not be running on the device.
01:54However, if you do decide to only support certain features, and even want to
01:58prevent people from running your application if they have a different setup, you can.
02:03In your Plist, there's a UIRequiredDeviceCapabilities key, where you can add
02:09an entry specifically requiring or specifically prohibiting a whole bunch of
02:14different very specific features; in fact, the available options are quite a few.
02:19So if you wanted to say, for example, that you had to have the microphone or
02:24that you wanted to prohibit your application from running on people with an
02:28auto-focus camera, you could do this.
02:31But in general, you'll leave this entry alone.
02:34You don't have to specify the things you'd like to have;
02:38you only put something in that key if your app absolutely must not run
02:43under certain conditions.
02:44It either must have telephony or must not have telephony.
02:48Otherwise, you just leave that key alone and do some basic reactions to
02:53different hardware support within your program itself.
02:57Bear in mind that during the app store submission process there are also options
03:01to restrict your app to certain devices.
03:05But more than anything else is the obvious: test, test, test, because if you
03:11don't, Apple may, and they have a pretty good process for detecting
03:15incompatibilities between what you say you support and what you actually do.
Collapse this transcript
Using weak linking to new frameworks
00:00Now, these days, Apple aren't even accepting submissions to the App Store that
00:04are built on versions of the OS prior to 3.2, but we could still have
00:09legitimate reasons for building applications that we want to run on both the 4.0
00:13with the extra new frameworks, and on 3.2 without them, say, such as the iPad.
00:18Now typically, this idea isn't going to work.
00:21For example, if I create a New application, I will call it BothDevices, because
00:26I want this to run on both devices.
00:28I am going to expand this, and then I am going to link to one of the frameworks
00:33that's only in iOS 4.0.
00:35I am going to pick the Assets Library.
00:40That's only in the 4.0 version of the device.
00:42So, let's say I select my simulator here, and what I am going to do is just
00:46click Build and Run.
00:47I'd expect this to build successful and install on the simulator.
00:52It's not going to do anything, but it installs okay. Looks good.
00:55What I want to do is have this code also install and run on an iPad.
01:01There are a couple of things I have to do to get this to work.
01:05Now, a couple of different ways of getting there, but the way I prefer is
01:08first I am going to go to my project here, right-click and say Get Info and
01:14on the Build section, I have a whole bunch of information about how this project is built.
01:20Now oftentimes, people jump straight to this Base SDK thing that currently
01:24says iPhone Device 4.0, and we think, well, could we switch it to 3.2?
01:28And the answer is absolutely not, because I am wanting to link against the
01:32Assets Library, which is in 4.0.
01:35So the Base SDK here is not really the lowest thing that we are going against.
01:40This is the optimum one that we are going against.
01:43However, what I can do, if I come further down in here, is what I am going to
01:48find is a section that allows me to select the Targeted Device Family, just the
01:54iPhone, the iPad or the iPhone/iPad -
01:55that will do - and what's called the iPhone OS Deployment Target, which is, okay,
02:03we compiled or built against the 4.0, but what should the code load on?
02:08And I am going to select here 3.2.
02:11I am going to then close this window, and just hit Build and Run again.
02:18I shouldn't expect any changes.
02:19We are still opening up in the iPhone Simulator, but what I can do now is go
02:24over to the dropdown and say that I want to switch to the iPad Simulator.
02:29Now, one of the things you will often see is if you hit the Option key, you will
02:33see more options in there.
02:34But I'd hope with those changes that from the regular dropdown, you should see
02:38iPad simulator, and I am going to click Build and Run here.
02:41That didn't seem to do much.
02:46In fact, it looks like it's completely just dumping out right away.
02:50Even though technically it built, the program is not running on the iPad, and if
02:54I open up the console, we are going to see why.
02:57We have got a message popping up here that the Library is not loaded.
03:05The Assets Library, image not found.
03:07Now, depending on how the configuration is done, you will find a variety of
03:11error messages for this, but this is not really a particular surprise.
03:15We are trying to load the Assets Library, and the Assets Library does not exist
03:19on the iPad Simulator.
03:20This is 3.2, and it only exists in 4.0.
03:24So, what can we do? Well, step one;
03:26I am going to go back into my Xcode project.
03:29What I need to do is say that the AssetsLibrary.framework is Weak Linked, really
03:35saying, if you've got it, use it.
03:38If you don't, just forget about it; just ignore it.
03:41The default is for all our frameworks to be required, and they must be there for this to run.
03:47So I need to change the settings of this one to be Weak Linked.
03:50And the way that I am going to do it is I am going to find my Targets section,
03:54and expand the Disclosure Triangle and highlight the name of the application.
04:00Now, there is a couple of different ways of getting here too, but this is the
04:03most straightforward, I find.
04:04And come down and say, Get Info.
04:07On Get Info for the Target,
04:09I am going to switch to the General tab, where we see all our Linked Libraries here.
04:13And you will see that all four of them are required right now.
04:16I am going to change Assets Library to Weak. Close that.
04:22Another place you will often see those settings is actually when the Target is
04:26correctly highlighted, you may often see them over here, and you can actually
04:30change them there too, but I preferred going more directly to them.
04:34And I am going to click Build and Run.
04:36We open up in the simulator.
04:38We are not doing anything, but the application is running. Close that. Come back down,
04:43switch over to the iPad simulator, and Build and Run, and at least the application loads.
04:49And if I open up the console, the last session that's started looks like it's fine.
04:54There is no problem there.
04:55There are no error messages.
04:57So, looks good. Then what?
04:59Well, the problem is, of course, I am not doing anything.
05:02I am not actually using the Assets Library classes in any way, shape, or form.
05:07And of course, my situation is that I want to be able to use them if I have them,
05:11and not use them if I don't.
05:13Now, obviously your application's behavior has to support this.
05:16The question is, how do we write the code to do it?
05:20Let's say I open up my View Controller, and in my
05:24viewDidLoad, I am going to write a little code.
05:28Well, if I just do something along the level of ALAssetsLibrary, well, first we
05:32are not going to find it, because I need to Import the library here.
05:39But if in my viewDidLoad, I decide to create a copy of this,
05:45this is going to work fine on 4.0, but is not going to work fine, at all, on 3.2,
05:51and it's going to cause a major problem.
05:53So how do we deal with it?
05:54Well, as ever, there are actually a few ways.
05:58One of the most simple ways we could do is we could wrap our code in some kind
06:02of condition, and we can base that on a couple of things that we can find out.
06:05One example might be the UIDevice currentDevice systemVersion.
06:10Now, this will actually return a string, but it will say, in our case 3.2 or
06:154.0.1 or 4.0.2, and I might wrap my code in this condition.
06:21So in a particular part of my code, I will check what version I am.
06:24If I am 4.0 or above, I will create the ALAssetsLibrary;
06:28otherwise, I might disable that part of the application.
06:31So I am just going to write that out in a NSLog to show you what that data
06:34looks like, and here is another more direct way of doing it.
06:38I am going to actually write a IF statement that's asking If NSClassFromString,
06:44now this is a built-in function, part of NEXTSTEP, and it basically is asking, is
06:50there a class with this name?
06:52If this returns nil, then it doesn't know about an existing class
06:56called ALAssetsLibrary.
06:58So, if it's true, I could go ahead and create that, and in this case, I will put
07:03out a message saying, Yes, it exists,
07:05create the Classes and use them; otherwise, I am going to do an output message
07:09that says, No, it doesn't.
07:11I am not going take you much further than this;
07:13you should be able to get the point that pretty much you are going to have to
07:16wrap a lot of code in conditions. Is that annoying?
07:19Oh, you betcha!
07:20Absolutely! It's very annoying code to write.
07:22But at least we can write it.
07:24We don't have to guess at it.
07:25I am going to save this and build, and then I am going to run this on the iPhone
07:31simulator and open up the console here, and what I'd expect to see is exactly
07:37this, that I see version is 4.0.1.
07:41The class ALAssetsLibrary exists, and I could go ahead and create it.
07:45If I stop this, clear the log again, switch over to the iPad simulator, and now
07:53because we are doing Weak Linking, and we are also checking for the existence of
07:56the class, what I'd hope to see, with the console open, is that version is 3.2 and
08:03no, the class doesn't exist.
08:05So I wouldn't create it.
08:06I might disable part of the application.
08:10So, while writing this conditional code is not the most fun thing in the world,
08:14if you are trying to create one application that does support multiple versions
08:19and is smart enough to turn pieces of itself off,
08:22this is the way to do it.
Collapse this transcript
Conclusion
Goodbye
00:00Thanks for joining us for iOS 4 App Development New Features.
00:04You've now seen many of the new and improved features, frameworks, and tools
00:08found in iOS 4, and you should now have a good idea of what parts of iOS 4 you
00:12want to take further.
00:14You might want to do more with motion, or dive deeper into video and audio, or see
00:18what can be done with multitasking, and also how to make apps that not only use
00:22these new features, but degrade gracefully for older devices when necessary.
00:27Keep a regular eye on developer.apple.com.
00:30In the early days of iOS 4, it's updating with new examples all the time and
00:35best practices on using these frameworks, but it's a great time to be an iOS app developer.
00:40Good luck with your applications.
Collapse this transcript


Suggested courses to watch next:

Xcode 4 New Features (1h 58m)
Bill Weinman



Are you sure you want to delete this bookmark?

cancel

Bookmark this Tutorial

Name

Description

{0} characters left

Tags

Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading
cancel

bookmark this course

{0} characters left Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading

Error:

go to playlists »

Create new playlist

name:
description:
save cancel

You must be a lynda.com member to watch this video.

Every course in the lynda.com library contains free videos that let you assess the quality of our tutorials before you subscribe—just click on the blue links to watch them. Become a member to access all 100,984 instructional videos.

start free trial learn more

If you are already an active lynda.com member, please log in to access the lynda.com library.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Access to lynda.com videos

Your organization has a limited access membership to the lynda.com library that allows access to only a specific, limited selection of courses.

You don't have access to this video.

You're logged in as an account administrator, but your membership is not active.

Contact a Training Solutions Advisor at 1 (888) 335-9632.

How to access this video.

If this course is one of your five classes, then your class currently isn't in session.

If you want to watch this video and it is not part of your class, upgrade your membership for unlimited access to the full library of 1,943 courses anytime, anywhere.

learn more upgrade

You can always watch the free content included in every course.

Questions? Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com.

You don't have access to this video.

You're logged in as an account administrator, but your membership is no longer active. You can still access reports and account information.

To reactivate your account, contact a Training Solutions Advisor at 1 1 (888) 335-9632.

Need help accessing this video?

You can't access this video from your master administrator account.

Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com for help accessing this video.


site feedback

Thanks for signing up.

We’ll send you a confirmation email shortly.


By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked