IntroductionWelcome| 00:03 | Hi, I am Simon Allardice, and
this is iOS 6 SDK New Features.
| | 00:08 | If you have been developing for iOS devices
but working with the features in iOS 5 and
| | 00:13 | before, this course will quickly bring you up to
speed on what is available in iOS 6 and how to use it.
| | 00:18 | We'll see the changes to user interface controls in this
version of iOS, particularly collection views and what they offer.
| | 00:25 | We'll also explore the
changes and improvements in Xcode.
| | 00:28 | Things like using Auto Layout for your
user interfaces and the current best practices
| | 00:33 | when creating classes and
properties in Objective-C.
| | 00:36 | We'll see how to create apps that use
Apple's new Maps features, or how to use passbook
| | 00:41 | in your own applications for managing passes,
tickets, or coupons, see what the
| | 00:47 | social framework offers for Facebook integration.
| | 00:48 | So, let's get started with our look at the new
features of the iOS 6 Software Development Kit.
| | Collapse this transcript |
| What you need to know| 00:00 | This is a new features course
for version 6 of the iOS SDK.
| | 00:04 | So, this is meant to bring you up to speed if
you've already been developing iOS apps using iOS 5 SDK.
| | 00:11 | And you need to have that knowledge
if you want this course to make sense.
| | 00:14 | You know your way around Xcode, you can
read and write Objective-C, and you're familiar
| | 00:18 | with the core skills of iOS development like
working with Model-view-Controller, Delegation,
| | 00:22 | and Target-Action, and I do expect you to be
comfortable with the major developer features
| | 00:27 | of iOS 5 like Automatic Reference Counting
and Storyboards.
| | 00:31 | Now, if you need to first learn these skills
or even just brush up on your knowledge, take
| | 00:36 | a look at our other courses at lynda.com first, like the
courses on Objective-C, or iOS SDK Essential Training.
| | 00:43 | But if you are ready to go, then let's start exploring
this version of the iOS Software Development Kit.
| | Collapse this transcript |
| What we'll cover in this course| 00:00 | I am recording this course using iOS 6.1 and Xcode 4.6,
both released at the very end of January 2013.
| | 00:09 | As ever, Apple do release new
versions of Xcode and iOS on a regular basis.
| | 00:14 | So if you're using a newer version,
you may see some slight differences.
| | 00:17 | What you don't want is to have
any earlier version than I do.
| | 00:21 | So if you open up Xcode and see version 4.5 or
earlier, make sure to update Xcode before continuing.
| | 00:28 | If you've been following the progress of
iOS development over the last few years, you'd
| | 00:32 | know that with every major number release
of iOS to the general public, we've also had
| | 00:37 | big changes to the SDK, and we
only have a few years of this.
| | 00:41 | After all, version 2 of the operating system
iPhone OS 2 was the first version where developers
| | 00:47 | outside Apple could create apps at all.
| | 00:50 | But quite quickly, we had version
3 and then version 4 of the SDK.
| | 00:54 | Now, version 4 brought multitasking and
added blocks to the Objective-C languages.
| | 00:59 | These were both very big changes for
developers who started on OS 2 and OS 3.
| | 01:05 | And then iOS 5 came along and gave us the
wonderful Automatic Reference Counting,
| | 01:10 | or ARC, as well as Storyboards.
| | 01:11 | And once again, these were big sweeping changes,
things that every iOS developer needed to understand.
| | 01:18 | But iOS 6 doesn't have anything on the same level
as the addition of ARC or the switch to multitasking.
| | 01:25 | There's simply nothing that impacts
every iOS project on that same scale.
| | 01:29 | What we have this time
around are several new frameworks.
| | 01:32 | Now, we always get new frameworks, iOS 6 is
no exception, and a few smaller things that
| | 01:36 | do improve the overall programming experience.
| | 01:39 | AutoLayout, it's a new way of
arranging iOS user interfaces.
| | 01:43 | It is probably the most noticeable if you're
coming from iOS 5 to iOS 6, but it's nowhere
| | 01:48 | near as bigger change as say
Storyboards were going from iOS 4 to iOS 5.
| | 01:54 | The most substantial additions in iOS 6 are the new
feature-focused frameworks, PassKit, and the Social Framework.
| | 02:01 | Now, here is the issue with
creating a course on those frameworks.
| | 02:05 | You may or may not care about any
of them, and that's perfectly okay.
| | 02:09 | Those kinds of frameworks aren't about general
iOS development, they're very specific to a need.
| | 02:14 | You use them if you want that feature,
you would know them if you don't.
| | 02:18 | So you for example maybe totally enthused
about Facebook integration for your app or
| | 02:23 | it may be completely irrelevant to you, same
with integrating maps or working with passbook.
| | 02:28 | So to keep everything useful and relevant here,
| | 02:31 | what I am going to focus on in this course
is not trying to make you an expert on any
| | 02:34 | one of the new frameworks, but just to
make you a good all round iOS 6 developer.
| | 02:39 | You understand them all, and not just at a
simple sentence level, but you've had a hands-on
| | 02:44 | example of what the new major frameworks
cover and how you'd get moving with them,
| | 02:49 | and if and when you need to go deeper,
you know exactly how to do that.
| | 02:52 | And we'll cover in more depth things like
AutoLayout and the new user interface controls
| | 02:57 | like collection views, things that you are more
likely to use in all your iOS development going forward.
| | 03:03 | So, before we get into those frameworks,
we're going to start with those changes, additions
| | 03:06 | to Xcode and new and improved
controls for the iOS user interface.
| | Collapse this transcript |
|
|
1. Xcode and Objective-C changesChanges to Xcode| 00:00 | The previous major release, iOS 5, was
released along with Xcode 4.2, and there were
| | 00:06 | a few point releases of Xcode during 2012.
| | 00:09 | We had 4.3, 4.4, 4.5, as well
as a few others in between.
| | 00:14 | But rather than just talk about what's new
specifically in Xcode 4.6, and there really
| | 00:20 | isn't a lot new in 4.6, I am going to cover
the changes that have happened in Xcode since
| | 00:25 | the release of iOS 5.
| | 00:26 | So if, for example, you had watched
the iOS SDK Essential Training
| | 00:31 | or Objective-C Essential Training courses, a lot of those
were recorded using Xcode 4.2 and 4.3, I am going to get
| | 00:38 | up to speed on what has
changed in Xcode since then.
| | 00:42 | Now, Apple often go into excruciating
detail on the Xcode changes between versions.
| | 00:48 | We don't really need to do that.
We just need to clear the decks.
| | 00:51 | So, even if you have been working with 4.4,
4.5, 4.6, I'm just going to go through
| | 00:57 | and cover the two or three
major impacts of each version.
| | 01:01 | And over all the changes that have happened,
I am only going to have three things that
| | 01:04 | are big enough to talk about on their own.
So Xcode 4.3 arrived.
| | 01:09 | This was the one that turned Xcode into a
regular App Store application that just installed
| | 01:14 | into your normal Applications
folder on your Mac.
| | 01:17 | Before that, we needed a separate
installer application for the SDK, and it installed
| | 01:22 | all the tools at a different location,
and really, that was the main change
| | 01:27 | of Xcode 4.3, there wasn't a lot new there.
| | 01:29 | Although it did mean that you had to now
open other developer tools like Instruments say
| | 01:34 | from within the Xcode menu because they
weren't installed as totally independent applications
| | 01:40 | as they have been previously.
Then we got Xcode 4.4.
| | 01:43 | A couple of good things here, 4.4 didn't
change much visually, but it uses a new version of
| | 01:49 | the LLVM compiler, version 4, behind the scenes,
and that supports a couple of shortcuts of
| | 01:55 | efficient ways of writing Objective-C to
save us some time, first, Objective-C Literals.
| | 02:02 | We've long been able to use the at sign as
a shorthand to create an NSString object,
| | 02:07 | but now we can use that also to
create NSArrays, NSDictionaries, NSNumbers.
| | 02:12 | We don't have to use some of the more
tedious init methods to create these.
| | 02:17 | I am going to cover literals in
their own movie in just a minute.
| | 02:20 | Now also with Xcode 4.4,
synthesize happens by default.
| | 02:25 | You don't have to write synthesize
statements for your properties anymore.
| | 02:29 | This was a technically minor change, a
minor improvement just to kind of get away some
| | 02:35 | speed bumps in the road, but it did trip a
lot of people up, particularly developers
| | 02:39 | new to the Objective-C world, because it meant there
was a little bit of behavior now happening automatically.
| | 02:45 | But if you didn't understand what that behavior
was, it wasn't clear how your properties worked.
| | 02:50 | So, this is the second thing I'll talk
about on its own and talk about these synthesize
| | 02:55 | statements and the current best
practices with them in just a moment.
| | 02:59 | But first, let's finish clearing the decks.
| | 03:01 | Xcode 4.5, this was the first
version of Xcode to work with iOS 6 SDK.
| | 03:08 | The two main points here, LLDB is now the
default debugger in Xcode to bring us in line
| | 03:13 | with using LLVM as the default compiler.
| | 03:17 | And AutoLayout, a new layout option that had
been available in Cocoa desktop development
| | 03:22 | for a while is now supported and
is actually the default in iOS.
| | 03:26 | And AutoLayout will be the
third thing I'll cover separately.
| | 03:29 | And that brings us to Xcode 4.6, no huge changes here,
some general improvements in the compiler and debugger.
| | 03:38 | You can do things like inspecting the elements
inside NSArrays and NSDictionaries and the debugger.
| | 03:44 | Okay, if you're coming from another
language, you might think, big deal.
| | 03:47 | We've had that for years,
well we didn't, and now we do.
| | 03:51 | Now with improvements to the compiler and
debugger, if you know you have older projects
| | 03:56 | that are still set to use the older style GCC and GDB,
know that Xcode 4.6 is the last version to support these.
| | 04:04 | So, be aware that sometime soon, change your
project settings over to LLVM and LLDB, because
| | 04:10 | that is where Apple have planted their flag.
| | 04:13 | Now, all new projects, everything we do in this
course will just use LLVM and LLDB by default.
| | 04:19 | So, I've got three things to cover here,
literals, synthesize, and AutoLayout.
| | 04:25 | Let's do literals first.
| | Collapse this transcript |
| Using Objective-C literals| 00:00 | Objective-C Literals syntax is great and
something that you are likely to use in everyday code.
| | 00:05 | But let me be clear, what I am about to show
you doesn't give you any new capability you
| | 00:10 | didn't already have, but it does make it faster
and easier to write code to create common objects.
| | 00:16 | And you have already used this idea with NSString,
if you've ever written a line of code likes this
| | 00:22 | where you didn't say alloc and init or any
variant of that, but you still end up with
| | 00:27 | a NSString object because the at sign here is
telling the compiler to go ahead and create
| | 00:32 | that NSString object with these contents, it's a shortcut
format to make it easier for you to create NSStrings.
| | 00:39 | Now this syntax has been expanded to include
NSArray, NSDictionary, and NSNumber objects.
| | 00:46 | And as with NSStrings, it's all about the at sign.
That is the indicator to the compiler that
| | 00:51 | you are about to begin using the literal syntax.
Let's see some before and afters.
| | 00:58 | So I've just got some simple code here inside
a basic Command-line tool, and let's take the
| | 01:02 | good old NSArray on line 22 here.
| | 01:05 | This is the format used by many years of
Objective-C developers, creating Arrays with the method
| | 01:11 | alloc and init with objects or perhaps
using array with objects, and you are providing
| | 01:16 | a list of those objects, although taking
care to terminate that list of objects with nil.
| | 01:21 | This is how you have to tell the NSArray that it's
finished, that you've provided all the objects for it.
| | 01:27 | And the objects I am passing here are just
the ones I am creating on line 17 through 19,
| | 01:31 | just basic NSString and NSNumber.
| | 01:33 | Well, this is now the alternate
way of creating an NSArray.
| | 01:38 | I first define the pointer to it, NSArray *myArray=
then I use the at sign, and I need
| | 01:45 | to open up the square bracket here.
| | 01:48 | And it gives me the little pop-up code sends
that I just need to provide a list of objects.
| | 01:53 | So I will, I have a few that I am creating
on those earlier lines, and then I am done,
| | 01:59 | I just close the square
bracket and finish the line.
| | 02:02 | I no longer need the alloc, I no longer need init
with object, and I no longer need the nil at the end.
| | 02:08 | Now once again, this is not a new kind of NSArray,
this doesn't provide anything different, it's
| | 02:13 | simply more concise, this is
easier to write and easier to read.
| | 02:16 | Now just as there is that syntax to create
them, there is also a shortened syntax to
| | 02:22 | access the elements inside an
NSArray once you've actually got one.
| | 02:26 | Now this is the conventional format that you're probably
used to already, using the objectAtIndex method of NSArray.
| | 02:34 | Well, this is the new format, name of the
array and then as in many other programming
| | 02:39 | languages, we can just use the square brackets here
and give it the number of the element that we want.
| | 02:44 | So if I want the second element, that's
going to be number 1, zero based of course, again
| | 02:49 | just simply a concise way to do this.
| | 02:52 | Now one of the objects I am adding to this
array here--this baz object--is this one that
| | 02:56 | I am creating on line 19, and it's an NSNumber.
| | 02:59 | Because if you just want to put say a basic
primitive value like an integer or a float
| | 03:04 | inside a collection, you can't. You need to box
it up, you need to make it a proper Objective-C
| | 03:09 | object, and that's what NSNumber is for,
it's a wrapper for a primitive value.
| | 03:14 | So we commonly use methods like this,
creating an NSNumber with numberWithInt.
| | 03:19 | Although there is lots of these methods
numberWithChar, numberWithFloat, numberWithLong.
| | 03:24 | Well, NSNumber gets a literal syntax too, so I
want to create a new NSNumber with the integer 99.
| | 03:30 | All I need to do is use the at sign and the
number, and it's smart enough to understand
| | 03:37 | whether we are providing an Int
or a Float or a Double and so on.
| | 03:40 | So for an integer, this is
just like using a number with Int.
| | 03:44 | If I passed in 99.345, that would be like
using number with double, I'd add the F if I want
| | 03:50 | it to make it a float explicitly.
| | 03:53 | Now sometimes NSNumber is used to wrap a
Bool primitive so you can also use Bool values,
| | 03:59 | just an uppercase YES or uppercase NO.
| | 04:02 | Don't need any square brackets, don't need
any double quotes, we just use the at sign
| | 04:07 | and the value, it's as simple as that.
| | 04:09 | And finally, we have NSDictionary,
a set of key value pairs.
| | 04:13 | So we are not accessing the elements
by number, we are accessing them by key.
| | 04:17 | And there is a few different ways to create
an NSDictionary, but very commonly you'd see
| | 04:21 | using this method, using it together
with alloc and initWithObjectsAndKeys.
| | 04:25 | Now I've always found this format quite
clunky and unintuitive because it is written
| | 04:31 | as key value pairs, but it's written as the value--
say iOS SDK New Features--followed by the key
| | 04:39 | which is kind of unusual.
| | 04:40 | More conventionally across multiple
programming languages, it's key then the value.
| | 04:45 | So I am providing four sets of key value
pairs here, and then you also have to terminate
| | 04:52 | an NSDictionary with nil.
| | 04:53 | There is going to be a lots of
problems if you don't do that.
| | 04:57 | So let me comment that one out and
show you the new way of doing it now.
| | 05:06 | Once again using the at sign, but this time
we are not using the square brackets, we are
| | 05:10 | using the curly braces, and if you see the pop-up
here, I can see the close to this literal syntax.
| | 05:15 | We've got the NSString is using the double
quotes, we've got NSArray is using the square
| | 05:20 | brackets, and we've got NSDictionary is using the
curly braces with pairs of keys colon object comma.
| | 05:28 | So we just give it repeating
pairs of keys and values.
| | 05:32 | I'll just scroll up to give myself a bit
more room here, and I'll split this across lines
| | 05:36 | so it's a little more readable.
| | 05:42 | And this is the new NSDictionary literal
format, it's using the key then the value,
| | 05:47 | the more conventional way to write these,
and I just provide pairs of these.
| | 05:50 | All right, so I am just going
to paste in a little code here.
| | 05:56 | So I've split these on multiple lines so they
are more readable, I am just giving it multiple
| | 05:59 | pairs of keys values, here I am actually
using the NSNumber literal syntax to just pass in
| | 06:05 | directly the number 2013
and a Boolean value of YES.
| | 06:09 | We have the closing curly
brace, and we finish the line.
| | 06:12 | As with the NSArray literal format, a nil is no
longer needed to terminate the NS dictionary.
| | 06:17 | We just finish writing the key value pairs.
| | 06:20 | And also adds with NSArray we have a
shorter way of getting to the values inside there.
| | 06:25 | This is the conventional way of accessing
an element in an NSDictionary, we use the
| | 06:30 | value for key method, and this is the new way.
| | 06:36 | The name of the dictionary and while we
create it with curly braces, we access the elements
| | 06:41 | using the square brackets,
the subscript operator.
| | 06:45 | Same is with an array and same is in many
other languages, and I just provide the key
| | 06:50 | to that element, so author for example.
| | 06:54 | And this could be a separate independent NSString object.
I am just using NSString literals for the sake of time.
| | 07:04 | So if I go ahead and run it, well, I see I
am actually mismatching my own values here,
| | 07:07 | I am saying the title is but also writing
out the author, so let's try and pass
| | 07:13 | in a different key, and that's
what I'd expect to see here.
| | 07:18 | So to summarize NSString literal format which
you've used before is the at sign and the double
| | 07:25 | quotes, whatever you want inside that.
| | 07:28 | The NSArray is the at sign and the square
brackets and your list of objects inside that,
| | 07:34 | the NSDictionary is the at sign and the curly
braces, and the NSNumber is just the at sign and the
| | 07:39 | primitive value that you want to box up.
| | 07:41 | And one thing worth mentioning, when I say
they've added the syntax for creating NSArrays
| | 07:46 | and NSDictionaries and NSNumbers, I don't
mean those classes and all the other things
| | 07:51 | just like them like NSSets and NSMutableArrays.
No, those don't support this format.
| | 07:56 | It is just NSArray, NSDictionary,
and NSNumber, at least for now.
| | Collapse this transcript |
| Current usage of @synthesize| 00:00 | When defining properties in your classes
like this very simple Objective-C class I have
| | 00:05 | here, it became common behavior for Objective-C
developers for many years to get into the following habit.
| | 00:11 | You'd write the property and define it in
your interface and your header file, and then
| | 00:15 | you jump over into the implementation, and you would
match it up with a synthesize statement over there.
| | 00:21 | And what this would do is tell the compiler
to synthesize or generate the instance variable
| | 00:27 | for each of these properties and also create
the standard accessor methods, a getter method
| | 00:32 | and a setter method for each property.
Well, you no longer need to do the synthesize.
| | 00:37 | As of Xcode 4.4, writing the
synthesize statement is now optional.
| | 00:41 | So if you've defined the property, and you
don't write the synthesize statement or provide
| | 00:46 | any other custom code for that property, the
compiler will just automatically synthesize by default.
| | 00:52 | However, it's worth understanding a
little more about what the effect of this is.
| | 00:58 | Because if you were previously in the habit
of writing simple synthesize statements,
| | 01:02 | like this where I've got synthesize name and
synthesize hireDate to match my properties and my header.
| | 01:07 | And this for simplicity is what
I typically show in my courses.
| | 01:12 | What this would actually do, say in the case
of hireDate is it would synthesize three things.
| | 01:17 | An instance variable called hireDate, a
getter accessor method which had exactly the same
| | 01:23 | name, hireDate, and a setter method which would
just put the set word in front of it, so set hireDate.
| | 01:30 | But if I delete this line and let automatic
synthesis happen, I may run into a problem,
| | 01:37 | because the automatic synthesis behavior
that's provided by Apple--or rather provider
| | 01:42 | by the compiler--is not exactly the same as just
writing synthesize hireDate or synthesize name.
| | 01:48 | It's more the same as if I've written
this, @synthesize hireDate = _hireDate.
| | 01:55 | Now what this format means for synthesis is
that the synthesized instance variable internal
| | 02:02 | to the class would have the leading underscore.
| | 02:04 | The getter and setter methods will
stay the same, hireDate and set hireDate.
| | 02:09 | So what happened if I was using either that
format manually or leaving it off entirely
| | 02:14 | which is exactly the same as writing that
is it's complaining down here but I am trying
| | 02:19 | to use the format that suggests I am
looking for an internal instance variable,
| | 02:23 | and it no longer has that name.
| | 02:25 | I could actually use _hireDate,
but that kind of reveals a problem.
| | 02:29 | I should really use the proper accessor method
instead of trying to directly get to the instance
| | 02:35 | variable, even internally inside this class.
| | 02:38 | It would be much better practice to either
use self hireDate, the name of the actual
| | 02:44 | getter or alternatively I could use .syntax,
which would also use the accessor method.
| | 02:53 | And if I got rid of the other synthesize,
we'd have exactly the same problem here, showing
| | 02:57 | me that I was using the name of the instance
variable but that now would have an underscore
| | 03:01 | in front of it can I could use the underscore,
but it's the best practice that I would actually
| | 03:06 | use the proper accessor method.
| | 03:10 | So with auto synthesis, if you just let
the compiler do it--and I suggest you do--
| | 03:16 | just know that your instance variable for that
property will be named with a leading underscore,
| | 03:21 | but you should be really using the
accessor methods to get to it anyway.
| | 03:25 | Beyond that little gotcha, nothing has changed.
| | 03:28 | If you need to create non-standard getters
and setters, you can still do that by simply
| | 03:33 | providing your own getter and setter methods.
| | 03:36 | But this is the behavior that you'll get if you just
define your property and let automatic synthesis happen.
| | Collapse this transcript |
| Creating an iOS user interface with Auto Layout| 00:00 | Autolayout was first added to Xcode in 2011,
but at that time it was only for Mac desktop
| | 00:06 | development, not for iOS, and it's an
improved way of how controls on user interfaces can
| | 00:11 | arrange and resize and lay themselves out, and it
replaced the older technique called struts and springs.
| | 00:17 | Now with the release of iOS 6 Autolayout is
also the default method for iOS user interfaces,
| | 00:24 | and it's what we're using in this course.
| | 00:26 | So I'm going to create a classic Single view iOS Application.
I'll just do this for iPhone and use Storyboards.
| | 00:34 | It doesn't matter if you use storyboards or
stand-alone XIB files, it'll work the same.
| | 00:39 | Autolayout is used in both.
| | 00:41 | So if I go ahead and create this and then
jump into the Storyboard, at first glance
| | 00:46 | it doesn't look any different from what we might
have seen in several previous versions of Xcode.
| | 00:51 | But if I select the view Controller--I'll
just click the status bar to see the big blue surround--
| | 00:56 | go over here to the
File inspector, the first one,
| | 01:00 | I should see this check box here to
Use Autolayout, so this is the default now.
| | 01:05 | Now if I turn that off, there is
no visible difference to this.
| | 01:09 | Although I can see down at the bottom of the
canvas that I'm getting a few extra buttons
| | 01:13 | turn up when Autolayout is enabled.
| | 01:16 | But the best way to demonstrate Autolayout is
to first kind of compare to what we had before.
| | 01:21 | I can do that by just
turning this off for a moment.
| | 01:24 | This is going back to the old way that
we've had in Xcode for several years.
| | 01:29 | So I turn off Autolayout, I'm going to go into my
object library here and just drag on a few buttons.
| | 01:35 | Position this one at the top left,
position another one at the top right.
| | 01:40 | Again, this is standard stuff, nothing new here.
| | 01:45 | And drag on a third one, and
I'll put it into the center.
| | 01:48 | We see the usual guidelines to help us put
something in the center or connect it to the
| | 01:54 | left and still keep it a certain gap
away from the suggested iOS guidelines here.
| | 02:00 | Very simple interface, I'm just
going to hit Command+R to run this.
| | 02:04 | It opens up in my simulator here, and
we've got immediate couple of problems.
| | 02:08 | First, the bottom button has completely
disappeared the way I'm looking at it now.
| | 02:12 | Secondly if I change this orientation to
landscape, the button that currently says top right is
| | 02:17 | positioned well more towards the center, when
I'd really want to move it towards the right.
| | 02:23 | So the reason that the bottom button has
disappeared is because I go back into the design here,
| | 02:28 | what I'm looking at is the default view
controller layout which is actually for the iPhone 5,
| | 02:34 | the longer orientation, the 4-inch screen,
but my simulator was set up to run with the
| | 02:38 | older style iPhone with just 3 & 1/2 inches,
so it's disappearing off the bottom.
| | 02:43 | So I'm using the old way of laying
this out, and I could still fix this.
| | 02:47 | What I have to do is go into the size
inspector over here, selecting the different elements,
| | 02:53 | and let's stop manipulating the struts and
springs that we'd see in the Autosizing section
| | 02:58 | to make sure that for example this button
was not hooked up to the top, but it actually
| | 03:03 | had a strut connecting it to the bottom.
| | 03:06 | Struts and springs are like physical idea of
struts and springs in architecture or automobiles.
| | 03:10 | A spring is something that can expand and contract
and a strut is something solid with a fixed width.
| | 03:16 | So I could select this top right button which
currently has struts connecting it to the top on the left.
| | 03:21 | What I'd really want is struts connecting
it a fixed width to the top and the right,
| | 03:26 | I can see the little highlight that it should
be dragged to the right as this screen either
| | 03:31 | resizes, while we don't resize on iOS,
but we do change with orientation.
| | 03:37 | If I'd worked with the springs, which are the things
inside the box, we'd see it actually grow and shrink.
| | 03:42 | But I'm just going to turn on a couple of
struts there and go ahead and run this again.
| | 03:48 | This looks better, we at least have the bottom
button turning up, and if I switch into landscape
| | 03:53 | view, this is a bit more what we'd want.
| | 03:56 | So I can still fix it the old
way using struts and springs.
| | 04:01 | But Autolayout as you'll see in a moment
is a better way, and it usually works better
| | 04:05 | right out of the box without any manipulation.
| | 04:09 | So I'm going to switch back, so I'm
going to switch this back into Autolayout.
| | 04:12 | So selecting the actual view controller itself,
I'll make sure I have the blue bar here, jump
| | 04:16 | into the File inspector, the
first one, and turn on Autolayout.
| | 04:20 | Now I could keep these controls where they
are, but I'm just going to delete them all
| | 04:24 | just to kind of re-add and prove that they work
differently and drag on a couple of buttons again.
| | 04:30 | Nothing remarkable here, I'm still getting the
guidelines, I can change the text of this button.
| | 04:35 | If I didn't know better, I'd
think it was exactly the same.
| | 04:40 | But the important thing is happening, and
here's what's important about Autolayout.
| | 04:44 | It's not about us dragging on these buttons,
it's not about these guidelines, Autolayout
| | 04:48 | is all about what happens when I let go.
| | 04:50 | And if I let go of this button that's kind
of guided to the top and the right, what I'll
| | 04:55 | see is two lines appear over
here on the top and the right.
| | 04:59 | These are what are referred to as
constraints, and Autolayout is all about constraints.
| | 05:05 | They describe a relationship
between two visual elements, two views.
| | 05:09 | So we can have a constraint between a button
and the top of the view that it's contained
| | 05:14 | in or a constraint between the right-hand
side of the button and the right-hand side
| | 05:19 | of the view that its contained in.
| | 05:20 | You can also have a constraint
between two elements of the same level.
| | 05:24 | So if I drag another button beneath this one,
we get a little constraint is appearing--
| | 05:29 | little difficult to see there--
but between the two buttons.
| | 05:33 | Constraints are actual objects in
Objective-C, it's the NSLayout constraint objects.
| | 05:38 | They're added by interface
builder as we edit our XIB files.
| | 05:42 | You can also manually write them in code, but
that's not what we're going to do in this course.
| | 05:45 | So when Autolayout is turned on, if you
click a user interface element like a button,
| | 05:50 | you will see all the constraints
that are attached to that object.
| | 05:55 | You can then actually click the constraint
itself, sometimes a little difficult to click
| | 05:58 | because they are so small and an amber highlight will
appear to show you what objects that constraint applies to.
| | 06:05 | Now as a side note, it's a common gotcha when
you're new to Autolayout to accidentally have
| | 06:09 | a constraint selected when you think you
have a button or something else selected.
| | 06:13 | So if you see the amber highlight, know
that you have a constraint selected, you don't
| | 06:17 | want to be trying to Ctrl-drag from a constraint into our
code file when you think you're Ctrl-dragging from a button.
| | 06:25 | So constraints highlight in amber, regular UI
elements highlight in blue as they have done always.
| | 06:30 | Now you can also get to these
constraints using the dock or the jump bar.
| | 06:35 | If I open up this doc here I'll see there
is a section called constraints, and I can
| | 06:39 | drill through each individual one.
| | 06:41 | You see there are different kinds of constraints
here, vertical space, or horizontal space constraints,
| | 06:46 | they're highlighting as I click around them.
| | 06:48 | And selecting each one will show
you which elements it applies to.
| | 06:53 | If I drag another button down here towards
the bottom, and I want to position it in the
| | 06:57 | center, if I use these guidelines here,
I'll get another kind of constraint,
| | 07:02 | a Center X Alignment constraint, that they are
actual first-class objects in Objective-C.
| | 07:07 | Now if I select any of these user interface
elements and then jump into the Size inspector
| | 07:11 | where we used to see struts and springs in
the Autosizing section, we don't see that
| | 07:16 | anymore but we will see a Constraints
section if that element has constraints on it.
| | 07:21 | So it's telling you I have a constraint in
the top space to the button above it and in
| | 07:25 | the trailing space which means the space to
the right-hand side to the Superview, Superview
| | 07:30 | meaning the container that this is
sitting in the actual window view.
| | 07:34 | And when you actually select a constraint itself,
you can even edit it in the Attributes inspector.
| | 07:40 | It's a true object like all other objects are.
| | 07:44 | Here's the thing, most of the time you
don't add constraint yourself, you let Xcode
| | 07:49 | do it as you're setting out your interface.
| | 07:54 | And Xcode makes a really good guess
where the constraint should be added.
| | 07:58 | As you move elements around, it tries to create the
minimum number of constraints based on your arrangement.
| | 08:03 | If you drag to the left-hand side, you'll get a
constraint between the left-hand side and the top.
| | 08:08 | As I stop moving towards the bottom, it thinks
that it's more important to have the constraint
| | 08:13 | between the bottom and the left-hand side.
| | 08:16 | If I move it underneath another element, it
assumes that the constraint that's important
| | 08:21 | here will be a constraint
between the two elements.
| | 08:25 | Sometimes you have to drag or re-drag an element
around to get the constraint that you're expecting,
| | 08:30 | but you can usually get it.
| | 08:31 | Now I've got too many buttons here, so I'm going to
drag on something a bit more interesting like a Text view.
| | 08:41 | The guidelines are still very useful and
they will help you in adding those constraints,
| | 08:45 | so I'm dragging this one down, waiting to see
it snap near the button, and that should do it.
| | 08:51 | Go ahead and test this again, seems okay in
portrait, and it also seems okay in landscape.
| | 08:59 | However, I actually don't even need to wait
that long, I don't need to run it to see this
| | 09:03 | because the Autolayout impact is
visible in the designer itself.
| | 09:07 | If I selected the entire view controller
just by clicking status bar, jump over here into
| | 09:11 | the Attributes inspector, I can change the
orientation to landscape and those constraints
| | 09:16 | will take effect here as well.
| | 09:19 | So what you're hopefully noticing is Autolayout
is working pretty well straight out of the box.
| | 09:24 | I don't have to change anything the way that
I had to change things with struts and springs
| | 09:29 | just to make even a very basic layout like
this work the way I typically want it to work.
| | 09:34 | So let's do something a
little bit more involved.
| | 09:37 | I am going to imagine that perhaps this screen
is a terms of use that somebody has to agree on.
| | 09:42 | I have to click a button that says Yes,
which is right there in the center, and then
| | 09:46 | I'm going to put another button
beside it to say that they disagree.
| | 09:51 | So drag on this button, I'll use the snapping
guidelines to give me the right size and give
| | 09:56 | it a long title like, No, I totally disagree.
| | 10:00 | Now perhaps you'll notice that as I did that
it did resize the button the way that you'd
| | 10:07 | hope it would, but it is keeping it to the
right-hand side of this Yes button, because
| | 10:11 | yes was dragged to the center and has that
Center Constraint which is regarded as important.
| | 10:16 | So I'm going to go ahead and run this again,
and it opens up in portrait view and really
| | 10:23 | doesn't look all that good.
| | 10:24 | That button is moving
off to the right-hand side.
| | 10:27 | The reason for this is that the only
constraints we actually have down here is that
| | 10:32 | the Yes button has to be in the center and then there
is another constraint in between the buttons
| | 10:37 | to say that the No, I totally
disagree is to the right of it.
| | 10:41 | There is no constraint on the right-hand side
of this button, so there is nothing that would
| | 10:46 | stop it from moving off the side of the screen.
| | 10:49 | Now there are of course multiple ways I could
arrange these buttons, I'd probably just drag
| | 10:53 | them to the right-hand side and make a
constraint appear on that right-hand side,
| | 10:58 | but let's say what I've decided I really want this
Yes button in the center where possible, but only
| | 11:04 | as long as it's not pushing the
disagree button off to the right.
| | 11:07 | Well, I can do that, I just need to play
a little bit with some manual constraints.
| | 11:12 | So I can add a manual constraint to the right-
hand side of this disagree button, what's referred
| | 11:17 | to as the trailing side.
| | 11:19 | Again by selecting the button I see all the
constraints that are currently here, there
| | 11:23 | is one connecting it to the next button, there
is one hooking it up to the bottom, but that's it.
| | 11:28 | So here is how I connect one on this
side, I create a new manual constraint.
| | 11:32 | With that selected, I go to the Editor menu,
come down to Pin, and what I'm looking for
| | 11:37 | is this option, Trailing Space to Superview.
| | 11:41 | Trailing space is the right-hand side of this
element, Leading Space would be the left-hand
| | 11:45 | side, Top Space is the top of the
element, Bottom Space the bottom.
| | 11:48 | And we're doing it to the Superview because it's
the container, it's the window that this is inside.
| | 11:53 | So I click that, and you will see the
constraint appear on the right-hand side.
| | 11:57 | All right, let's see what impact that has.
| | 11:59 | I'll run it again, and we're
still having problems here.
| | 12:05 | It's not moving off the right-
hand side, but it's not a lot better.
| | 12:09 | If I just perhaps have the
word no, it might be fine.
| | 12:11 | Here is what's happening, the three constraints
that we have are saying have this yes button
| | 12:16 | in the center, have a gap between the buttons,
and have a gap between the right-hand side
| | 12:21 | of the button and the right-hand side of the screen.
| | 12:24 | So the only thing left to do is shrink
the button, which is what iOS is doing.
| | 12:29 | So not really what I wanted.
What might we do here?
| | 12:32 | Now the reason for that happening, if I
select that right-hand constraint here and go to
| | 12:38 | the Attributes inspector, what it's telling
me is this constraint is a horizontal
| | 12:42 | space constraint, no surprise there.
But we've got a few options here.
| | 12:46 | What's happening is it's saying this is a
space constraint that must be equal to a Constant
| | 12:50 | of 79, so it's a fixed-width constraint,
and it's not really what I want, I don't need
| | 12:56 | this to be always 79 points in the edge,
I just need it to be at least a little gap.
| | 13:02 | Now the question is, well, what amount? What
amount does it have to be from the edge of
| | 13:07 | the screen, what is it, 20 pixels, 40 pixels, what
would it be on a retina display versus a normal display?
| | 13:12 | Well, I don't really care and
luckily I don't have to care.
| | 13:15 | What I can do is with that constraint selected
so that I want this relationship, I want this
| | 13:21 | space to not just be equal to but either
greater than or equal not 79, but I'm going
| | 13:26 | to click this Standard button, that's an
automatic gap between the right-hand side of the view
| | 13:32 | and the right-hand side
of the button that it's in.
| | 13:35 | So I'm going to go ahead and run this, and
it's a little better but still not what I want.
| | 13:42 | So right now what we're getting is the
constraints as it has to be at least the Standard gap
| | 13:46 | between the right-hand side and
edge of the button, that's fine.
| | 13:49 | But there is also the constraint that says
Yes is in the center, and there is also the
| | 13:52 | constraint that says there must be a gap between
the button, so we're still shrinking that button.
| | 13:57 | So what else can we do?
| | 13:59 | Well, this is where we can start to play
around with the more advanced part of constraints
| | 14:02 | which is the priority of them.
All constraints have priorities.
| | 14:07 | If I actually select the individual ones,
with this Attributes inspector open I can
| | 14:13 | see they all have this priority, and
by default they're all set to 1,000.
| | 14:17 | So one between the buttons, that's 1,000.
| | 14:21 | The Center Constraint here has a priority
of 1,000, and that means they're all equally
| | 14:26 | important, and I want to
say that's not the case.
| | 14:28 | Now there is a few ways you might approach
this, but if I say, well, really what I want
| | 14:33 | to describe is I'm saying I want the Yes
button to be in the center where possible.
| | 14:38 | But if it's not possible to be in the
center, it's okay that it moves off there.
| | 14:42 | So what I want to say is that this center
priority is actually less important than
| | 14:48 | the gap between the right-hand
side of the disagree button.
| | 14:50 | So I'm going to highlight this center one
and take this priority down a bit, and there
| | 14:57 | is actually multiple levels you can take it
down and Xcode will give you a bit of a hint
| | 15:02 | as to how this might impact the design.
| | 15:05 | I'm going to take it down to just
priority 470, go ahead and run this again.
| | 15:11 | Now this is looking a lot better, looks
okay in portrait but if we go back to landscape
| | 15:18 | where there is a bit more room, it's
going to move that into the center.
| | 15:22 | So we haven't gotten rid of that Center Constraint, we've
just said it's less important than the other constraints.
| | 15:28 | And what you'll find is that when you start
working with multiple constraints that are
| | 15:31 | kind of impacting each other, that working
with priority is really the best thing to do.
| | 15:36 | Now sure, okay, I have presented
a pretty contrived example here.
| | 15:40 | I could have laid this out perfectly well
by just repositioning these buttons without
| | 15:44 | having to bother with adding manual
constraints, and you'll find you're capable of getting
| | 15:49 | a great deal of layouts to work
without adding manual constraints.
| | 15:52 | And yes the first time that you need them,
you will end up experimenting with different
| | 15:56 | constraints and priorities to get your
custom layout working the way that you wanted.
| | 16:01 | But unlike a desktop, you don't have to cater
for endless amounts of possible window sizes,
| | 16:07 | it's really just the transition from iPhone 5
to classic iPhone orientation or from portrait
| | 16:13 | to landscape on iPhones and iPads.
| | 16:16 | But this is the basics of Autolayout, it
often just works immediately in situations that
| | 16:21 | would have required struts and
springs to be manipulated beforehand.
| | 16:26 | But it's very flexible, and it's configurable
in the interface designer, and it allows us
| | 16:30 | to create interfaces that previously
would often require writing code to handle
| | 16:35 | orientation changes in different screen sizes.
| | Collapse this transcript |
|
|
2. iOS Collection ViewsIntroduction to iOS collection views| 00:00 | Collection views are new in iOS 6, and
these are actually my favorite part of iOS 6.
| | 00:05 | We've had Collection views for Desktop Cocoa
development for a while but not in iOS until now.
| | 00:11 | Though if you've used them in Cocoa, they
are not exactly the same as things rarely
| | 00:15 | carry over exactly from Cocoa.
But what are Collection views?
| | 00:20 | Well, in iOS, we've always had the UI Table view.
| | 00:23 | This has been the classic data-driven
control, whether on iPhone or iPad.
| | 00:28 | Table views are used in everything, they're in
the settings app, they're in the mail application,
| | 00:32 | they're in the music application, you can
have them in your own applications of course.
| | 00:37 | These can be styled to make them appear with a
different look, but it's always a good old UI Table view.
| | 00:42 | It's always one column wide, it's got multiple
rows, but importantly it's a data driven control.
| | 00:49 | You are not explicitly laying out these
rows manually in Xcode, this is dynamic.
| | 00:56 | You setup the template for these rows, and
then you write code so that when your application
| | 01:00 | runs, you're providing the contents of each
item, each individual cell and what's in it,
| | 01:06 | whether it's a piece of text or a title and
a subtitle or a button or an image as well
| | 01:12 | or several pieces combined.
| | 01:14 | So these don't go away,
we still have Table views.
| | 01:17 | But with the new iOS Collection
views, we have another option
| | 01:21 | where we're not limited to one column of rows.
| | 01:24 | So this new Collection view is a data-driven
control like Table views but where we have
| | 01:30 | much more flexibility how to set up these items.
| | 01:33 | Not just a collection of rows, but we can have rows
and columns, we could have a classic grid-based layout.
| | 01:39 | Well, it wouldn't have to look as formalized
as a grid like this, we could use it to set
| | 01:44 | an interface like this or we could use it
to take these items and group them together
| | 01:49 | and stack, so we could show them in a
circle or however you'd want to do them.
| | 01:54 | Collection views support all this, and
it means you can create better layouts.
| | 01:59 | You could create application like say the
Bookstore application on the iPad, either
| | 02:04 | the Library view of it where we've got
multiple grid style rows and columns here,
| | 02:11 | but perhaps the Bookstore app itself.
| | 02:12 | Each of these items is dynamic, they weren't
setup manually in an interface builder file in Xcode.
| | 02:19 | Another example would be something
like the World Clock app on the iPad.
| | 02:23 | This is an interface that is built in
columns and rows, it doesn't have to be exactly the
| | 02:28 | same thing for every column.
We can choose how these would be represented.
| | 02:33 | So you might use them to create something
like the App Store, you might use them to
| | 02:37 | create something like the Photos application
where you have a very even grid-based layout here.
| | 02:42 | Although in the Photos application we could
choose to view the photos this way, we could
| | 02:46 | also choose to view them in stacks, and
Collection views would support you doing either of these.
| | 02:52 | Now, these kinds of applications could have
been done before Collection views came along,
| | 02:57 | but it usually required a lot of code.
| | 02:59 | What we have now is the Collection views provide
a framework for building these kinds of screens,
| | 03:05 | these kinds of layouts.
So how do we get started?
| | 03:08 | Well, know that the Collection view is similar
to UI Table view, though it doesn't replace it.
| | 03:13 | But if you know how to use the
Table view, you're after a good start.
| | 03:17 | And I'm actually going to assume here that you do know
at least the basics of working with UI Table views.
| | 03:22 | That when you've got one, these are controls that
themselves, they don't store the data, they just show it.
| | 03:28 | They need to be connected to a data source class,
some code that will provide the data for each element.
| | 03:35 | For a Table view it's how many rows
does this have and what is in each row?
| | 03:40 | And they're also connected to a delegate class to
say what happens when one of the rows is selected.
| | 03:46 | The data source code and delegate code could be in
the same external class, but they don't have to be.
| | 03:51 | So this is the way Table views work,
Collection view is very similar to this.
| | 03:55 | So some important concept and
terms to let us get started.
| | 03:58 | Our Collection view is not limited to a grid-
based layout, but that's certainly the most
| | 04:03 | common usage of it, so
it's the one we'll explore.
| | 04:07 | So there is this idea of a Collection view,
the UICollectionView class, it's the container.
| | 04:12 | It shows nothing by itself, it
expects to contain multiple items.
| | 04:17 | Now you provide these items by connecting
it to a data source like with a Table view.
| | 04:23 | You have a class that's going to tell this
Collection view how many items it has and
| | 04:27 | what each item is and there are
specific methods to supply that.
| | 04:32 | And these items are
whatever you want them to be.
| | 04:34 | They could represent photos, documents,
audio files, or video files, some kind of custom
| | 04:39 | object or all of the above, whatever that
means for your application as long as it can
| | 04:44 | be given some kind of visual appearance.
| | 04:47 | And each item is considered a cell,
a UICollectionViewCell object.
| | 04:53 | Again it's your job to provide these cells just
as it is to provide the data in a UI Table view.
| | 04:59 | Now however, with a Table view there is a
default layout for a single cell, whereas with
| | 05:05 | a Collection view, there isn't a default cell.
You need to say what this look like, and we'll
| | 05:09 | see how to do that shortly.
So the data source can provide all these cells.
| | 05:13 | Now these cells, these items, can be
exactly the same size, but they don't have to be.
| | 05:18 | They can be large, small, or a variety.
| | 05:20 | You might have a dozen, you might have 10,000,
and the Collection view will take care
| | 05:25 | of arranging them, that's what it does.
| | 05:27 | But because this same Collection view
could arrange this in multiple ways--they could
| | 05:32 | be in stacks, they could be in circles, they
could be in the basic grid layout--the Collection
| | 05:37 | view uses something called a layout object.
| | 05:41 | These are the rules, this defines the rules
for how these items, these cells, are laid out,
| | 05:47 | how much spacing should be between the items,
are there headers and footers to show?
| | 05:52 | The default provided layout object
is what's knows as a flow layout.
| | 05:57 | This provides all the rules for creating
a grid style system of rows and columns.
| | 06:01 | Well, that doesn't give the
full idea of what it's capable of.
| | 06:05 | As you'll see in a moment,
it's very customizable.
| | 06:08 | But you can even define your own layout objects, your
own sets of rules for the Collection view to follow.
| | 06:15 | So here is the basic idea.
| | 06:16 | You add a Collection view to
your interface, it's the container.
| | 06:21 | You write some data source code to provide
the items, the cells for that Collection view.
| | 06:27 | And the CollectionViewLayout object says how
this should be arranged while it's the Collection
| | 06:32 | view itself that will actually do the arranging.
| | 06:35 | And because you want to be able to interact
with this, to touch items, to select them,
| | 06:39 | to scroll up and down or side to side, you'll
also provide a delegate object for this Collection
| | 06:45 | view, and there you write code to respond
to those events like selecting something.
| | 06:50 | So, okay, there can be more to it.
| | 06:52 | We can split things up into sections, we can
talk about having background images and headers
| | 06:58 | and footers and so on, but this is the
core of working with Collection views.
| | 07:02 | So let's start with this, and
we'll add the other things as we go on.
| | Collapse this transcript |
| Adding and configuring a UICollectionView| 00:00 | I am going to create a new project and add
all of the basic elements of a Collection
| | 00:04 | view scenario and get them
all talking to each other.
| | 00:07 | This will be simple, but it's going to have
all the necessary parts and will get more
| | 00:10 | complex in the following movies.
| | 00:13 | So in Xcode, I will create a new iOS
application, it will be a single view application.
| | 00:18 | Now, while Collection views can do more
impressive things on the iPad, simply for space issues
| | 00:24 | I'm going to use the iPhone as it's more visible
in a recording like this with a reduced screen size.
| | 00:30 | So call it CollectionDemo, it will be for the iPhone
with storyboards and automatic reference counting.
| | 00:37 | And I will jump into the main storyboard
where I just have the single view controller here.
| | 00:42 | So right now there's nothing
to do with Collection views.
| | 00:45 | So I am going to come over
here into my Object library.
| | 00:49 | And if down here in the Filter box I will
type in the word Collection, you'll see a
| | 00:53 | few options appear, Collection View Controller,
Collection View, View Cell, and Reusable View.
| | 00:59 | What I want to add is the Collection View itself,
I am not adding the Collection View Controller
| | 01:04 | that would add another view control,
another screen, not that that would be bad,
| | 01:09 | but I just want to add one to this
of view controller I already have.
| | 01:13 | So grab the Collection View, drag it over and try
and position it somewhere in the center here.
| | 01:19 | That will have to do.
| | 01:23 | And when I drag this on, it's
invisible, it doesn't show me anything.
| | 01:27 | If I expand the dock on the left-hand side,
well, I can actually see here that I've really
| | 01:32 | gotten three things, I have had a Collection View
that has been added as well as a Collection View Cell ,
| | 01:38 | and the Collection View Flow Layout,
that's the layout object, the predefined rules
| | 01:44 | for a grid-based layout in a Collection view.
| | 01:47 | So it adds this one cell, and if I select that I
can see it highlighted over here to about 50x50.
| | 01:54 | This is not an actual item, a cell is a
placeholder, it's a template for an item.
| | 01:58 | You're going to have to write code to say how many of
these there will actually be when the application runs.
| | 02:04 | As with Table views, cells and collection
views are intended to be reusable objects.
| | 02:09 | So if we have 10,000 pieces of data that
might be shown in this application, but only
| | 02:15 | 20 cells can fit on the screen at any one time,
we'll actually keep reusing the same cell objects,
| | 02:20 | just swapping out the data
inside them as we scroll up and down.
| | 02:24 | And just so we'll be able to make this
visible, I am going to go into my Inspectors here,
| | 02:29 | making sure I have the cell selected.
| | 02:33 | I am going to change its
background to a light gray color.
| | 02:36 | And again, making sure it's the cell that's selected,
I am going to come here to the Reuse Identifier section.
| | 02:43 | This is the same as having a
Reuse Identifier for a table view.
| | 02:48 | I'll type in demoCell, it doesn't really matter
what you call it as long as its name you remember.
| | 02:53 | The idea here is that you might have multiple
cell templates, you might have different cells
| | 02:58 | for say book products and other ones for album
products and other ones for software products,
| | 03:04 | so you may have several different configurations,
and you can give them all their own unique
| | 03:08 | name so that you can reuse different ones
later and get the right one at the right time.
| | 03:13 | But for right now all I need to do is have
some identifier string in here of my own choosing.
| | 03:19 | Now if I just go ahead and run this, I have
all the necessary actual UI pieces, but it's
| | 03:25 | not going to do anything at all because
we're not providing the necessary data source.
| | 03:31 | We don't see anything, not even
that one cell that was in the design.
| | 03:35 | That's because we're not providing the
necessary data source, we are not saying
| | 03:41 | does this have any data in it, does it have
any cells, does it have any items?
| | 03:45 | The collection view needs to be hooked up
to an object to provide this information.
| | 03:49 | If I select the Collection View in my dock here--
and I am going to go over to the Connections inspector--
| | 03:54 | I see two outlets here for dataSource and delegate.
| | 03:59 | The most important one right now is
dataSource, but I am going to hook both of these up.
| | 04:03 | Now this is virtually identical to working with the
Table View Controller in previous versions of iOS.
| | 04:09 | I need to connect these outlets to a class.
Now I could create a new class and connect it
| | 04:13 | to that, but for this demo I am just going
to tell the Collection view to look for this
| | 04:17 | code in the current view controller.
| | 04:18 | So I am going to drag over the dataSource,
click and drag over to View Controller and
| | 04:24 | let go and do the same with the delegate,
click and drag over to View Controller and let go.
| | 04:30 | What that means is this Collection View object
is now going to look into the View Controller
| | 04:35 | implementation code to find the information
about how many cells do I have and what's in each cells.
| | 04:40 | It's going to look for specific
methods, and I'll be writing the code in these files.
| | 04:46 | Well, the first thing that I need to do--
I don't have to do it, but it's good practice--
| | 04:51 | is to jump into the view Controller header
file and say that I'm going to support those
| | 04:55 | delicate protocols, I am going to be both a
dataSource and a delegate for that collection view.
| | 05:01 | So let's start typing in UICollectionViewDataSource, and
it appears, hit Enter comma UICollectionViewDelegate.
| | 05:12 | By doing that, if I was to go ahead and build
this project, what I'd get is a few warnings
| | 05:16 | here of the incomplete implementation.
| | 05:19 | I haven't supported the
methods that I said I was going to.
| | 05:23 | There are actually three warnings here saying
you haven't provided the numberOfItemsInSection
| | 05:28 | for the Collection view, and you also haven't
provided the collectionView:cellForItemAtIndexPath.
| | 05:35 | Again if you're familiar with working with
Table views, you'll see that these are very
| | 05:39 | similar methods to what we are used to.
| | 05:42 | Okay, so I can do that now, I'm in my implementation
file, I'll just type the dash and collectionView,
| | 05:49 | I am looking for a
numberOfItemsInSection, there it is.
| | 05:53 | There's a quite a few methods here, so it
might take you a second to find the right one.
| | 05:59 | It's also now complaining I need to support
collectionView:cellForItemAtIndexPath so I'll
| | 06:05 | do that as well -collectionView, there we go,
it's the second one from the top for me,
| | 06:13 | cellForItemAtIndexPath.
| | 06:17 | So I have these method signatures now,
but I need to say what they actually do.
| | 06:21 | This first one for collectionView:
numberOfItemsInSection needs to return an NSInteger.
| | 06:28 | It's simply saying how many items do I have?
| | 06:31 | Like a table view, a collection view can be
split into multiple sections to group
| | 06:36 | some of these items together.
| | 06:37 | I didn't do that, so I just have one section,
and that's actually the default, I don't have
| | 06:42 | to say I have one section.
| | 06:44 | If I don't say anything,
it's assumed I have one section.
| | 06:47 | For the purposes of this demo I am just going
to say return 15, I'm going to say I have 15 items.
| | 06:52 | Well, next, I have to describe them all.
| | 06:57 | This method will be called automatically once
for that section, it will say you have 15 items.
| | 07:02 | What will then happen is this
method gets called 15 times.
| | 07:07 | Passing in an index path and asking what's at position
one, what's at position two, what's at position three?
| | 07:13 | And this is the more important, more
involved method, this is where we have to return the
| | 07:19 | actual cell, you can see the
return type is a UICollectionViewCell.
| | 07:24 | Now as I mentioned earlier what we do
here is like what we do with table views.
| | 07:28 | Before just creating a new cell object, we
can ask the Collection view if it has any
| | 07:34 | cells it's not showing, is
there anything we can reuse?
| | 07:43 | So I will create a new pointer for a UICollectionViewCell
object, and instead of saying alloc and init
| | 07:50 | I am going to talk to the collectionView parameter
that was passed in and call its method,
| | 07:57 | dequeueReusableCellWithReuseIdentifier,
| | 07:59 | again, very similar to
working with a table view.
| | 08:01 | We are asking do you have any reusable cells?
Do you have any cells you're not using right
| | 08:06 | now that we should use instead
of instantiating a new object?
| | 08:10 | Now, what I have to do is pass
it a string, that identifier.
| | 08:14 | If you remember in the
storyboard I called it demoCell.
| | 08:18 | Now I also have an index path, and that parameter is
just passed into this method so I'll just reuse that.
| | 08:23 | I'm not actually going to create different
items for each of these, I am just going to
| | 08:28 | pass back 15 of the same item, but we do
have that index path parameter so that we could
| | 08:34 | change and write more substantial code here to
create different kinds of objects and pass them back.
| | 08:40 | Now if you are familiar with table views,
you're probably looking at this going, okay,
| | 08:43 | it's pretty much the same thing, and what
you'd think I'm about to do next is write
| | 08:48 | a little bit of code like this...
| | 08:53 | Basically asking is there a cell? Do I have
an object? I asked the Collection View to
| | 08:59 | dequeue any reusable cell, but it might not
have had a reusable cell, in which case this
| | 09:04 | would be nil, and I would have to
instantiate one. Well, not anymore.
| | 09:09 | The way that this method works now is it's going to
guarantee that you will get an instantiated object back.
| | 09:15 | It's going to look for a reusable cell,
if there is one, you'll get that back.
| | 09:19 | If there isn't one, it will instantiate one
based on whatever the identifier of that cell was
| | 09:24 | and what that's connected to.
| | 09:26 | In this case, it's from our little
default gray box that's in the storyboard.
| | 09:30 | We'll make a more complex one later.
| | 09:32 | Now when I create a more complex one, if I
had that cell defined and say a separate class
| | 09:37 | and not in the storyboard,
that's completely fine too.
| | 09:40 | I would add one line to register that custom
class with the Collection view so that this
| | 09:45 | same call to dequeue a reusable
cell would know where to find it.
| | 09:49 | Now when we make a more complex cell we might have
labels and buttons and images inside it to configure.
| | 09:54 | Currently this object is really just a plain
gray box. I am just going to return it.
| | 09:59 | I am going to save that and run it,
and it runs, we have 15 items showing up.
| | 10:06 | I could change the orientation, and it
will alter it, and if you notice the layout is
| | 10:10 | We can get an even layout, here three rows of five,
and here we have to have one row of eight,
| | 10:16 | one row or seven, and the Collection View is
doing that based on the rules that are
| | 10:20 | defined in the Collection View
layout object, the flow layout.
| | 10:24 | Let's take it a little further, I am going
to stop this go back in and change this and
| | 10:28 | say I'd rather have 150 objects, and this
is just to show its very simple is going to
| | 10:33 | instantiate a 150 of the same things, but
the collection view itself not only shows them,
| | 10:39 | but it will let us scroll up and down and
handle those object being reused in the background.
| | 10:45 | Once again, switching to landscape,
I can scroll up and down as well.
| | 10:49 | Now while of the collection view is what's
handling the arrangements of these, it's the
| | 10:57 | layout control, the flow layout, that is
actually saying things like how much spacing does
| | 11:02 | there have to be in between these different items?
| | 11:05 | And if I stop this and go back into the storyboard,
I can actually select that Collection View Flow Layout object.
| | 11:11 | it isn't visible here on the View Controller,
but it is a full-fledged object.
| | 11:16 | If I open up my inspector, I will
find a few things I can change about it.
| | 11:21 | One for example is working with the minimum
spacing for cells and for lines, we'll get
| | 11:25 | a bit more into this later, but if I start
to say manipulate it, say 20 for cells
| | 11:34 | and 30 for lines, go ahead and run this.
| | 11:39 | You start to see a
slightly different impact here.
| | 11:44 | Now what you'll find it's very telling that the phrase
that they use here is Minimum Spacing, not exact spacing.
| | 11:51 | Because what it's going to do based on its
own rules is lay them out, it's always going
| | 11:55 | to be at least 20, but it might be a
little more if it thinks that's a better layout.
| | 12:00 | Another option we have here are Section Insets.
| | 12:05 | What that will actually do is create it's
like a padding all the way around the content.
| | 12:09 | So if I wanted to have multiple options
but to have some blank space around the edges
| | 12:14 | of this collection view I could do this in.
| | 12:17 | If you actually watch the gray box as I am
increasing this value, you see it move in
| | 12:21 | from the left or move down from the top.
| | 12:26 | I'll nudge them up on the bottom of the right,
and I'll do one more thing before we go back
| | 12:31 | in which is switching over
here to the attribute inspector.
| | 12:34 | The only option that I have here is for
scroll direction, this is the flow layout,
| | 12:39 | I can change them from vertical
to horizontal, run it again.
| | 12:44 | Now we've got much more spacing going on,
we've got some blank area around the outsides
| | 12:48 | as well, and I don't scroll up and
down, I can scroll left to right.
| | 12:55 | Same if we switch into landscape, we're
scrolling left to right now, but very easy to do,
| | 13:00 | very easy to start configuring.
| | 13:01 | We've got a bit more that we are going to
have to work on if we start to get irregular
| | 13:06 | items here, if they are of different sizes.
| | 13:09 | And sure, there is more to do, we can have
custom cells, we can split this up into sections,
| | 13:13 | we can respond to selection.
| | 13:15 | But this is how we'd get started, to load
the collection view up with a bunch of items
| | 13:20 | and let it take of arranging them, of scrolling them,
of reusing the graphical objects that display them.
| | 13:26 | So next up, we are going to
start making a more complex cell.
| | Collapse this transcript |
| Defining a UICollectionViewCell| 00:00 | When you work with UI Table views, there is
a basic default layout provided for a table
| | 00:05 | view cell with a place for a Title
and a couple of different styles.
| | 00:09 | You can start loading it up with your data.
You can customize it a bit.
| | 00:13 | You can choose to use subtitles or put an
image on the left and a disclosure button
| | 00:17 | on the right, but it's very easy to get that
standard iOS look and feel for a Table view.
| | 00:23 | But this isn't true with collection views.
| | 00:25 | The default cell for a collection view does not
have any predefined labels or buttons or anything.
| | 00:30 | It is a totally blank canvas because
there simply isn't a default look
| | 00:35 | and feel for a Collection view.
Now canvas is actually a good name for this.
| | 00:39 | It does know how to draw itself, and we could
easily give it a color, but there's nothing on it.
| | 00:44 | So, you will always need to customize it and
your own user interface elements and typically
| | 00:49 | provide your own custom class for outlets
and actions and any behavior that you need.
| | 00:54 | Now, CollectionViewCell is a visual element
so while you could create this cell all in
| | 00:59 | code, more typically, you'll arrange the
visual parts in Interface Builder in Xcode.
| | 01:04 | You can either do it in a Storyboard or
you could put it in a separate NIB file.
| | 01:08 | You get the same abilities in both places, it
just depends on how you like to manage your project.
| | 01:13 | So, I'm jumping over here
into a project in Xcode.
| | 01:17 | This is where I finished off from the previous
one, although I've taken it back down to
| | 01:21 | a standard vertical flow and just 15 elements.
| | 01:25 | If I had to run it, we can see that by
giving these cells a background, we can see them
| | 01:30 | appear, but we're going to have to
customize them to make them do anything useful.
| | 01:34 | Now, when I dragged on that Collection view,
and I can see this over here in the dock,
| | 01:40 | I did get that one Collection
View Cell, the blank canvas.
| | 01:44 | This is based on the default
UICollectionViewCell class.
| | 01:47 | I could see that by selecting it and
then going over into my Identity Inspector.
| | 01:52 | So this is what I'm going to start with,
but first I'm going to add a new class to put
| | 01:56 | any outlets or actions that I need.
So, I'm going to add a new file in Xcode.
| | 02:05 | It's going to be an iOS Objective-C class.
| | 02:08 | I'm going to call it ProductCell because
I'm going to show kinds of products like DVDs
| | 02:12 | and Blu-Ray and applications.
| | 02:15 | And importantly, I need to make sure that
I'm inheriting from the correct superclass.
| | 02:20 | So, this is a subclass of UICollectionViewCell.
It adds the .h and the .m files to my project.
| | 02:30 | Now importantly, what I'm going to do here
is jump back into the Storyboard now, select
| | 02:35 | that cell and in the Identity Inspector,
the third one, I'm going to make sure that
| | 02:39 | I'm connected to my new one.
It might not show up.
| | 02:41 | So, I'm just going to type it in here.
| | 02:46 | This is just to make the link between the
element on the Storyboard and the actual new
| | 02:50 | code file that I just created.
| | 02:52 | Next, I'm going to go into my Object
Library and find just a simple label.
| | 02:59 | Drag that into the cell itself, and I'm
just going to arrange it here in the center.
| | 03:07 | I'm double-checking here that the label is inside
the Product Cell here, which is where I'd want it.
| | 03:13 | I don't want it anywhere else on the interface.
| | 03:15 | Now, I want to connect this label to our
new custom class so that we can get to it when
| | 03:20 | we are configuring these cell objects.
| | 03:22 | So, I'm going to switch into a System view
just to give myself a bit more room here.
| | 03:29 | Now, because I'm currently in the Storyboard
that is connected to the larger view controller,
| | 03:35 | it'll certainly show me the ViewController
class here, the ViewController header file,
| | 03:39 | and it's not what I want.
I want my new custom class.
| | 03:42 | So, I'm going to need to manually change
it by clicking the Automatic part, switch to
| | 03:46 | Manual and drop into my Collection project.
I'm looking for the ProductCell header file.
| | 03:53 | Now, what I can do is Ctrl-drag, so hold
down the Ctrl key, drag from Label over into the
| | 03:59 | interface section to insert the outlet.
| | 04:01 | It should be of type UILabel,
and I'll just call it cellTitle.
| | 04:06 | Now, I can switch back out of the System mode.
| | 04:10 | Now very importantly, I'm just going to double-
check that on this cell, the actual cell itself
| | 04:15 | that we do still have the Reuse Identifier
we were using before, demoCell, and that's
| | 04:20 | the name we're going to be using
when we're creating it in code.
| | 04:23 | Back into the main ViewController class in
our implementation here, I'm going to come
| | 04:28 | down to the collectionView: cellForItemAtIndexPath.
| | 04:33 | This is the code that actually creates
and configures that cell and returns it.
| | 04:38 | Now here's where we can
finally do a bit of customization.
| | 04:41 | Instead of creating a generic UICollectionViewCell,
I can now create a new instance of that ProductCell
| | 04:47 | that I have and get to its title.
| | 04:50 | Well, the first thing I'm going to need to do
is to make sure I've got an import for that.
| | 04:58 | And then in my code, I'll change it here.
Now let's just test it.
| | 05:05 | If this is an instance of the ProductCell,
I should be able to get to cellTitle.text.
| | 05:14 | Let's just put the word test in here, make sure
that's in a string literal, save that and run it.
| | 05:24 | Looks good. We are now actually talking directly
to that object and setting properties inside it.
| | 05:29 | Now, it's a little boring just
to have test there all the time.
| | 05:34 | Usually, what I'd be doing is having a collection
of model objects to start to configure the
| | 05:38 | data in my cells, for here let's
just have some random product names.
| | 05:43 | I'll create a simple array of productNames
here like CD, DVD, Blu-Ray, Book, App, and
| | 05:48 | I'm just going to randomly select one of these.
| | 05:55 | And it should give me a generically random
number between 0 and 4, and I'll now use that
| | 06:02 | to get into the productNames array.
| | 06:06 | All right, so we're getting some more
random data in there, and as you can see,
| | 06:12 | some of the changes in the text that I have
are kind of blurring out some of design here.
| | 06:16 | Blu-Ray doesn't look too good at all.
| | 06:18 | Currently, the layout object is assuming all these
cells are exactly the same size and the same layout.
| | 06:24 | We could change that in the Layout object itself, or we
could dynamically change it in code, but that's another topic.
| | Collapse this transcript |
| Adding highlighting and selection to view cells| 00:00 | Once we've started to create custom cells,
it's a common question to want to know how
| | 00:04 | do we start to interact with these, how
can we touch one to select it, and so on.
| | 00:08 | Well, that support thankfully is
already built into collection view.
| | 00:12 | As well as responding to scrolling when you
have more than one screen's worth of items,
| | 00:17 | every time we tap an item, it is already going
looking for a delegate to respond to that event.
| | 00:23 | So, I'm going to jump back into the code here.
| | 00:25 | Now, if I look at my MainStoryboard and
highlight the Collection View, and it's going to be
| | 00:29 | easier to select it from the dock or the jump
bar rather than on the actual View Controller
| | 00:35 | itself just because it's not really visible.
| | 00:37 | I'll open up the Inspector, and I'll see my
in Connections Inspector that I am hooking
| | 00:42 | up my delegate over to my View Controller.
| | 00:45 | You could hook it up to any
object that you wanted to.
| | 00:47 | This is just most convenient for me.
| | 00:49 | So, it's in the View Controller code file that
I'll need to write the delegate code to respond to this.
| | 00:55 | It doesn't really matter where I put it, I'm
just going to put it in here after the opening
| | 01:00 | implementation and the method that I'm looking
for is collectionView didSelectItemAtIndexPath.
| | 01:06 | Now, one of the things you have to be careful
of here is there are some similarly named methods.
| | 01:13 | There is a didDeselectItemAtIndexPath which
can look very much identical when you're just
| | 01:19 | scanning them correctly, but what I'm looking for
is this one, collectionView didSelectItemAtIndexPath.
| | 01:27 | This will be called when we tap on one of
those items, it will pass in an indexPath
| | 01:32 | parameter which will give us both an integer
for the section and an integer for the row.
| | 01:37 | We only have one section right now, but I'll do a little
NSLog message to write out both pieces of information.
| | 01:47 | So just using indexPath.row for the item and
indexPath.section which right now should be
| | 01:52 | zero all the time, let's test this.
I see behind the scenes here.
| | 01:59 | I'll just open up my messages that are coming out,
Item 6 in section 0, Item 0, Item 14, and so on.
| | 02:08 | So we're responding to these events already.
| | 02:11 | Although the actual user interface doesn't
give us that clue, it's only by looking
| | 02:15 | at that message, we could
tell that's what's happening.
| | 02:17 | Often, you want to change the visual
appearance of the cell when it's tapped, not always.
| | 02:22 | Sometimes, you might just immediately transition
to another View Controller or pop up a modal
| | 02:27 | window, but it's common to give the cell a
different look when someone's finger is touching it.
| | 02:32 | Now here's the thing, there is actually a
lot more going on here than you can see.
| | 02:36 | As far as the Collection View is concerned,
it's already tracking multiple states for
| | 02:41 | all of these items, even
if it doesn't look like it.
| | 02:44 | And there's not just two states, is someone
touching it or are they not touching it,
| | 02:48 | there's actually three states.
| | 02:50 | The cell can be normal, as
we're seeing most of them here,
| | 02:53 | it can be in a highlighted state, or it can
be in a selected state, and all of this is
| | 02:59 | built into Collection View,
and it's happening already.
| | 03:01 | So, what's the difference?
| | 03:02 | Well, highlighted means while your finger
is actually touching the cell, there is a
| | 03:07 | Boolean property called highlighted in every
cell object that's automatically set to yes
| | 03:12 | when I would touch something, and
it's set off to no when I let go.
| | 03:17 | Now, selected on the other hand is that
you touch and release one cell, and that cell
| | 03:22 | will have a Bool property called selected
set to yes. When you touch another item, the
| | 03:27 | first one selected becomes no
and the second one selected is yes.
| | 03:31 | But you say it doesn't
look any different. Well, no.
| | 03:34 | Making it look different is our job.
| | 03:37 | So these states are being tracked, but we
need to do some kind of visual appearance work.
| | 03:42 | That's completely up to us.
| | 03:44 | So, first let's handle the idea of selection,
and I'm going to handle selection because
| | 03:49 | we've already got part of that code written.
| | 03:51 | Here, where we handle the didSelectItemAtIndexPath,
what I can do is change the color of the items.
| | 03:59 | First, what I need to do is grab a reference
to the currently selected cell which I'm going
| | 04:05 | to do by calling the
cellForItemAtIndexPath of the collectionView object.
| | 04:10 | Then I'm simply going to reach into its built-in
property called contentView, into the backgroundColor
| | 04:15 | of that and set that to the very basic
UIColor, blueColor. Let's test that.
| | 04:22 | So, I come over, I tap something,
it becomes selected.
| | 04:27 | I come over, I tap another,
well, it becomes selected.
| | 04:31 | The first one is technically deselected, but
there's no code there to change the color back.
| | 04:36 | But you can at least start to see how
we can start to interact with this stuff.
| | 04:41 | So a little bit more of a tweak needed first. Just as
we have the Collection view didSelectItemAtIndexPath,
| | 04:48 | we also have the Collection view
didDeselectItemAtIndexPath method
| | 04:53 | where what I could do here is
just change the color back.
| | 04:59 | Now I'll grab the code that I just used, paste
it in there, and change that back instead to the lightGrayColor.
| | 05:11 | Test that again.
We click on one, it's considered selected.
| | 05:16 | We click on another, that one
turns back, this one is now selected.
| | 05:24 | It is very careful
and conscious of the bounds of these.
| | 05:27 | If I tap somewhere in between, it
doesn't count as anything else being selected.
| | 05:31 | So, back into the code, now what
you'll find is highlighting is very similar.
| | 05:36 | So, if you wanted to use another state or
another visual appearance when somebody was
| | 05:41 | actually touching that item, at the moment they were
touching that cell, we could do it that way as well.
| | 05:47 | You will find there is a collectionViewdidHighlightItemAtIndexPath
as well as a collectionView did UnhighlightItemAtIndexPath.
| | 05:55 | And we could use these.
| | 05:57 | That's the one way to do it, but I'm going
to show you another way in just a moment that
| | 06:01 | will let us not only leave this code out, but to
let us get rid of most of this code as well up here.
| | 06:07 | Now it's good to see the fact that we have
these very explicit delegate events about
| | 06:12 | selecting an item and deselecting an item and the
Collection View by default handles single state selection.
| | 06:20 | It only has one of the items has its
internal selected Bool set to true at anyone time.
| | 06:26 | You can actually change that, but that is the
default that's the most common way to do it.
| | 06:30 | But rather than write all this manual code
to change the background color, there is a
| | 06:34 | way to automatically have the visual state of
a cell change for highlighting and selection,
| | 06:40 | but it does mean we have to understand a little bit
more about how the collection view cell is constructed.
| | Collapse this transcript |
| Using background views| 00:00 | The UICollectionViewCell, this is where you're
going to be adding your user interface elements,
| | 00:05 | labels, image views, whatever you need.
| | 00:07 | And when you drag on elements, what you're
actually adding them to is an inner part of
| | 00:12 | this collection view cell, it's something
called the contentView, and this is just a
| | 00:16 | UI view, it's a container for other elements.
| | 00:19 | But the default background of the content
view area is transparent. That's why one of
| | 00:23 | the early things I did with it was set the
background color just so we could actually
| | 00:28 | see this cell over the black background of
the collection view, otherwise it would have
| | 00:32 | been a black label on a transparent background
on a black background, we wouldn't have been
| | 00:36 | able to see anything, so
we have this contentView.
| | 00:39 | But there are a couple of other views already built
into this UICollectionViewCell, we haven't used them yet.
| | 00:46 | We also have a backgroundView property
and a selectedBackgroundView property.
| | 00:51 | Now both of these are nil, they're empty
by default, but the benefit of using them is
| | 00:56 | if you put stuff in these views, you decide to
use an image or set a color in the background,
| | 01:02 | well, then the Collection view will
automatically swap them in and out as it's tracking the
| | 01:07 | highlighted and selected state of each shell. We
don't have to write any code to respond to those events.
| | 01:13 | However, there is one slight problem. If I
have defined the backgroundView color and
| | 01:17 | the selectedBackgroundView color as well as
the contentView backgroundColor, the contentView
| | 01:22 | will always win, because this has to be on
top, it's the thing that contains your actual
| | 01:28 | user interface elements, so select your
background view and background view behind and even
| | 01:33 | if the Collection View is swapping them out,
we're not going to be able to see them, because
| | 01:38 | they're behind that solid background view color.
| | 01:40 | So one of the things I will have to do is
remove the background color of the contentView
| | 01:45 | so we can see the effect of that.
So let's take a look.
| | 01:48 | So back into Xcode, if I take a look at this
cell that I have here and open up the Attributes
| | 01:54 | Inspector for it, I can see that I have got
the background of a light gray color, this
| | 01:58 | is what I set a little earlier.
| | 02:00 | If I take it back to the default of no
background color, and we go ahead and run this,
| | 02:07 | well, it's not a terrifically impressive application.
| | 02:09 | Everything is actually there, we just got
a black label on a transparent background
| | 02:14 | with black in the back, so
we're not seeing anything.
| | 02:16 | Well, let's fix that.
| | 02:18 | I want to set both the
backgroundView and the selectedBackgroundView.
| | 02:21 | Now you might think a good place to do this would be in
the view controller in the cellForItemAtIndexPath method.
| | 02:27 | After all, that's where we were setting the
label on that cell, so maybe we should set
| | 02:32 | the background and
selectedBackgroundView here too.
| | 02:35 | Well, no, not really, that's not the best
place. After all, this cell could be being
| | 02:40 | reused hundreds or thousands of times.
| | 02:42 | The better place to put this in is actually
when the cell is instantiated, and that is
| | 02:46 | our ProductCell object. We haven't really
been using this for much so far just as a place
| | 02:52 | to have the outlets for that label, but
I'm going to jump into the implementation.
| | 02:56 | Now when I created this, I did get the
default skeleton code here, and it provided me an
| | 03:03 | initWithFrame method, that's not going to work
for us, because we're going to be initializing
| | 03:09 | this, and it's going to be brought out of the
storyboard, and when something is initialized
| | 03:13 | out of a XIB file or storyboard,
let's using init with coder instead.
| | 03:17 | I could type that in, but I'm going to find
one over here in my code snippets, which you
| | 03:21 | should find one there too, jump into the
Code Snippet Library, I'll just filter down
| | 03:27 | at the bottom here on init, and I'm looking
for initWithCoder, there we go, that's the one
| | 03:32 | I want, drag that after
initWithFrame, and we get initWithCoder.
| | 03:39 | The standard outline here is just calling
initWithCoder or the super class, and here
| | 03:43 | is where we can put in a little bit of code to create
those backgroundView and create the background color.
| | 03:50 | Here's the issue, that I do have self.backgroundView
as a property and is also selected backgroundView
| | 03:57 | as a property, they're both nil right now.
| | 03:59 | So I have to actually instantiate a UI view
object, I'm going to just paste in a little
| | 04:04 | code to do this, rather than
have you watch me type this.
| | 04:08 | So in line 26, I am instantiating a UIView
called bg, just allocating it and knitting
| | 04:14 | with the frame that's 50x50. It doesn't
really matter what size I make it because
| | 04:19 | it's the layout object that's going to be
responsible for creating the size of it on
| | 04:24 | the screen screen, but this will do.
| | 04:26 | Then on the next line, I'm going to set it
to the backgroundView property of self, and
| | 04:31 | then I can reach into it and set the
background color of the UIView to in this case white.
| | 04:37 | So that would be the standard
color for the backgroundView property.
| | 04:40 | Then I'm going to repeat the whole thing, just
instantiating another UIView object and setting
| | 04:44 | its background color to dark
gray, go ahead and run this.
| | 04:50 | Now I have got the white background the
default background color, when I touch, that will
| | 04:54 | be considered highlighted, it will swap that
state out for a highlight as well as a selected,
| | 05:00 | so when I let go, we're still getting the
blue here, and that's just because I still
| | 05:04 | have the code running in the view
controller, so let's get rid of that.
| | 05:10 | Jump over into ViewController, and up here is
where I have two methods for didSelectItemAtIndexPath,
| | 05:21 | it's grabbing that cell and setting its
background color, and then didDeselectItemAtIndexPath.
| | 05:24 | I don't need either of these,
I can just get rid of them.
| | 05:31 | Now we have no code whatsoever that's handling
the select and the highlight, but it is still
| | 05:37 | working from the fact that we
just set those background views.
| | 05:41 | So highlight goes gray, but so does a select.
If I select something else, that select turns off,
| | 05:45 | and that's all handled by the collection
view itself, it's working without code.
| | 05:53 | If you need a different behavior, you need the
highlight and selected states to be different
| | 05:58 | from each or you need multiple selections
to be supported, then you're going to have
| | 06:02 | to get a bit more into the code, but if
you want this basic default behavior of being
| | 06:08 | able to just change the states by setting
them up up front, then all you need to do is
| | 06:12 | set the backgroundView and
selectedBackgroundView objects in your custom cell.
| | Collapse this transcript |
| Splitting a collection view into sections| 00:00 | As with table views, collection views can
also be split up into sections, grouping your
| | 00:04 | items together, and these sections
can have their own headers and footers.
| | 00:08 | We'll see that in a moment.
First, let's just see how to do it.
| | 00:11 | So I have here a new Collection View project that I
have created and just done a little bit of groundwork.
| | 00:17 | For our purposes here, what I'd like this
to do is show a collection of short words,
| | 00:22 | twoLetterWords and threeLetterWords and
fourLetterWords, maybe I'm a Scrabble fan.
| | 00:26 | So, I have got a little bit of this working so far,
it's creating some two letter word items here.
| | 00:31 | If I jump back in and explain what I've got,
I've already added the Collection View to
| | 00:36 | the View Controller, inside that I have the
regular cell that I've hooked up to our custom
| | 00:42 | class with one label on it, all the stuff
that we've done already, I just needed to
| | 00:47 | have a bit more complex data that we
could group together into sections.
| | 00:51 | So what I have done instead of loading in
a file or connecting to core data for our
| | 00:55 | purposes of simplicity, in my ViewController
I'm defining three NSArrays, and I'm using
| | 01:01 | the new NSArray literal format just to
load them up with some pretty simple data.
| | 01:06 | The problem is is by default the
Collection View thinks it only has one section, so I
| | 01:11 | might've written a whole bunch of other code
to load stuff in, but if it thinks it only
| | 01:15 | has one section, it's never
going to ask for anything else.
| | 01:19 | So before I do anything else, I'm going to
add the method numberOfSectionsInCollectionView,
| | 01:27 | that's the one, I don't really have to be
dynamic here because I know I have three
| | 01:31 | arrays, so I'm just going
to return the number 3.
| | 01:35 | Then as I go down a little further, nothing
particularly remarkable happening here.
| | 01:39 | When we jump into the number of items in section,
this was the place that previously I was just
| | 01:43 | returning the flat number 15 or 150.
| | 01:47 | What I'm doing is just a simple switch
statement that's going to either return the count of
| | 01:52 | the two letter word array, the count of the
three letter word array, or the count of the four letter word array.
| | 01:56 | Very similarly down here in the standard
cellForItemAtIndexPath, instead of just creating that cell
| | 02:04 | asking if there is a reusable one available and
setting some random text, I'm going to do this similar
| | 02:10 | switch statement here that's going to access
the right part of each of these arrays, nothing
| | 02:15 | remarkable here, in fact nothing really
different about anything that we've seen so far.
| | 02:19 | I'm going to go ahead and run this.
| | 02:22 | Now what's happening is it is splitting our
items up into different sections, it's not
| | 02:27 | collapsing them all together, we can
see there is a division between them.
| | 02:31 | That division is completely configurable.
| | 02:34 | We can start to work with the
spacing, we can add headers and footers.
| | 02:38 | But one of the first things we're running
into is an issue that given the four letter
| | 02:42 | words aren't all fitting well in the cells.
| | 02:45 | Now I could change the layout object to make all
the cells bigger, but I really don't want to do that.
| | 02:51 | So up next, let's see how to dynamically
change the size of the cells as they're been created
| | 02:57 | so that some are larger and some are smaller.
| | Collapse this transcript |
| Dynamically changing the size of view cells| 00:00 | It's an important point to understand with
Collection views that it isn't the cells themselves
| | 00:05 | that control how big they should be in
the Collection View, it's the layout object.
| | 00:10 | That's what controls the
size of all of these cells.
| | 00:13 | Now if I jump back into my storyboard here
and expand the Collection View, I can find
| | 00:18 | that Layout object inside the Collection View.
| | 00:21 | This is what controls the
size of all these cells.
| | 00:24 | If I jump over to my Size Inspector, I'm
going to see here that currently they are 50x50,
| | 00:29 | and that will apply to all of them.
| | 00:31 | Any change that I make here
will also apply to all of them.
| | 00:35 | So what if I want to have a bit
more dynamic behavior, what can I do?
| | 00:39 | Well, it's still the Flow Layout object
that's going to control that, but I can't change
| | 00:44 | anything here to just make
things auto expand and auto contract.
| | 00:48 | What's the solution here is all about
delegation, like so many things in iOS.
| | 00:53 | Now we're already behaving as a delegate.
| | 00:56 | If I highlight the Collection View itself
and go to my Connections Inspector, this is
| | 01:00 | where I'm volunteering to be the delegate
here for the dataSource and the normal delegate
| | 01:05 | to respond to selections to
highlighting and deselecting things.
| | 01:10 | But I can also be the
delegate for the Flow Layout.
| | 01:13 | Now the way that I do this is go
over into my ViewController here.
| | 01:16 | This is where I'm currently saying I'm supporting the
UICollectionViewDataSource and UICollectionViewDelegate,
| | 01:21 | and before this closing bracket, I'm going to put in a
comma and also the UICollectionViewDelegateFlowLayout.
| | 01:29 | So, responding to the events in the FlowLayout
object as well as the regular Collection View.
| | 01:37 | Save that and jump over
into the implementation file.
| | 01:40 | Here we can write just a little bit of extra code
to control the sizing independently for each cell.
| | 01:47 | The method that we want here is the
collectionViewSizeForItemAtIndexPath.
| | 01:53 | Let's see if I can find this one here.
There we go, that's it.
| | 01:56 | Sometimes a little bit tough to see, if you're
actually looking at the big dropdown window,
| | 02:01 | but if you look up here where I'm actually
typing, I can see the little gray text that
| | 02:06 | says that's what I'm looking for here,
collectionView:layout:sizeForItemAtIndexPath.
| | 02:13 | This returns CGSize that basically just has
the height and the width of each individual
| | 02:19 | cell, because it's accepting a parameter
and index path that will be passed in,
| | 02:24 | so this will be called repeatedly
for every item in every section.
| | 02:28 | So I get that both the section and a row,
and I could write lots of code to ask what
| | 02:32 | individuals cell this is going to be. What
I'm going to do is just do something fairly
| | 02:36 | generic and just say all the items
in the final section should be bigger.
| | 02:42 | So we have three sections, 0, 1, and 2, so I'll
ask if indexPath.Section = 2 and will just return
| | 02:49 | a CGSizeMake of a couple of floats. If that
is that last one I'm going to start with
| | 02:54 | 80 wide using the .f, so it'll
take it as a float and 50 high.
| | 03:02 | However, seeing as I do always have to
return a CGSize, I better have an else as well,
| | 03:08 | so if it's not in the last section, we'll just
return the standard 50x50 size. Save that and run it.
| | 03:20 | Then we see that do have dynamically sizing
cells, the first two sections of the standard
| | 03:24 | square are 50x50 and the last section is 80x50.
| | 03:28 | However, I'm still running into a problem
in that I'm not getting all of those words,
| | 03:33 | I'm still getting the dot,
dot, dot, the ellipses here.
| | 03:36 | So what's the problem?
| | 03:37 | Well, now what we're running into is almost
certainly a problem with the Label and with
| | 03:41 | the constraints inside the individual cells,
so let's go back and take a look at that.
| | 03:46 | I am going to stop this
and jump into the storyboard.
| | 03:50 | Selecting this cell itself--and I've called
it wordCell here--I can expand that, I find
| | 03:54 | I have a Label inside it.
| | 03:57 | And the Label itself has two constraints, I can expand
the right-hand side just to see these a little better.
| | 04:04 | I have a Height constraint
and a Width constraint.
| | 04:07 | And the Width constraint is Equal, not Equal
to or Greater Than, but Equal, so what it's
| | 04:13 | saying is this Label is always going to be
equal to 42, that fits quite nicely inside 50,
| | 04:19 | but if it's still 42 inside 80,
it's not actually growing.
| | 04:23 | Now, there's a couple of
ways I could try and fix this.
| | 04:26 | One is I could change this to Greater Than or Equal to,
and that's almost certainly not going to work.
| | 04:30 | In fact, look over here that
I currently have two in the dock, a Height
| | 04:34 | of 21 that's fixed, and a
Width of 42 that's fixed.
| | 04:37 | If I try and make that Greater Than or Equal,
it's actually dumping in another one, and
| | 04:42 | you'll occasionally see this where there's some
kind of conflicts in the a tight space, that
| | 04:47 | what it's actually doing is taking that fixed
Width of 42 as being really important because
| | 04:52 | as the priority of 1,000, and it's not
letting me reassign this, so it's actually
| | 04:58 | adding another one, that's not what I want.
| | 05:00 | So what I'm first going to do, I'll delete
that new constraint that was created, go back
| | 05:04 | to the Width of 42, that's fixed, I'm just
going to ramp down the priority of this and
| | 05:09 | just say it's just really not that important.
| | 05:12 | I might have to do a little
bit of experimenting with this.
| | 05:14 | I've taken this down to about 235.
Now I'll go ahead and run this again.
| | 05:19 | That's a lot better.
| | 05:21 | Now we're actually saying that the Label is
allowed to resize itself if that's important,
| | 05:26 | if you have got bigger contents inside it.
| | 05:29 | And this is how we'd start to
manipulate our cells on the fly.
| | 05:33 | Of course, we can have multiple cell types.
| | 05:36 | We could create new cells and
new classes for those cells.
| | 05:39 | So if you do have things that are substantially
different, you're probably actually going
| | 05:42 | to create an entirely new cell, with a
different class and a different ID, but you can do some
| | 05:48 | at least small rearranging of the cells that
you do have in response to the data you have.
| | 05:53 | And that's an important distinction.
| | 05:55 | If you ever use this actual method,
I'll jump back into it over here.
| | 06:01 | So if you use this sizeForItemAtIndexPath method,
know that the cell has not actually been created yet.
| | 06:09 | It's asking for the size of it so that it
can create it. What that means is I cannot
| | 06:13 | get to the cell object or
get to it properties here.
| | 06:16 | I have to make all my decisions based on the
actual data that's going to be put into the
| | 06:21 | cell, not on the cell itself, because this
method sizeForItemAtIndexPath will be called
| | 06:28 | before this method, the cellForItemAtIndexPath.
| | 06:31 | So, all your decisions about size need to be made on
the data itself, not on the properties of the cell.
| | 06:40 | So this is starting to get a bit more useful.
| | 06:42 | Next, let's see how to add
headers and footers to this.
| | Collapse this transcript |
| Adding headers and footers to a collection view| 00:00 | Adding headers and footers to a Collection
view is based on a new kind of object,
| | 00:05 | something called a Supplementary Reusable view.
This sounds like a mouthful, but it really isn't.
| | 00:10 | Supplementary view is simply to distinguish it
from our regular view cells or actual data.
| | 00:15 | So if we want to add a header or add a footer
to our sections, well, that isn't our important
| | 00:21 | data, it is extra, it is supplementary and
reusable, because just like our reusable view
| | 00:26 | cells, if we are splitting our data into multiple
sections, we would like to reuse those supplementary
| | 00:32 | header and footer objects if we can.
| | 00:34 | The assumption is your headers are going to
be dynamic, they're going to have say labels
| | 00:39 | on them that can change, they are data-driven just
like your cells, but just nowhere near as complex.
| | 00:44 | So how do we add one?
| | 00:45 | Well, I am beginning where we finished off
last time, and I have this basic application
| | 00:50 | with several cells just split into three different
sections, and I want to add headers and/or footers to this.
| | 00:56 | So I am going to jump into the
Storyboard for this application.
| | 00:59 | Now if you have looked at the Object library,
when we've been adding some of these collection
| | 01:05 | view objects, I am just going to
filter on collection in the Object library.
| | 01:10 | I actually find that there is something
called a Collection Reusable View, and this is
| | 01:16 | what is used for headers or footers, but we don't
need to drag it onto the storyboard because
| | 01:21 | if we are actually adding it on the
storyboard, there is an easier way.
| | 01:25 | If I go over into my dock of the storyboard
here, find the Collection View itself, expand
| | 01:32 | that so I can see it a little better and jump
over to my Attributes Inspector, again I want
| | 01:36 | to make sure I am selecting
the Collection View object.
| | 01:39 | What I should get then is these two check
boxes in the accessory section, one for section
| | 01:44 | header and one for section footer, selecting either of these
will add a Supplementary Reusable View to the Collection view.
| | 01:52 | You can of course add it to a different XIB file
if you want to, but for our purposes this is fine.
| | 01:57 | In fact, when I click this, you'll see it add some
extra space at the top here, add a header, add a footer.
| | 02:04 | We can't actually see them here because I
have still got white on white going on--
| | 02:08 | or really, it's transparent with a white background.
| | 02:11 | But over here in the dock I see that I
have one Collection Reusable View and clicking
| | 02:15 | that will highlight it in the Storyboard view,
same for the footer, because like the cell
| | 02:20 | on the Collection view itself these are all transparent.
There is nothing on them until you put it on.
| | 02:25 | So you get used to selecting them on the
dock itself or in the jump bar. Okay, now what?
| | 02:31 | Well, what am I actually going to do is
get rid of my footer here, I am just going
| | 02:34 | to go through the process of adding a header
because it's exactly the same as a footer,
| | 02:38 | and this will just half the
time than it needs to take.
| | 02:42 | So selecting this header, so I can see
it's just showing up highlighted here.
| | 02:47 | The size of the header like the size of all
of our view cells is not actually controlled
| | 02:51 | by the header itself, it's
controlled by the Flow Layout object.
| | 02:55 | If I were to select that and go over into
size, you will see that not only now that
| | 02:59 | we have the cell size of 50x50,
but we have a header size of 50x50.
| | 03:03 | That really is a minimum
height, but it means it's 50 high.
| | 03:08 | That's okay for us to get started with.
We may want to experiment with that later.
| | 03:12 | What I am going to do so it's visible is
select that Reusable view, and I am going to give
| | 03:17 | it just a background color so we can see it.
I will just make it a light gray color.
| | 03:22 | And just to prove a point, if I go ahead
and run this, I am not going to see anything,
| | 03:26 | I'll get the spacing, but I won't actually
see the object because there's nothing that's
| | 03:30 | going to instantiate it probably.
| | 03:32 | What I wanted to something a bit more involved.
Quite typically with a header, you're going
| | 03:35 | to want some data on it, perhaps
a label with a category heading.
| | 03:40 | So in my Object Library, I'm going to
select a label, drag it into the header,
| | 03:47 | and just double-checking in the dock that it
is inside my Collection Reusable view.
| | 03:51 | I will just drag this a little wider, so
it gives us a little space, center-align it,
| | 03:58 | and I will make it bold.
| | 03:59 | But if I want to get to this through code, well,
it's like getting to the label inside the cell.
| | 04:04 | I can't expect that the default built-in
class has support for this new thing that I
| | 04:09 | just added, so I am going to
have to make my own class.
| | 04:11 | So I am going to add a
new class to this project.
| | 04:16 | Cocoa Touch Objective-C class of course, to
class that represents my header for this Word
| | 04:21 | app, so I will cal lit Word header, and this
is the class that it needs to be a subclass
| | 04:27 | of is UICollectionReusableView.
| | 04:32 | We want to be very careful here not to
create it as a subclass of UICollectionViewCell.
| | 04:35 | So UICollectionReusableView,
click Next, click Create.
| | 04:40 | Really, right now the only reason I'm doing this
is to have a place to put an outlet for that label.
| | 04:44 | So the class is created, but right now there
is no connection between that class, and this
| | 04:50 | actual reusable view element.
| | 04:52 | I am going to select that over here in the
dock, because if we jump over to the identity
| | 04:57 | inspector we can see that right now it's just hooked
up to the standard default UICollectionReusableView,
| | 05:03 | I need to change that to
my one which was WordHeader.
| | 05:09 | So it now at least knows it's
associated with that code file.
| | 05:13 | However, I still need to
explicitly connect the label to the code.
| | 05:18 | So giving myself a bit more room,
I'm going to jump into Assistant view.
| | 05:22 | As we saw before what will typically happen
with assistant view is you will get the Automatic
| | 05:26 | option show up where it's going to connect
you to the view Controller, what you actually
| | 05:30 | need is the manual option, so it will
connect to the new word header class.
| | 05:35 | And as long as the header has been associated
with this class, I should be able to select
| | 05:40 | that label and either from the storyboard itself
or from the dock, Ctrl-drag into the interface.
| | 05:47 | Let go and insert an outlet,
I'll call this headerTitle.
| | 05:54 | I'll jump back into the regular editor here.
| | 05:56 | Now there is an important thing here: as with
working with cells, if I'm going to do this
| | 06:01 | in the storyboard, and I'm trying to assume
that these are reusable header objects,
| | 06:06 | the same way that my view
cells were reusable view cells.
| | 06:09 | Well, I need to give it an identifier.
| | 06:12 | If you remember when we worked with the actual
view cells themselves, they would have a Reusable
| | 06:18 | View Identifier called wordCell, and if I
select the header I also get a reuse identifier here.
| | 06:25 | Again, if it's difficult to grab, then make
sure that you open the dock instead, select
| | 06:30 | the header itself, and select its reuse
identifier. You don't want to mix these up.
| | 06:35 | So I'm going to use a
Reuse identifier of header.
| | 06:38 | Now if run this, I will still get nothing.
| | 06:41 | I am getting that spacing going on, but just
as with the individual cells that I need to
| | 06:47 | provide that cell for item at index path
method to actually make sure they're created,
| | 06:52 | I need to do the equivalent for the header as well.
| | 06:55 | So jump back I am going to go into my View
Controller code, use the Jump bar and just
| | 07:02 | to jump down to cellForItemAtIndex path.
| | 07:07 | This is where we are dequeuing the individual
cell items and setting their contents.
| | 07:12 | I need to do something very similar to this, it's a different
method, so I will create myself a bit of space here.
| | 07:17 | But it is on the collectionView, and what I
am looking for is--actually it's the very last
| | 07:22 | one here, it is collectionView:
viewForSupplementaryElementOfKindAtIndexPath.
| | 07:30 | What does that mean, supplementary element of kind?
It's a supplementary element of some kind, what kind?
| | 07:35 | Well, it could be a header, it could be a
footer, so it's a specific method that we use
| | 07:39 | to grab these supplementary reusable views.
| | 07:43 | That's all we want, and what I want to do
is actually be able to get a reference to my
| | 07:49 | custom WordHeader class that I just wrote, but this
view controller class doesn't even know that one
| | 07:54 | exists, so I better jump up to the top and
import it, #import "WordHeader.h", and then
| | 08:02 | I'll use my jump bar just to jump right
back down to viewForSupplementaryElementOfKind.
| | 08:12 | I can create a pointer to
this, I will call it header.
| | 08:17 | And the way that I get to it is quite similar
to asking the collection view for a dequeued
| | 08:23 | reusable cell, instead I am going to ask the
collection view to dequeue a reusable supplementary
| | 08:30 | view, and there is an extra parameter here,
where it's saying well what kind because I
| | 08:34 | know it's not just the same cell, it
could be a header, it could be a footer.
| | 08:38 | This parameter is typed as an NSString, but there is
actually a useful enumeration that we can just use.
| | 08:43 | If I start typing
UICollectionElement, there we go.
| | 08:47 | There's two options here, UICollectionElementKindSectionFooter,
it is a Section Footer or it's a Section Header.
| | 08:54 | Well, we are interested in the Section Header.
| | 08:56 | You are drawing the distinction or telling
the Collection view to make the distinction
| | 09:00 | here so it knows how to do the
proper sizing and spacing and everything.
| | 09:04 | Now we still have that Reuse Identifier, because
theoretically we could have multiple different
| | 09:10 | kinds of header view. We only have one,
but it doesn't know that.
| | 09:15 | So I will just put in the Reuse
Identifier, and we would call it header.
| | 09:20 | And the last parameter here for index path,
well, that's actually being passed directly
| | 09:24 | in as index path, so I'll use that.
| | 09:28 | So now we should have a header object, and
because it is my custom class, I should be
| | 09:33 | able to use .syntax and jump right into, there we go,
my header title that I just defined and set the text.
| | 09:41 | I could do a switch statement here to do
some custom stuff, but for purposes of time
| | 09:45 | I am just going to give it a
literal string of Category goes here.
| | 09:51 | Finally, return that object, save it, run it, and now
we have the headers appearing above every section.
| | 10:05 | Creating a custom footer is essentially
following exactly the same process with a few
| | 10:10 | different names, footer instead of header.
| | 10:12 | One thing to be aware of
is actually in this method.
| | 10:16 | The one that we have just added which is the
viewForSupplementaryElementOfKind, this would
| | 10:21 | be called when it's looking for a header,
this would be called when it's looking for
| | 10:24 | a footer, and we'd have to make that
we were instantiating the right class.
| | 10:28 | So if you didn't need to do that, you are
just going to put in basically an if statement,
| | 10:33 | that asks what is the kind, so if kind is
equal to, and we have these UI Collection
| | 10:40 | Element Types is it equal to the section header?
If so, we are going to go ahead and dequeue
| | 10:45 | header, if it's equal to footer,
we'll go ahead and dequeue a footer.
| | 10:48 | There only are those two kinds,
so it really is just an if/else.
| | 10:52 | But I only have a header, so I don't need
that, I just need to make sure that this is
| | 10:56 | going to return some object of the right type.
And that will do it for the time being.
| | 11:01 | For the purposes of this What's New in IOS course,
this is what we are going to cover for Collection Views.
| | 11:07 | As you can probably tell this is a deep and
very customizable area of iOS development,
| | 11:12 | and I could do an entire course on collection views, getting
into deletion or dynamic updating or even custom layouts.
| | 11:19 | And you might want to keep an
eye out for that at lynda.com.
| | 11:22 | But hopefully this will be enough to get you started,
and next, let's take a look at some of the new frameworks.
| | Collapse this transcript |
|
|
3. Working with PassbookIntroduction to Passbook| 00:00 | I'm going to begin with the idea that you've
seen there is a new built-in app in iOS called
| | 00:05 | Passbook, but you might not
have really explored it yet.
| | 00:08 | So this application is part of iOS.
| | 00:10 | It's already there on the iPhone when you
have iOS 6, it's also on the iPod touch with
| | 00:14 | iOS 6, but isn't on the iPad, it's just on
the smaller iOS devices, at least at this time.
| | 00:20 | It is also on the iOS
Simulator, which can be very useful.
| | 00:24 | It's an app designed to hold coupons, store
loyalty cards, boarding passes, event tickets, and so on.
| | 00:30 | I've loaded a few into my simulator already.
| | 00:33 | The idea is that this Passbook app is a
single application that can store these kinds of
| | 00:38 | things for multiple companies, multiple stores,
multiple airlines, or venues, and you keep all
| | 00:43 | of your passes in Passbook.
| | 00:44 | But there are a couple of
important points to understand.
| | 00:49 | Passbook is not an application for
generating passes, meaning it does not create unique
| | 00:54 | coupons or provide unique event tickets.
| | 00:56 | And neither is it an event management system,
it doesn't handle pass redemption.
| | 01:02 | It is simply a place that can store your passes, your coupons,
your tickets that you or some other company define.
| | 01:10 | The idea is that if you're an airline, for
example, you already have an existing system
| | 01:15 | that creates unique boarding passes, and
you already have the physical scanners at
| | 01:20 | the gates to read them back in.
Apple is not trying to replace that.
| | 01:23 | But now instead of emailing a PDF of that
boarding pass to your passenger and having
| | 01:28 | them printed out, perhaps even having them
have to wander around strange hotel at 5 a.m.
| | 01:32 | in the morning, trying to find the
business center and a working printer.
| | 01:36 | You send them this electronic version instead.
| | 01:38 | And when they get to the gate of the airport,
the airline scans it in to that existing system.
| | 01:43 | If on the other hand, your store, the expectation
is you already have a system to manage loyalty
| | 01:50 | cards or gift cards and handle those, this just
provides another place to store that information.
| | 01:56 | Same as if you're working with events, the
assumption is you already have a system that
| | 02:00 | could be generating tickets and a
system in place to validate them.
| | 02:03 | So it isn't intended to replace any of these.
It's intended to supplement these existing systems.
| | 02:09 | Now you see barcodes on these examples that
I'm showing you here, you don't have to use
| | 02:14 | a barcode, but it's commonly
expected that you would do.
| | 02:18 | The Passbook app already has built in support
for common 2-D barcodes, it supports QR, Aztec
| | 02:25 | and PDF417, but it does not have built-in
support for what are call 1-D barcodes, the
| | 02:32 | single level ones, like a common UPC code that
you might see on something get at the grocery store.
| | 02:39 | Certain third parties are actually trying
to support these right now, but just be aware
| | 02:43 | that Passbook out of box supports the 2-D ones.
| | 02:47 | The reason for that is that 2-D barcodes are
much more reliable to scan optically rather
| | 02:52 | than using the laser scanners that the 1-D
barcodes support, so it's just more reliable
| | 02:57 | to use the 2-D versions on a
backlit device like an iPhone.
| | 03:00 | Now you might look at this kind of
information and think, well, this is nothing new.
| | 03:05 | I've seen different companies create their own
applications to manage their boarding passes,
| | 03:10 | and sure that's completely true.
| | 03:11 | But there are a few
benefits from using Passbook.
| | 03:14 | One, because Passbook is integrated into iOS,
it's also integrated into the lock screen,
| | 03:19 | and what that means is if I go to the lock
screen of my device here, I can get things
| | 03:24 | like a boarding pass actually show up on
the lock screen, but only when it's relevant.
| | 03:30 | I can have a time and a location built into
this pass so that the text that I'm at the airport
| | 03:34 | at the right location and at the right time.
| | 03:38 | So it doesn't clutter the screen up with a
boarding pass for a flight that's not 'til next week.
| | 03:43 | And one of the benefits here is you can
actually get to this pass details directly from the
| | 03:47 | lock screen, I don't have to unlock the
phone and type in any code that I might have,
| | 03:52 | I just drag this icon and slide it, and
it'll go directly just to that pass.
| | 03:58 | And this is not considered unlocking
the phone, the phone is still locked.
| | 04:02 | So getting there really quickly very
convenient if I'm standing in the queue at the gate by
| | 04:06 | the airport, and when you're viewing one of
these passes, Passbook will automatically adjust
| | 04:11 | the brightness on the iPhone to be the
best brightness for scanning these codes.
| | 04:16 | And it'll also extend the time that this pass would
be shown before the iPhone goes back to blank again.
| | 04:23 | So what we need to do when we're working
with Passbook is handle the information to get
| | 04:28 | our pass into one of these pre-provided formats.
| | 04:32 | Apple has provided five pass styles in Passbook
with different layouts. There's one specifically
| | 04:38 | for boarding passes for
airline or train or boat.
| | 04:43 | There's a style for managing event tickets,
if you notice there's a slightly different
| | 04:47 | visual look to the edges of most of these.
| | 04:51 | If I select coupon one, you'll see there's a
perforated edge here, that's a different style as coupon.
| | 04:59 | There's a built in style for a store card,
and finally one that's considered generic,
| | 05:05 | pretty much anything else.
| | 05:06 | Now you can provide your own colors, you
can provide your own artwork and logos.
| | 05:10 | But really what you're doing a lot of the
time is providing the correct information
| | 05:14 | to fit into these templates.
| | 05:16 | So here's the second
important concept to understand.
| | 05:19 | To work with Passbook, to create your own
passes, your own coupons or tickets or store
| | 05:24 | cards or whatever they are for Passbook, you do not need
to build an iOS application, it's not necessary at all.
| | 05:31 | To understand why we need to ask, well, how do
these passes get into in our Passbook application?
| | 05:37 | How would I get a boarding pass from Delta
or a coupon from Starbucks or a movie ticket
| | 05:42 | from Fandango into this application right now?
| | 05:46 | There's three ways to get a pass
into the Passbook app right now.
| | 05:50 | First is email, the same way that an airline
right now might send you a PDF of your boarding
| | 05:56 | pass, they could send you a Passbook
pass file that's recognized by iOS.
| | 06:00 | If you open it up in the Mail application, you can
just touch it and import it directly into Passbook.
| | 06:05 | It's a self-contained file called a PKPASS file.
| | 06:09 | You can get it here, you can
preview it, add it into Passbook.
| | 06:12 | Now the airline might send you both a PDF and
PKPASS file, whatever's most useful at the time.
| | 06:18 | Second, with a URL, so by downloading from
a web page, say I sign on to the site for
| | 06:24 | a movie theater, I buy a ticket and their
confirmation page can generate a URL for me
| | 06:29 | to download that pass file,
that PKPASS single file.
| | 06:34 | And on iOS 6, it would open up in Passbook.
| | 06:37 | Apple have even suggested badges
for me to place on a website for this.
| | 06:41 | Now third, I could if I wanted to
do it from another iOS application.
| | 06:47 | If I currently have an app installed on the
user's machine, I could generate these passes
| | 06:52 | in my app using the new Pass Kit
framework to get them into Passbook.
| | 06:57 | But most commonly the passes will arrive on the
user's machine via email or downloaded from a URL.
| | 07:03 | And this means the actual passes that we're
creating, those PKPASS file, they're typically
| | 07:09 | created by a back-end system
somewhere, on a website for example.
| | 07:13 | And here's the great thing, a PKPASS
file is actually pretty simple to create.
| | 07:19 | Although it's delivered as one single file,
which if you had it on your Mac desktop,
| | 07:23 | it might just have a PKPASS suffix.
It's really a zipped Archive.
| | 07:31 | If I rename this to zip, I can then expand it
into its own folder, and I can see the contents of that.
| | 07:40 | It's a bundle. It's got a few icons, an image or two,
and very importantly a text file that contains
| | 07:47 | the information to be shown on the pass.
| | 07:49 | Now this is not in Objective-C or some other language,
it's actually in JSON, JavaScript Object Notation.
| | 07:58 | It's a very simple way to package up some
pure data in key value format, we're going
| | 08:03 | to explore these in just a moment.
| | 08:05 | The reason that it's in JSON is because JSON's
are really simple format that a lot of back-end
| | 08:11 | web server-side frameworks are great at
generating, Ruby or Python or ASP.net.
| | 08:16 | And it's much more likely that that's
where you would want to generate your passes.
| | 08:23 | So this pass that I have isn't a
program, it isn't an application.
| | 08:28 | There's no executable code in it, it's just
a little bit of text and some artwork,
| | 08:32 | all zipped up and given a name.
| | 08:34 | You can also include localizable
strings to support multiple languages.
| | 08:38 | However, to get these into an iOS device,
these passes do need to be digitally signed
| | 08:43 | in the last step of generating this PKPASS
file so that someone couldn't pretend to be
| | 08:48 | Delta and Starbucks and Fandango all at once.
So the pass files will always have a signature.
| | 08:54 | And these passes will get added to Passbook
application, someone uses them, and when they're
| | 08:58 | done with them, they can just
choose to delete that pass file.
| | 09:05 | So to start to create our own, next let's get a little
bit more hands-on with what a pass is actually made of.
| | Collapse this transcript |
| Creating a custom pass| 00:00 | The first place to go when creating passes for
passbook is actually to the Apple Developer site.
| | 00:06 | Specifically, developer.apple.com/passbook,
because here you'll find some references that
| | 00:11 | aren't included in the basic iOS SDK that you're
going to need, or least you're going to want them.
| | 00:17 | Now if you're working with passbook you'll
almost certainly want to bookmark this page.
| | 00:20 | It will be very useful.
| | 00:24 | The several documents here that are great to
have on hand, and there is also a downloadable
| | 00:27 | batch you can get you, too, to add to your
websites and emails to say that you support Passbook.
| | 00:32 | But what I'm really interested in first off
is this, the Example Passes and Sample Code,
| | 00:38 | and you do have to be signed-up member
of the iOS Developer program to get these.
| | 00:47 | The Passbook Support Materials are just a
dmg, which I'm going to grab and download
| | 00:52 | so a disk image that will open up in finder.
| | 00:58 | And apart from the Read Me file, there are
three folders here, this first thing is a
| | 01:03 | bunch of example Passes, there is one pkpass
file provided for each of the five provided
| | 01:09 | times, BoardingPass, Coupon,
Event, StoreCard, and Generic.
| | 01:12 | So, you get the signed bungled pass file that you could
just email to yourself or even drop into the simulator.
| | 01:20 | But you get also all the resources used to make
them. We're going to explore these in just a second.
| | 01:26 | But also in these resources you find signpass.
This is a simple Xcode command line project
| | 01:33 | that we can use to sign our passes so that we
can test one on our device or on the simulator,
| | 01:37 | and that's really useful for us as developers,
because again, Passbook will not accept a pass
| | 01:41 | that hasn't been digitally signed.
| | 01:43 | But most typically, you won't actually be creating
your real passes using an Xcode command line project.
| | 01:49 | So, the third resource you get is this one, it's
a ServerReference, it's a reference implementation
| | 01:56 | for a server-side application that
creates and signs Passbook Passes.
| | 02:00 | Now this is actually written in Ruby so if
you are saying building a website rails app,
| | 02:05 | it would be a great thing to have on hand,
but as it's Ruby its also very readable, even
| | 02:09 | if you're going to end up building your
passes using ASP.NET or PHP or Python or Java or
| | 02:16 | whatever server-side application you have.
| | 02:19 | Now in this course we won't be getting into
the server-side of things, because once you're
| | 02:22 | familiar with a few things like the JSON
format of a pass, it really has nothing to do
| | 02:27 | with iOS, so I'm going back in
to the Passes directory.
| | 02:31 | Let's take this BoardingPass example
that I have here, BoardingPass.pkpass.
| | 02:36 | I'm going to open up my simulator, because
it's embedded inside Xcode I actually use
| | 02:40 | Xcode menu to open up the iOS Simulator, but
if you find yourself using it a lot what you
| | 02:46 | can do after you've opened an app from
Xcode is you can right-click the icon
| | 02:52 | and choose to keep it in the dock.
| | 02:55 | So, open that over on the left, and I'm
going to drag in BoardingPass.pkpass here.
| | 03:03 | Now the effect that I get here is the same
that I would if I had open this up, say, in Safari.
| | 03:09 | In fact, that's what's happening,
it is opening up in Safari on this Simulator
| | 03:14 | device and giving me this preview here.
| | 03:16 | I can take a look at this Pass, I can flip
the little eye button to look at the back of it.
| | 03:21 | It hasn't been added to a Passbook yet.
I can either cancel adding it to it,
| | 03:25 | or I can click the Add button.
| | 03:27 | And there's little animation there
as it's added to all the other passes.
| | 03:31 | So, now let's take a look at the
resources that were used to create this.
| | 03:38 | If I go into that BoardingPass.raw folder, I get
five files, but there's really just three things.
| | 03:44 | There is a logo, an icon, and
the all-important pass.json file.
| | 03:49 | The logo and icon are just provided twice.
| | 03:52 | One regular and one high-res at sign 2x version
that will automatically be used for retina display.
| | 03:58 | So, what's the difference between icon and logo?
| | 04:00 | Well, the icon is what is used as an icon
for this pass file when it's sent in email
| | 04:04 | or shown on the lock string.
| | 04:06 | Whereas the logo is what's actually going
to be used at the top of the pass when we
| | 04:11 | are looking at the pass in Passbook itself.
| | 04:15 | I still have several of those sample passes
here, including a couple of duplicates, but
| | 04:19 | if you notice several of these logos here are
using the old white format, that is actually
| | 04:24 | what Apple officially recommend.
| | 04:26 | If you have a monochrome version of your
logo, that you can show here, to do that one.
| | 04:30 | We'll talk about those in a bit later.
The all-important file here is pass.json.
| | 04:35 | I am going to open this up in Xcode, it
doesn't have to be Xcode, there is nothing special
| | 04:40 | about this, you could use any
text editor or programming editor.
| | 04:43 | We are not in the world of Objective-C
in iOS projects, we don't need to be.
| | 04:49 | So, here's the data for this boarding pass in JSON
format, which is a simple set of nested key value pair.
| | 04:56 | I don't expect it all to make sense, but it should seem
reasonably readable as I start to pass through this.
| | 05:03 | It's meant to include the
information for a particular boarding pass.
| | 05:07 | So, could I scan little segments of code
here and say, well, I have got passenger is
| | 05:11 | John Appleseed there, I've got a
departure time and a flight number.
| | 05:14 | So, can I make a pretty educated guess as to
what information in this JSON file is actually
| | 05:20 | being shown in the pass
itself? And sure I can do.
| | 05:23 | Now looking through JSON file, I can see
that they seem to be split up into few different
| | 05:28 | sections, we have an area called primaryFields,
we have secondaryFields, we have auxiliaryField.
| | 05:33 | Now if I go down even further, we
have a section called backfields.
| | 05:38 | The backFields are what would
be shown on the back of the pass.
| | 05:42 | We see here a key for a passport for
Canadian and residents, and that's what actually
| | 05:46 | is showing up in the pass over
here as well as the terms of use.
| | 05:50 | Now some of this JSON file is different
for each of the different five pass styles.
| | 05:56 | Boarding passes have one set of expected
information, StoreCards have a slightly different set,
| | 06:01 | events another and so on,
but it's all fairly similar.
| | 06:05 | And particularly the stuff near
the top is almost exactly the same.
| | 06:08 | Now the question is, well, how would you know?
| | 06:11 | We can get a lot of this information from
the passbook for Developers web page from
| | 06:16 | one of the documents there, which is known
as the Passbook Package Format Reference.
| | 06:21 | This is actually a fairly small document.
| | 06:24 | But this is what describes the
actual pass files themselves.
| | 06:27 | We have a Package Structure section.
| | 06:30 | Talks first about the images you can include
like the icon and the logo that we already saw
| | 06:34 | and then gets into the
keys in the JSON file itself.
| | 06:42 | Top level keys like description and organization
name, I'm going to drill into this in a little bit.
| | 06:47 | But the idea is that you need to roughly
understand this format, but you don't need to learn it,
| | 06:53 | you're not going to be
manually writing JSON files.
| | 06:56 | This is going to be generated by your server-
side system and read by your Passbook application.
| | 07:01 | JSON is a format that's intended to be
written by one computer and read by another.
| | 07:06 | So, once you've got it working, you
don't even want to see it anymore.
| | 07:09 | But it is worth experimenting with
these files, with changing a couple of them
| | 07:13 | so we can follow the process of creating
a pass and understand what our server-side
| | 07:19 | technology would need to do.
So, next up, I'm going to create one of my own.
| | Collapse this transcript |
| Configuring the pass.json file| 00:00 | I am going to make my own
coupon pass for Passbook.
| | 00:03 | A coupon is the simplest pass so we can explore
some of the options available in the pass.json file.
| | 00:08 | So, I have the Passbook Materials disc
image loaded here, and inside Passes I'm going
| | 00:14 | to grab the Coupon.raw folder because
it's on our read-only disk image.
| | 00:18 | I am going to drag it over to my
desktop to make my own copy of it.
| | 00:22 | Go into that folder and what I'm
interested first off is the pass.json file,
| | 00:30 | and I'll open that up in Xcode.
| | 00:33 | Again, you can use any editor you want,
there is nothing special about Xcode here,
| | 00:37 | we're just working with a single file,
not working with any kind of project.
| | 00:40 | Now when you start to really work with these,
one thing that's useful is to go to that Developer
| | 00:45 | Passbook page and make sure that you have a
copy of the Passbook Package Format Reference on hand.
| | 00:51 | You can download a PDF version of this if you want to.
It's a pretty short document.
| | 00:55 | I think it's less than 20 pages.
| | 00:58 | So, what I'm going to do with
this JSON file is change it.
| | 01:01 | I don't want to write it from scratch, I'll change
what Apple has provided here and make my own one.
| | 01:06 | Now I want to make a buy one
get one free limited time coupon.
| | 01:09 | So, the top of the pass.json file, this first
section is the standard keys needed in every
| | 01:15 | passbook pass no matter the style. I won't
go through every single option, but I will
| | 01:20 | talk about the most important ones.
| | 01:23 | The first one at the top here is the
passTypeIdentifier, this is very important.
| | 01:27 | It must be the same as the certificate
will use to sign the pass.
| | 01:31 | I haven't made the certificate yet,
but I will do that in a moment.
| | 01:35 | So, this value here, pass.com.pawplanets.coupon,
is the one Apple were using.
| | 01:41 | So, I need to use one for
me or for my organization.
| | 01:45 | The way these are written, they are quite
similar to things like organization identifies
| | 01:49 | that you'd use when creating a project, and
that it's usually written reverse DNS style.
| | 01:54 | So, com.mycompany.something, though for
passbook it should also start with pass dot.
| | 02:00 | So, I'll have pass.com., and I'm going to
say twotreesoliveoil.coupon, twotreesoliveoil
| | 02:10 | is a website name that we often use at lynda.com
for examples and they should make my pass
| | 02:17 | type identify unique. Nobody else should be
attempting to sign passes with that same ID.
| | 02:22 | Beneath that we have serialNumber, this is
completely up to you but should be a unique
| | 02:26 | string, so you can track
whether it's been used or not.
| | 02:30 | Again, the tracking of whether a coupon has
been used is completely up to you.
| | 02:34 | Passbook doesn't care, it's just a
place to hold a unique ID.
| | 02:38 | This doesn't need to follow a particular format.
| | 02:40 | Although no two passes that you create under your
pass type identifier should have the same serialNumber.
| | 02:46 | Again, this would usually be
generated by your back-end system.
| | 02:49 | So, I am just going to put
something vaguely random in here.
| | 02:56 | Under this we have teamIdentifier. Well, this
is not random. This is the 10-character team ID
| | 03:02 | you can get from the developer portal.
| | 03:04 | If you're part of an iOS develop team or have
a team ID, if you are just an individual you'll
| | 03:08 | have an individual ID, and you can use that.
| | 03:11 | It's not hugely important for what we are
doing here, but we do need it in this file,
| | 03:16 | and the idea is that if I use this team ID
for creating my passes, and then I publish
| | 03:22 | an iOS app to the App Store
that uses the same team ID,
| | 03:26 | well, that app can access my passes and
passbook and get to them programmatically.
| | 03:31 | So, I'm just going to type
in my own ID that I have.
| | 03:36 | Below that we have authenticationToken and
webServiceURL, these two lines are worked together.
| | 03:42 | They can be used if we want to support
dynamically updating this pass over the web.
| | 03:47 | Now that would be done using Apple's Push
Notification service, which is beyond the
| | 03:51 | scope of this introduction, and
it would be overkill for a coupon anyway,
| | 03:55 | so I'm pulling both of these lines out.
Next we have barcode.
| | 03:59 | As I explained earlier we work with the most common
2D barcodes, that's the built-in support in Passbook.
| | 04:06 | This one is using the PDF417 format, and
you can pretty much say anything that you want
| | 04:11 | to, it could be a completely unique message,
it could be just the address of a web page,
| | 04:16 | or a website, it's totally up to you.
| | 04:19 | messageEncoding is pretty much always
left to iso-8859 classic Latin encoding.
| | 04:26 | Now very briefly talk about locations here
Locations is part of the idea of something
| | 04:31 | called relevance of a pass.
| | 04:33 | Now it can either be
location, or it can be a date.
| | 04:37 | With locations you get the opportunity of
giving it several potential position of longitude
| | 04:43 | and latitude and depending on the pass you
select, that can mean that, that pass will
| | 04:47 | appear in the lock stream when it's
detected you're at that particular location.
| | 04:51 | If you are working with a boarding
pass, you can also use a particular date.
| | 04:55 | I'm not really interested in either for
the purposes of this example, but this is
| | 05:00 | the whole idea of relevance.
| | 05:02 | A coupon that we're doing here can work with
location as relevance, it cannot work with date.
| | 05:07 | And you'll find more information
about that in the package reference guide.
| | 05:11 | After this things get a little easier, we get a
bit more obvious options here, organizationName,
| | 05:17 | logo text, and description.
| | 05:19 | So, we'll change the organizationName to Two
Trees Olive oil as well as the logoText, which
| | 05:24 | is what will show up on the actual pass itself,
give it a basic description here that's used
| | 05:31 | by the accessibility parts of iOS.
| | 05:35 | Now we have foregroundColor and
backgroundColor, think of this as pretty much
| | 05:41 | the text color and the background color so I am going
to leave the text at 255, 255, 255, which is white.
| | 05:47 | Again, just a more muted background, and I'll
pick this. Then we jump into the primary fields.
| | 05:53 | I'm going to change this so it changes our
offer to Buy one get one free, and that we
| | 06:02 | expire on the 31st of March.
| | 06:07 | And finally, in here we have the area called
backFields. This is what's on the back of the
| | 06:12 | pass, when they flip it over it's got an example
TERMS AND CONDITIONS, you can have anything you want here.
| | 06:17 | The thing about backFields is you pretty
much just copy this general format, inside the
| | 06:22 | square bracket, I can put another set of
curly braces and inside that just key value pairs
| | 06:29 | to match the whole key, label, and value setup.
| | 06:35 | And that should pretty much do it, I am
going to save that JSON file, and in my excercise
| | 06:42 | files for this chapter, I do have a couple
of logos that I can use here, just kind of
| | 06:48 | drag them into the coupon and replace them.
| | 06:52 | For my examples, I am just going to use logo and logo
at sign 2x, I am not going to bother with the icon here.
| | 06:58 | Again the recommendation from Apple is that
if you have a monochrome version of your logo
| | 07:02 | all in white, then use that. For information
on the logo sizes, just go to the Passbook
| | 07:08 | area of developer.apple.com, go into
Passbook programming guide, and you'll find a section
| | 07:15 | called Pass Design and Creation and in that
images fill there allotted spaces, and there
| | 07:20 | is information in here up on the suggested
sizes for things like icons and for things
| | 07:25 | like the logo image, how much
space do you have to play with.
| | 07:29 | So, I have everything now ready in this folder.
| | 07:33 | I want to be able to bundle these all up
and sign them and turn them into a pass.
| | 07:37 | So, next we'll see how to sign these,
package them up into a single pass file.
| | Collapse this transcript |
| Signing and using a custom pass| 00:00 | I have all the pieces ready in a folder on
my desktop, but I need to have a certificate
| | 00:04 | set up with Apple to allow me to sign this pass.
| | 00:07 | So, I am going to jump over to the
Developer site and into the iOS Dev Center, sign in,
| | 00:14 | and then go to the Provisioning Portal.
| | 00:16 | There has been a new section added to the
portal to support Passbook, which is Pass
| | 00:20 | Type IDs over here on the left-hand side.
| | 00:23 | Now with the idea that I'm using here, I
actually don't have one, so I am going to click the
| | 00:27 | button to create a New Pass Type Identifier.
| | 00:31 | First, I give it a description, which is
pretty much anything I want, something meaningful.
| | 00:34 | Well, this is going to be for creating
coupons for the Two Trees company.
| | 00:38 | So, I'll call it Two Tree Coupons, and
then we have to give it the formal identifier.
| | 00:43 | This is the part that must match what we
have in our JSON file in that reversed DNS format.
| | 00:49 | So, for me its going to pass.com, there we go,
twotreesoliveoil.coupon, and you can double-check
| | 00:57 | in your JSON file just to make sure what you
have in that first pass type identifier section.
| | 01:02 | This needs to exactly match what you're doing
for the certificate as well as this teamIdentifier
| | 01:08 | needs to be either your team or
your individual ID in the portal.
| | 01:12 | So, back over here, this looks
correct, I am going to hit Submit.
| | 01:16 | Now we have that ID, but we don't
actually have a certificate for it yet.
| | 01:20 | So, I need to go ahead and click this Configure button
and then in this screen click the Configure button again.
| | 01:26 | We now need to get set up for a little bit
of back and forth with Apple, because what
| | 01:30 | I'm asking for is a certificate.
| | 01:33 | It's going to give it to me, but I need to
generate something on my end so that I can
| | 01:37 | sign passes on this computer.
| | 01:39 | So, it's telling me first to launch Keychain
Access on my own computer, so I'll bring it
| | 01:44 | up there and then from the Menu go down to
Certificate Assistant and Request a Certificate
| | 01:50 | From a Certificate Authority.
| | 01:53 | I need to type in my email address, common
name, just something meaningful here so that
| | 02:01 | it has meaning to me when I see it in keychain access,
and then I am going to choose to save it to the disk.
| | 02:06 | Now if you are sitting there thinking how
I'm meant to know all this, well it is going
| | 02:09 | to tell you here on the
website exactly what to do.
| | 02:12 | So, I'll click Continue, and it will save
a signing request to the desktop, I'm done
| | 02:18 | with this part of keychain access, I go back
to the website, hit Continue there, it's going
| | 02:23 | to ask me to upload that file.
So, I'll choose it and click Generate.
| | 02:29 | Now it's going to generate me that certificate
and in a moment give me the option to download it.
| | 02:35 | I'll click Continue and Download.
| | 02:38 | And I don't just want to
download it, I want to install it.
| | 02:41 | So, I'll go and find where it was downloaded,
I have a couple from before so I am going
| | 02:46 | to remove the older one that I have to the
trash that's the new one that I just downloaded
| | 02:50 | here, and I'll double-click it, which
will install it into Keychain access.
| | 02:57 | I actually should be ready to go, I'm done
with the Provisioning Portal. Well, what next?
| | 03:02 | Well, I need to run a little program to
actually sign this, to combine all these files together
| | 03:08 | in this folder into that signed pkpass file,
and the way I am going to that is jump into
| | 03:13 | my Passbook Materials, that disk image that
I downloaded from the Apple Developer site,
| | 03:18 | and I'm looking for this, the signpass project.
| | 03:21 | I'm going to just copy this to my desktop
here just so I have a copy that I can change
| | 03:26 | and alter if I need to.
| | 03:29 | Open it up in Xcode. I am not going to
change anything about this project but I am going
| | 03:33 | to go ahead and just to Run, which is going
to build it and compile it into an executable
| | 03:38 | on my disk which I am going to use in a moment.
| | 03:40 | But the most useful thing it does is pop up
a little message telling me how I'm supposed
| | 03:45 | to use it, which is the name of the program
signpass, a little flag -p, and then I give
| | 03:50 | it a path to the contents of the
folder, or actually to the folder itself.
| | 03:55 | I can optionally give it
the path to a certificate.
| | 03:57 | I won't need to do that because my certificate
is already loaded into Keychain access
| | 04:02 | for everything I do on this machine.
So, how do I get to this application?
| | 04:07 | Well, if I expand my files over here in
the Products folder I should see the compiled
| | 04:12 | executable, because it's Xcode it's put up
this derived data this rather long location,
| | 04:17 | which is fine, I could copy it to my own
Documents folder or some other location.
| | 04:22 | But for purposes of time, I am just going to
right-click the executable file and choose
| | 04:27 | to show it in the finder and then
right-click it and click Get Info.
| | 04:31 | And I am just going to copy the path to
that location, Command+C, and open up a Terminal
| | 04:40 | window, just increase the front a little bit,
paste in the path, that will take me take to
| | 04:45 | me the folder, so then forward slash, and
the program itself is called signpass, -p and
| | 04:52 | a space, and then the address of the folder that
contains everything that I want to package up.
| | 04:57 | Well, that's in my Home folder so ~/Desktop,
and it's called Coupon.raw, and here is where
| | 05:06 | I find out if there's any issues
with any change I made to the JSON file.
| | 05:09 | What is starting to do here is give me
these messages that it's starting to combine all
| | 05:14 | these PNGs together. I do get a message here saying
couldn't find a pass type identifier in the past.
| | 05:20 | Well, I know there is one there. This is the
common error you'll get if you make any mistake
| | 05:25 | with the JSON file, you forget to close
a curly brace or do something like that.
| | 05:29 | So I'm going to jump back over into the
JSON file itself, open that up with Xcode, and
| | 05:39 | I could scan it but I actually
know where I made a mistake here.
| | 05:43 | Which is down near at the bottom.
| | 05:44 | In the last movie, I'd added some extra
back fields here, which was a set of key it has
| | 05:49 | for just a phone number, it can be whatever
field I want, but I really needed a comma after
| | 05:55 | the closing curly brace here
and the opening curly brace here.
| | 05:58 | So, I'll try that I'll save it, close that
one down, go by to my Terminal window, just
| | 06:05 | hit the up arrow to find
that previous option, hit it again.
| | 06:10 | Now this looks good its actually asking me
does it have access to get to my Passbook keys?
| | 06:14 | And yes it does, I'll say Allow,
I could say Always Allows as well.
| | 06:18 | We don't get any kind of message saying that
worked successfully, but if I go and look at the
| | 06:22 | desktop, I have Coupon.pkpass
that's the signed pass file.
| | 06:28 | So, let's make sure this works. I am
going to open up my iOS Simulator.
| | 06:31 | If you don't have an icon to it,
again, open it up through Xcode.
| | 06:34 | I am just I am going to jump into Passbook
first just to let you know I have deleted
| | 06:39 | all the passes that I had in there.
| | 06:40 | So, my passbook is empty and now go ahead
and drag this into the simulator, it will open
| | 06:46 | up in Safari, and let me take a look at this.
| | 06:48 | I have got my logo loading in, I've got my
backgroundColor and foregroundColor of white,
| | 06:52 | I have got this Barcode being generated.
| | 06:55 | If I flip to the back, I have that phone
number that I've added to the back fields, as well
| | 06:59 | as the terms and conditions, looks good.
I am going to click Add.
| | 07:06 | Now I should be able to find that in
Passbook and use it whenever I want to.
| | 07:10 | view it, switch to the back,
and when I'm done just hit Delete.
| | 07:18 | And that is the process for
configuring, creating, and signing a pass.
| | 07:23 | Now if you are going to substantially get more
into Passbook, then the Passbook for Developers
| | 07:27 | page is your primary jumping off point.
| | 07:29 | You'll find information here on everything
we just covered as well as taking it further,
| | 07:33 | like working with push notifications to
update passes that are already in passport, like being
| | 07:39 | able to push a changed gate or
departure time to a boarding pass.
| | 07:42 | And there is also information here on working
with Pass Kit, which is the fairly small framework
| | 07:49 | that Apple provides if you want to actually work
with Passbook passes within an application itself.
| | 07:56 | And there's references here on the Passbook
web service on downloading Passbook images,
| | 08:01 | badges you can use in your
own emails and your own websites.
| | Collapse this transcript |
|
|
4. Additional FrameworksPosting to Facebook with the Social framework| 00:00 | In iOS 5, Apple integrated Twitter support
directly into iOS, and now with iOS 6, they
| | 00:06 | have added Facebook support and support
for the Chinese blogging service, Sina Weibo.
| | 00:13 | These three services are
directly integrated into iOS.
| | 00:17 | What I mean by integrated is not that there's a
Facebook App or Twitter App right out of the box.
| | 00:22 | But there are system-wide settings in the
operating system itself that allow the user
| | 00:27 | to be signed into one or more of these services,
and this one setting is then accessible across
| | 00:33 | all the apps on the device.
| | 00:35 | For me, even on the simulator I immediately
get Twitter and Facebook settings.
| | 00:39 | I don't see weibo here, by default it doesn't
turn on unless its detected some kind of Chinese
| | 00:44 | support activated in the operating system.
| | 00:46 | But if I'd activated say a Chinese keyboard, I'd
suddenly see that appear in the settings as well.
| | 00:52 | And your application can detect if the user is
signed into any of these and use that information
| | 00:57 | to post directly to the account.
| | 00:59 | And there is a controlled and formalized
presentation to do this automatically using a slightly
| | 01:04 | different user interface for each service.
| | 01:07 | So to work with this we work with the new
Social Framework in the iOS 6 SDK that makes
| | 01:13 | it very easy, and the Social Framework is a
very simple framework, there are only two classes
| | 01:19 | here, and we're really only
interested in one of them.
| | 01:22 | Now if you used Twitter integration in
iOS 5, you use the Twitter framework.
| | 01:26 | We'll note that the social
framework basically replaces it.
| | 01:29 | The Twitter framework is now officially deprecated,
you shouldn't use it anymore because the social
| | 01:34 | framework supports Twitter and does
everything the Twitter framework did.
| | 01:38 | So there are only two classes in this new
framework, the user interface is already provided,
| | 01:42 | and it even works on the simulator, so let's see
how to post to Facebook right out of our application.
| | 01:48 | I'm going to jump over into Xcode where I have
made a very straightforward one-button application.
| | 01:54 | All I've done here is add a button called
post to Facebook and just connected up to
| | 01:58 | an IBAction called composePost.
| | 02:00 | Well, what I need to do first is this is a
new and separate framework, so I'm going to
| | 02:06 | need to link to it, I'll jump to my PROJECT
settings, select TARGETS, and go over into my
| | 02:11 | Build Phases where I will link it with the
new library, select Social.framework, and Add.
| | 02:22 | Next up, jump back into my ViewController
implementation file, and I really need to do
| | 02:27 | an import statement for that
social framework header file.
| | 02:31 | But here using the angle brackets
because it is a built-in framework.
| | 02:40 | That's my setup done, now I can jump into
this new composePost method that I've added.
| | 02:44 | This is what's called when the button is
touched, and this is all I need to do, I'm going to
| | 02:49 | generate an instance of the new SLComposeViewController,
call it socialPost, and rather than an alloc and init,
| | 03:02 | I'm going to call the method of the
SLComposeViewController that is composeViewControllerForServiceType.
| | 03:11 | This takes officially an NSString as a parameter,
but there are some predefined Enums here that
| | 03:15 | I can just use which is SLServiceTypeFacebook,
one for Sina Weibo, and one for Twitter.
| | 03:22 | I want the Facebook one, and that will give
me that viewController, and all I need to do
| | 03:27 | is nothing special, just call self presentViewController,
we'll make sure to animate it, and I'll just
| | 03:38 | set nil for the completion handler,
two lines of code, save that, run it.
| | 03:46 | The application opens, I have this button, post
to Facebook, it pops up this modal Facebook sheet.
| | 03:54 | I can type in some text here, I can add the
location if I want to, I could cancel out of it.
| | 03:59 | If I click the Friends options, it actually
looks up the account details of my Facebook
| | 04:05 | account and finds my audiences
that I've posted in here.
| | 04:08 | I don't have many, but I've got some here.
I'm just going to select Only Me and then Post.
| | 04:14 | That's it, one of the reasons this worked is I was
already signed into this account on the simulator.
| | 04:20 | If I hadn't been, it would have thrown an
error telling me that it can't do that and can you
| | 04:25 | go to the Settings and sign in properly.
But let's take it a little bit further.
| | 04:31 | Jumping back in, most typically in a method like
this, I'd actually want to check programmatically
| | 04:38 | to see if they are logged in. Perhaps I'd
even turned the button off if they weren't.
| | 04:42 | It's very simple to do in an if statement, there is
a class level method on the ComposeViewController,
| | 04:49 | so I don't even need to have created an
instance of it yet called isAvailableForServiceType.
| | 04:54 | And we just use the same service type options that I
have below ServiceTypeFacebook, ServiceTypeSinaWeibo,
| | 05:03 | ServiceTypeTwitter. So if that return to I
could then create that social post for the
| | 05:09 | ServiceTypeFacebook and pop
it up on the view controller.
| | 05:14 | Though a word of warning, I'm not going to
worry too much about doing this because as
| | 05:18 | far as I can tell when
you're working in the simulator,
| | 05:21 | the response from isAvailableForService type
is always true. It will return true when asked
| | 05:27 | about any of the three services
whether you're logged in or not.
| | 05:31 | Though it does work fine on an actual device, it
just all seems to return true on the simulator.
| | 05:36 | Now these are my options I can also do after
creating this ComposeViewController, but before
| | 05:41 | I actually present it, we've got methods like
setInitialText. That as you might imagine will set initial
| | 06:01 | text of what you're about the post.
| | 06:06 | There are also options on it for adding an
image, adding a URL, and it all just works.
| | 06:12 | Now the last thing is the default behavior
is either when the sheet is sent or canceled
| | 06:17 | the modal pop-up is just dismissed.
| | 06:19 | If you want to capture that happening, you
can create your own completion handler that
| | 06:23 | would pass in to
presenting that view controller.
| | 06:27 | But that's it post to Facebook out of
your application and a few lines of code.
| | 06:32 | Because you may have users that are signed
into multiple services, there is another new
| | 06:36 | control that can provide a more standardized way
to choose between multiple ways of sharing content.
| | 06:42 | But I'll talk about that when I
talk about the changes in UI kit.
| | Collapse this transcript |
| Improvements to existing frameworks| 00:00 | In iOS 6 as well as the new frameworks like
Pass Kit and the social framework, we have
| | 00:05 | a few additions to existing
frameworks worth covering.
| | 00:07 | Well, technically there are always a lot of
minor changes to the frameworks between versions
| | 00:12 | of iOS, so I am going to quickly cover
what I consider the most important changes.
| | 00:16 | To go into more specifics, take a look
at Apple's documentation. First, Maps.
| | 00:21 | Well, we've had MapKit as a framework for
quite some time, but the bit change in iOS 6
| | 00:26 | is Apple switching off using Google's
mapping infrastructure and starting to use their own.
| | 00:31 | Now this got off to a shaky start, but this
is the way we need to use if we want to work
| | 00:36 | with built-in maps in iOS.
| | 00:39 | If you weren't aware of this, you now
have the Maps app running in the stimulator.
| | 00:43 | And whether you are using this application to
compare or creating your own app, the stimulator
| | 00:48 | has a lot of features here. It has a menu
option for example under the Debug area
| | 00:53 | to change to a custom location.
| | 00:56 | And even to recreate a journey at multiple speeds
by just passing fake data to the stimulator itself.
| | 01:03 | Previous versions you could do some stimulation
of location and the scheme, but this is a great
| | 01:06 | way to test an application.
| | 01:09 | Now if you are writing an app that provides
turn-by-turn directions, whether that's for car
| | 01:13 | or public transport or bicycle or even walking,
you can register that app as a routing, or rooting, application.
| | 01:21 | And what that will mean is your app can show
up in search results when people start searching
| | 01:26 | for particular directions in
the Apple Maps application.
| | 01:30 | And in iOS 6.1 released at the end of January,
there is a new class called MKLocalSearch
| | 01:36 | that allows you to programmatically search
for points of interest and addresses the same
| | 01:40 | way a user might manually search
for something in the Maps application.
| | 01:44 | But although the infrastructure has changed,
the core concepts of how you work with maps
| | 01:48 | and core locations in iOS remains the same.
Next, on to EventKit.
| | 01:54 | EventKit was added back in iOS 4 for
working with calendar data, but we've had a couple
| | 01:59 | of worthwhile additions this time around.
| | 02:01 | The main thing is we can add, edit, and delete
reminders directly from our own applications
| | 02:06 | and those are stored in the classic EventKit
store and they do behave just like the ones
| | 02:11 | created in the reminder's application itself.
They can be time or location based.
| | 02:17 | The reminders app itself does not exist in
the stimulator, so you will need to test that
| | 02:21 | on a device if you want to prove that it works.
I am moving on to a couple of others.
| | 02:26 | Both the GameKit.framework for Game Center
and the StoreKit.framework for supporting
| | 02:31 | in app purchase are really specific enough
to need their own courses but there's a couple
| | 02:36 | of things here worth mentioning.
| | 02:38 | In GameKit there is new ViewController
called GKGameCenterViewController that clears up
| | 02:43 | the previous situation where you had to use
different view controllers, one to show
| | 02:48 | achievements and another I want to show
leader board information, and it combines them
| | 02:52 | into one master view controller
for the entire game center.
| | 02:55 | There are also new classes to allow one
player to issue a challenge to another and several
| | 03:01 | improvements to matchmaking
and the player display.
| | 03:04 | I am moving on to this StoreKit.framework
that handles in-app purchase.
| | 03:08 | Well, now you can support purchases of regular
iTunes content from inside your app, not just
| | 03:14 | your own content that you are selling, but
standard music, apps, movies, books, and so on.
| | 03:19 | And one great thing they are also supporting with iOS 6
is Apple can now host downloadable content for you.
| | 03:26 | Previously if you sold downloadable content
in your application, you had to control and
| | 03:30 | manage that downloadable content yourself,
control those service, and provide the ability
| | 03:35 | for uses to restore previous purchases.
| | 03:37 | But now you can host it all with
Apple, making that story a lot simpler.
| | 03:42 | So these are worthwhile changes to point
out, and then in the last movie, I am going to
| | 03:45 | cover the changes in the UIKit.
framework that we haven't yet seen.
| | Collapse this transcript |
| Changes in UIKit| 00:00 | Earlier we spent some time going through
auto layout and a great new collection views in
| | 00:05 | iOS 6, but there are some other improvements we
should explore about the commonly used classes.
| | 00:10 | Now one of the reasons for doing this is it's
very easy to get into the habit of using our
| | 00:14 | favorite classes without realizing that
there may have been some big changes to them.
| | 00:20 | So to get us started,
let's talk about UITableView.
| | 00:22 | Well, there was something I did mention in
the collection view section, but I will make
| | 00:26 | it explicit here, there are
improvements in reusing cells in a Table view.
| | 00:32 | One of the classic methods people have been using
for years is the dequeueReusableCellWithIdentifier.
| | 00:39 | We ask the tableView to do this, are
there any reusable cells? And typically we would
| | 00:43 | write a little line of code that says, if
that returned nil, well, then we have to go
| | 00:48 | and make one, we have to go and instantiate one.
| | 00:51 | But this dequeueReusableCellWithIdentifier now
has an additional method with an external parameter.
| | 00:57 | So it's dequeueReusableCellWithIdentifier for
indexPath, and indexPath is always passed in.
| | 01:04 | The behavior of this is slightly different.
| | 01:06 | As long as you have tagged the cell on the
story board or registered a class with the
| | 01:10 | tableView this will always return an object.
| | 01:13 | So cell should never be nil, you
just don't need that code anymore.
| | 01:17 | Not a major change, but something that
makes it just a lot more pleasant to write.
| | 01:22 | Now also when working with UITableView, there
are new explicit classes for headers and footers,
| | 01:27 | and really what they have done here is take
a leaf out of the UI collection view stuff
| | 01:32 | that we explode earlier.
So there are actually new object types.
| | 01:35 | There is a UITableViewHeaderFooterView
which can act as either the header and the footer
| | 01:40 | and then there are new methods like
dequeueReusableHeaderFooterViewWithIdentifier.
| | 01:46 | Very similar to collection views, and it's
going to make it quite easy to jump between
| | 01:49 | the table and collection views as you need to.
| | 01:52 | Next up is a new control in
UIKit called UIRefreshControl.
| | 01:58 | This is a new standard
control to use with a Table view.
| | 02:01 | It's the official implementation of what has
slowly been becoming an unofficial standard
| | 02:06 | for the last couple of years.
| | 02:08 | The idea that if you have a Table view of
dynamic data and you want to refresh it,
| | 02:14 | you pull down on it to refresh the data inside it,
and you get a little progress bar up at the top,
| | 02:18 | refreshes the data, you pull down again,
this is now being used in the Mail application,
| | 02:23 | it's used in a lot of
Twitter applications, and so on.
| | 02:26 | So this object now exists formally in
UIKit with the animation already built in.
| | 02:32 | So it's UTRefreshContorl, it's
instantiated and added to UITableView.
| | 02:36 | I do have a simple sample project in the
excercise files if you want to see one being used.
| | 02:42 | When it's pulled down, it kicks off a
refresh event, you could use that to go and fetch
| | 02:47 | some data, when the data comes back, you
call the refresh event again, and you make
| | 02:52 | that little control go away.
Not all table views will need it.
| | 02:56 | For example, if you are working with
something like the Settings view, there is no benefit
| | 03:00 | to pulling down on this and putting in a Refresh control,
but it's very nice to finally have it built into iOS.
| | 03:06 | Next up is an important one.
| | 03:08 | Autorotation is changing in iOS 6. The
classic thing that we have been using for years is
| | 03:13 | this shouldAutorotateToInterfaceOrientation method.
This is officially now deprecated in iOS 6.
| | 03:22 | It's a slow movement away from this, though.
Instead, we have other options.
| | 03:26 | We have a SupportedInterfaceOrientations method and
also a PreferredInterfaceOrientationForPresentation.
| | 03:35 | The reason for these is Apple is actually
slightly moving towards a more flexible, a
| | 03:40 | more powerful way of handling orientation
that gets us past just the default it's either
| | 03:45 | portrait or it's landscape.
| | 03:47 | Well, no, it can be a bit more flexible than that when
there is views within views and subviews within subviews.
| | 03:54 | So what I expect to see,
shouldAutorotationToInterfaceOrientation
| | 03:58 | and sample code for some time to come.
| | 04:00 | Just know that, that is officially deprecated,
and you should stop moving on to the new ones.
| | 04:04 | Now while we are talking about deprecated
stuff, if I'm looking at the UIViewController
| | 04:09 | itself, there is a couple of method you simply should not
use anymore, and that's viewWillUnload and viewDidUnload.
| | 04:17 | Now in the past, these were mainly used for
freeing up, releasing things you are holding
| | 04:23 | onto as part of the whole deallocation process,
but with the benefit of arc and better ways
| | 04:28 | that the view controller themselves are
constructed, you simply shouldn't need these anymore.
| | 04:34 | If you really must use some method for actually
getting rid of resources that you are holding
| | 04:40 | on to, use view will disappear or view did
disappear instead or possibly even did receive
| | 04:45 | memory warning if there is a problem.
| | 04:48 | But viewWillUnload and
viewDidUnload simply should not be needed.
| | 04:51 | Now there's a few updates to control like
the stepper and the switch to support basic
| | 04:56 | visual customization, and I am going to
leave things like that as something that you will
| | 05:00 | look up and research when you need it, not
something really worth committing to memory.
| | 05:04 | Finally, in this section,
the UIActivityViewController.
| | 05:08 | This is a new controller for working with
multiple possible built-in options, when you
| | 05:13 | have an item that you might want to send to
Facebook or to Twitter or to the Clipboard.
| | 05:18 | Now you've almost certainly seen this
if you've spent any time with iOS 6.
| | 05:22 | For example, if you are
working with the photos album.
| | 05:25 | You select a photo in the album, you click
the Sharing button that you find at the bottom
| | 05:29 | left, and what you get is this modal
window will appear with multiple options on it.
| | 05:34 | Do you want to mail this, do you want to put
it in the photo stream, do you want to tweet
| | 05:37 | this, send it to Facebook, copy it,
print it, what do you want to do?
| | 05:41 | This is the UI activity view controller.
| | 05:44 | It's very easy to instantiate as the options
for it are really based on what else is active
| | 05:50 | in the system, and it
doesn't take much to configure.
| | 05:53 | You instantiate it with an array of items
that could be just a simple text message,
| | 05:58 | it could be an image, it could be objects
if that makes sense, and it will do its best
| | 06:03 | to pass that information to whatever you choose,
Mail or the Facebook sheet or the Twitter sheet.
| | 06:09 | You can choose to exclude some of these services
if you know they don't make sense, but by default
| | 06:15 | everything that's available would be
included on the UIActivityViewController.
| | 06:20 | This is shown as a modal window on the
iPhone, on the iPad it's shown in a pop-over.
| | Collapse this transcript |
|
|
ConclusionGoodbye| 00:00 | Thanks for joining me
for iOS 6 SDK new features.
| | 00:03 | I hope you got a good sense of the most
important changes and additions in this version of iOS,
| | 00:08 | and that you now feel comfortable with
things like auto layout and collection views,
| | 00:12 | how to get started with areas like
Passbook and the social framework.
| | 00:15 | As ever keep a bookmark to the documentation
at developer.apple.com as they refine
| | 00:20 | and update the references for iOS 6 material and
keep an eye on lynda.com for more iOS courses.
| | 00:26 | Let us know if there is
anything you would like to see.
| | 00:28 | Good luck with your apps, and see you next time.
| | Collapse this transcript |
|
|