Introducing Text Kit

Session 210 WWDC 2013

Text Kit is the powerful new text engine and API in iOS 7, providing sophisticated text handling and typesetting capabilities. Learn about Text Kit and how easy it can be to manipulate text on the fly, adjust text attributes, and apply the power of Core Text with fewer lines of code.

[ Silence ]

Hi. I'm Ian Baird, iOS Text Kit Lead Engineer.

And today, I would like to talk to you about what I personally think is one of the coolest features in iOS 7, and I know you're going to want to use it in your app.

I want to introduce you to Text Kit.

First, let's lay out an agenda for today's talk.

We're going to talk a little bit about the motivation, why we created Text Kit.

Next, we're going to talk about what is Text Kit, how it's composed, and why you should care.

And then we're going to give you a quick tour of some of the headline features in Text Kit, and I think you're going to be impressed.

And finally, we're going to wrap up with an awesome demo showing you how to use and display Rich Text inside of your app in noble ways that you can only do using iOS 7.

So let's get started.

Motivation.

Why did we do Text Kit?

Well, quite simply, we needed it to realize the type of graphically heavy and complex designs that you see in iOS 7.

In the beginning, we had NSString sorry, we had String Drawing and we had WebKit which were both based on Core Text and Core Graphics.

And upon the stack, we were able to build almost all of the UIText components.

And this worked really well for many people.

And like yourself, I was a third-party developer and I made great apps using the stack.

But occasionally, it wasn't enough.

You'd have to drop down to Core Text to turn on kerning or to have ligated glyphs.

And as we all know, Core Text is very advanced.

I read your tweets.

I saw what you guys said.

As a matter of fact, somebody even called it a rite of passage.

And this complexity is really just inherent in the system because Core Text is an advanced Unicode layout engine.

You use it to build a complex text system or a web toolkit on top of it.

It's really overkill to use it to render a label especially when all you want to do is kern your text.

So that being said, the great thing about Text Kit and Text Kit's design is that if you've invested the time to come up to speed on Core Text, this time is not lost.

The way the system is layered, most concepts are Toll-Free Bridged to Text Kit.

You can use a CTFont for a UIFont, a UIFont descriptor for a CTFont descriptor.

It's that easy.

[ Applause ]

You know what, if you couldn't use Core Text, a lot of you would embed rich web content inside of your application.

And this is great.

UIWebView is awesome for embedding web content.

And the reason it's awesome is because it's built on WebKit and WebKit is the preeminent HTML rendering system for the mobile platform.

It's awesome, it kicks ass.

Unfortunately, there are a couple of places where you can't really use it, like in ScrollViews.

And this had unfortunate consequences for UIText components that were built on top of WebViews like TextView.

It made it really hard to use them in places like collection view or table view cells or anything which required animations.

So we were faced with all these challenges and we looked around the company to see what we could do.

How could we expose the power or Core Text without exposing our developers to the necessary complexity of an advanced Unicode layout engine?

And I think you're going to love our answer to this.

Our answer to this problem is Text Kit.

So what is Text Kit?

Well, if you are going to take away one point from my talk today, I'd like you to know that Text Kit is a fast, modern text layout and rendering engine.

It's built on top of Core Text.

And so this is awesome.

It gives you all the power and flexibility of Core Text without exposing you to the hairy API.

A hairy API which uses CF types which as we know are not necessarily aren't friendly or developer or easy for developers to use.

And even better, it features great, and I mean great integration with UIKit.

What does this do for you?

Well, it gives you everything that you want because it's built everything, all of the UIText components are built on top of Text Kit.

[ Applause ]

And as I was saying a moment ago, this gives you complete control over all of the text rendering in your UIText elements.

UITextField, UITextView, and UILabel were completely rebuilt on top of Text Kit.

And so this gives you seamless integration with animations, UICollectionView, and UITableView.

You won't get white flashes anymore.

Things scroll onto screen.

It also features an extensible object-oriented architecture with support for customization features like subclassing, delegation, and even has rich support for notifications.

If you're already using UIKit and other Cocoa frameworks, you know how to use Text Kit.

You know how to bend it to your will.

So, that's Text Kit.

The next thing I want to tell you about today is I want to give you a high-level overview of some of the headline features inside of Text Kit and how I think you can use them in your app.

And the first thing I'd like to start out with is something that was difficult to do in years past using text components we gave you.

Now, using Text Kit, it's easy to create paginated layouts.

It's easy to lay out text in columns.

Text wrapping around arbitrary figures and shapes, that's simple too.

And again, as I said, you even have superior control over Rich Text editing inside of your app, and this allows you to have access to features like interactive text coloring.

As the user types into your app, you can change attributes.

Let's pretend I'm building an interactive client for a popular internet messaging service.

Just pretend, this is hypothetical.

I type in my friend's handle, and it just sort of sits there in the content, just blending in.

And you know what I'd like to do, I'd like to view this with meaning, I'd like to make a pop out to user by coloring it and making it stand out from the rest of the content.

This is now easy to do with Text Kit, just a few lines of code.

Text folding is also easy to accomplish with just a few lines of code in Text Kit.

And next, this is one of the features I think you're going to think is the coolest, custom truncation.

Well, the great thing about the iPhone and one of the reasons that we love it is that it fits in your pocket.

The downside of that is the screen is incredibly small, even on the new iPhone 5.

And sometimes, especially when you're using some of the new text styles, not all of the content that your user has selected or you want to show to the user will actually fit on that display.

So in the past, you were stuck with tail truncation, head truncation, or middle truncation.

Using Text Kit and a few lines of code, you can have custom truncation now.

Also enhanced in iOS 7, all of these techniques work in standard controls, you don't have to subclass TextView to have custom truncation or text folding.

Isn't that cool?

[ Applause ]

And building on our heritage from iOS 6, in the attributed text support that we've brought to you in iOS 6, we have now extended UITextView and UITextField to support all text attributes.

[ Applause ]

And as Toby and Jason and everyone else with Toby this week, we've extended kerning and ligature support everywhere and we've turned it on by default.

And we've even given you simple single attribute access to advanced text effects like Letterpress.

If you want to know more about this, I would suggest that you see the session Advanced Text Layouts and Effects with Text Kit.

So, the next thing I'm going to tell you about is another thing that I think is just incredibly awesome in Text Kit.

And Jason and Toby and everyone else and Chris have been talking about this all week.

It's Dynamic Type.

What's Dynamic Type?

Well, Dynamic Type is a set of designed type styles which are made for you to use in your app.

They're optimized for legibility, so they're easy for your users to read.

And again, it's user-centric.

Your user is able to pick the size.

They can go small, medium, or large.

And there's rich support for accessibility built right in to Dynamic Type.

And there's great support for Dynamic Type in Xcode 5.

So, to really utilize Dynamic Type to its fullest potential, you're going to want to know about the next feature I'm about to show you.

Font descriptors.

Now, for those of you coming from Core Text, this is not necessarily all that new.

But for the rest of us who have been using iOS 6 and previous versions, it's really, really cool.

Font descriptors are a way of specifying one or more fonts, and you can interact with the font system by using a font descriptor for query to query for a font and it will return the results in the form of more font descriptors which then you can hand to the system and tell it, "Hey, create a font for this font descriptor."

This is a big improvement over the past.

In the past, you have to create a font, change the point size, apply a trait, a symbolic trait of some variety, and everytime you were doing this, the system was creating a font to back this UIFont instance in the background.

You don't have to do that with font descriptors.

They're super cheap and lightweight.

They can be archived.

And if you want to know more about using fonts with Text Kit, I urge you to see the session Using Fonts with Text Kit.

It's going to be really awesome.

So you have these fonts and they're working well for you.

But, maybe you get a design that says, "The new fonts are great but we just need bold here."

How are you going to do that?

Well, you're going to do that with symbolic traits.

You can see here we have our regular unadorned type styles, a nice list of them.

Let's apply bold and italic attributes, and you can see or sorry, symbolic traits and you can see what it does to those fonts.

We also have support for the expanded and condensed traits.

And if you want to affect the line spacing, we even have traits for that.

For example, the tight trait allows you to pack more text into a smaller area.

Now, when you do this, and I wouldn't recommend that you do it all the time, but you can do it in places like summary fields where information density is at a premium for your user, and you don't want sacrificing a little bit of legibility.

So you wouldn't want to do this all over your app.

And if you're embedding rich web content inside your app, I've got great news for you.

All of this is supported by WebKit.

And if you want to know more about the great enhancements to fonts in WebKit, you should see the session What's New in Safari and WebKit for developers.

Next, I'd like to show you how we built one of the components in the UIText world, the TextView.

Here's our simple TextView and it has a nursery rhyme in it.

Well, how was it built now?

In the past, it had a WebView backing everything.

The first thing you're going to see when you pull it apart is the NSTextContainer instance.

NSTextContainer is giving the NSLayoutManager the bounds, the geometry to render the text into.

And NSLayoutManager is taking all of the text from your NSTextStorage and turning it into lines of glyphs inside of your TextView.

But now that you understand how TextView is built, this unlocks other features for you.

Like, again, when we were talking about exclusion paths before, the way you do this inside of a TextView, the way you get support for simple figures and cutouts in your UITextView is to first create an exclusion path.

In this case, we're creating an exclusion path for a butterfly.

And then you would take this exclusion path, you'd pack into an array, and you'd set it on the text the exclusion path's property of the text container which is associated with your TextView.

And that's all you'd have to do.

At that point, the text just magically wraps around your figure.

It's that simple.

[ Applause ]

Thank you.

It's an easy and declarative model.

You'll notice, there was no subclassing or delegation involved.

So let's talk a bit more about text container.

What is a text container?

A text container defines a coordinate system and geometry for an NSLayoutManager.

As we talked about, exclusion paths live entirely in the NSTextContainer's coordinate space.

Hit-testing is also done in the NSTextContainer's coordinate space, and I'm teasing another big feature that we've enabled for you in TextViews in iOS 7.

Hit-testing.

In the past, whenever we laid out text [ Applause ]

I'm glad you like it.

In the past, when we laid out text, we immediately threw away all of the information, all of the extents, the glyph IDs, everything just went away and we gave you back a bit map.

Now, NSLayoutManager keeps all of this around.

And this is useful for you because now, if you want to resolve a tap to a character index, all you have to do is call this API.

User's finger comes down.

You get the index into your text storage, and bam, you have your character.

It's that simple.

In order to understand the next few features, we have to go over some front matter about glyphs.

What is a glyph?

A glyph represents one or more characters on the screen or the printed page.

An important thing to remember about glyphs is that there's not necessarily a one-to-one mapping from a glyph to a set of characters or vice-versa.

Now, you may wonder, "How do I do this mapping then?"

Well, the answer is our friend again, NSLayoutManager.

NSLayoutManager maintains this mapping of glyph ranges to character ranges and it's really easy to use.

Just call this API, pass in the glyph range and it will map, in the case, the FFI ligated glyph to the three characters it's representing and it can go the other way.

It's that easy.

And it will maintain this mapping through edits, programmatic manipulations, attribute changes, whatever you do, NSLayoutManager always stays up-to-date.

There are a whole host of new interaction features in TextView.

Now, in the past, you may say, "Well, you can always interact with links," and that's absolutely true.

But what it necessitated was it necessitated using data detectors and putting in a web style, maybe HTTP link.

What's new in iOS 7, and what I think you're going to love, is that you can turn any arbitrary text range into a link now using NSLink attribute.

[ Applause ]

Associate a URL with it, and now, you have a rich interaction model right out of the box that your users are going to love.

We still support data detectors, they're there.

You see, we have the Moscone Center address.

The user taps or long-presses, and up comes an action sheet filled with useful interactions for the user to choose from.

Now, in order to understand the next feature, I want to tell you about text attachments.

The text attachments have been a long time coming to our platform, but they're really cool and really useful.

And they're totally distinct from exclusion paths, and I'm going to tell you why.

Attachments live with your data.

They actually live inside of your NSTextStorage.

There's a character which is interpreted and has the attachment data associated with it.

They can refer to an image or something else.

An exclusion path lives inside of the text container.

It actually changes the geometry that the layout manager uses to flow text into.

That's the difference.

So what do you generally use a text attachment for?

A text attachment is usually used for inline images.

It affects text layout and it's affected by text layout.

And, of course, it contains the geometry for the contained data including a baseline offset.

NSLayoutManager is going to use this information to place the text attachment in line with the rest of your data.

And, of course, it has another simple interaction model.

The user long-presses on the picture, and up comes another action sheet.

Again, this is built right into the system.

To show you some of the stuff and how you can use it in your app, I'm going to invite my colleague Jordan Breeding to the stage to give you guys a quick demo.

[ Applause ]

Thank you, Ian.

The first part of the demo we'd like to show you today is the show for our demo application.

As you can see, I already have it running in the simulator.

What I'd like to call out is that this collection view is backed by collection view cells.

They contain UILabels and UITextViews.

That's right.

It's a full-blown UITextViews in collection view cells.

They scroll well.

There's no synchronization issues.

I didn't have to deal with any main thread and web thread synchronization.

To show you that I didn't actually do anything tricky, I'm going to open my storyboard, go into my cell, and now, I'm showing you that inside of my background container, I have a UILabel and a UITextView, and I'd also like to call out a specific feature that Ian pointed out.

New in Xcode 5, into interface builder, you can directly select the text style that you would like instead of the old system choices.

In this case, I had selected the text style of body because this represents some body text inside of our cells.

Now if I build and run again I can enter our first section of the real demo.

This is the basic interaction demo.

What we're showing you here is that we have some blocks of texts which do not match any data detectors.

And if you go in right now, you'll notice that neither the phone number nor the URL is actually interactive.

We'd like to make it interactive.

So we go back into Xcode, into interface builder.

We select the view that contains that data.

And just like in iOS 6, it's as easy as turning on the links and phone numbers data detectors which I've just done.

Now, if I build and run, building and running now, going into basic interaction.

You'll notice that phone numbers and URLs work perfectly.

Now, something that you might have had to do in the past is customize that behavior that you just saw.

You might not want your users to go to Safari when they tap on a particular link.

In the past, to achieve this, many times, you had to layout your content in a UIWebView and use the interaction model with their delegates to then force it to open in your application.

I'd like to show you that today, we've given you just that directly in UITextViews in iOS 7.

Going to go into the view controller for this.

And what I'd like to show you is right here, I implement the delegate.

I've set myself as the TextView's delegate in my storyboard.

And as you can see here, I just implement TextView should interact with URL in range.

In this case, I compare the host of the URL to www.apple.com and if that's what it is, then I open my own WebViewController instead of Safari.

Building and running to show you that now.

And now, when you're user goes to the apple URL, you'll see that it opens a WebViewController.

Your user stays in your application, doesn't leave your experience.

[ Applause ]

We thought you might like that.

Next, our designer gave us a spec for an exclusion path demo.

Our designers specified some body text upfront and gave us a butterfly image to put on the bottom right-hand corner.

They also specified that we should have a pan gesture recognizer so that the user could move the butterfly around.

The issue that you have upfront is that when the user moves the butterfly, the butterfly and its drop shadow affect the text and overlay it.

We'd like to show you how easy it is to fix that issue in iOS 7 with UITextViews.

I'm going to go into my exclusion path view controller.

First thing I'm going to do is drop in a method that I wrote upfront.

This grabs my precalculated Bezier Path for my butterfly.

In this case, I can precalculate it because the image never changes, just its position.

I pull my plist out of my bundle, then I need to make sure that my image rect for my butterfly is in the correct coordinate space.

And finally, I transform my Bezier Path to match where the butterfly currently is on screen and return that Bezier Path here.

In viewDidLload, I'll use the new one line support in UITextView to set the exclusion paths then I'll handle the case of layout occurring again.

Whenever layout occurs, we know that the butterfly could have moved and we need to match the Bezier Path to the butterfly.

So, I dropped in some code there, do a viewDidLayout subviews method and go ahead and update the exclusion paths there as well on our UITextView's text container.

Lastly, in our pan gesture recognizer action method, we know that the butterfly has also moved in this case.

So again, we drop in the one liner to update the exclusion paths.

Now, I'll build and run.

And now, in the exclusion paths, you can see how fluidly [ Applause ]

You can see how fluidly that butterfly moved throughout the text and let everything flow back around it.

So, what did you see in that demo?

You saw that we still support data detectors for basic interaction in TextViews but you also saw that now you can provide a delegate and you can customize some of your user's behavior when they interact with that information.

You saw brand new in iOS 7 that TextViews can be used in collection view cells and everything worked perfectly.

You saw how to use some of the new text styles in interface builder and in Xcode.

You can also use them in code.

And lastly, you saw our one line support for exclusion paths so that you can make great looking interfaces for your users.

Next, I'd like to turn it back over to my colleague, Ian Baird.

[ Applause ]

That was a great demo.

So now that you're faced with all of this coolness, the reality is probably starting to sink in that there might be some work involved in realizing some of these new designs that your designers and your clients and maybe even your friends and families start throwing at you once they see iOS 7.

So now we're going to tell you a little bit about some of the techniques you can employ to realize some of these designs you're going to see.

So that you can work on creating apps like messages and mail.

If you look at the design of messages and mail, you can see that the text is precisely positioned.

Everything looks balanced and clean.

And the content is front and center.

Well, I'm going to tell you, you want to get as far down the road as you can with Auto Layout because it's going to make your life incredibly easy.

But, once you get past what Auto Layout can do for you, you're going to need to understand a few more tips and tricks.

Let's start with an example.

The new mail view is broken up into sections.

You can see there are a couple of header sections and then there's a body section.

Each section is separated by a gray key line, and this key line is important, it's very important to get our text spaced exactly in the perfect place with respect to the positioning of the key line.

And our designer has driven this home by saying that we need to put the first line of the body text 0.8 times the cap height away from the key line.

You may ask, "What is this?"

To understand some of these new designs, you need to understand a few things about font metrics.

So again, if you have a detailed spec like the one we showed you in Mail, you'll need to become familiarized with things like line height.

This encompasses the ascender and descender of each glyph on the line.

As a matter of fact, it's called the typographic balance in this case of the line.

And you can get this from the font by asking for its line height.

The next thing you're going to want to understand is cap height.

Cap height is the distance from the bottom of the baseline to the top the capital letter in this case like the flat line of the A or the if you have a capital H, it's basically the two top parts, and that was the distance that our designers specified that we should position our text relative to.

Next, you're going to want to understand leading.

Leading is the space between the lines of text, and using Dynamic Type, remember that this leading can be negative to drive the lines of text closer together.

This causes the descenders from the line above to overlap with the ascenders from the line below.

Now, all of these designs need to be responsive and the user gets to derive the size.

How do you do this?

We're going to want to listen for UIContentSizeCategoryDid ChangeNotification.

Thankfully, we have auto complete, and this will be omitted when the users selects new size.

You want to setup this observation probably inside of your view controller, and maybe your app, and probably your view controller.

And you want to re-layout your UI when you receive this.

Well, if you're using Auto Layout, again, as we told you, you should probably do, you'll need to invalidate the intrinsic content size of your UIKitViews positioned by Auto Layout.

And this is a mouthful and it really boils down to, if it's a UITextView, or a text field, or a UILabel, simply resetting the font on that view will invalidate the intrinsic content size and Auto Layout will just layout everything for you.

It's that simple.

However, if you're doing pixel perfect positioning like the stuff I was talking about earlier, you'll want to call setNeedsLayout on probably a parent view to reposition all the child views using whatever magic formula you and your designer have come up with to position these views.

Another key thing to remember is that you need to invalidate any cached preferred fonts or font descriptors because these guys are no longer valid in the context of your user's new chosen font size.

So, there's a lot there but it's actually pretty simple.

It shouldn't be too intimidating.

And to show you just how easy it is, I'd like to invite my colleague Jordan Breeding up to the stage again to give you another demo.

[ Applause ]

Thank you, Ian.

The next thing we'd like to show you in this demo is how to deal with some of these complex designs and also how to account for your user changing their preferred content size.

Now, the first thing I'd like to show you is a user changing their preferred content size.

In this case, you can see what our current collection view looks like.

And as the user goes over to settings and changes their preferred content size going back to our demo, you'll notice that nothing happened.

Now, that's a very inconsistent user experience.

Your users expect their content to change when they change the content size.

So in this case, I'm going to go to my collection view cells instead of the collection view controller because the cells themselves know about which content needs to change.

First thing I'm going to do is declare a method that our notification can call when it happens.

In this case, I'm calling it PreferredContentSizeChanged.

Next, while I'm setting up our initial layout and state, I'll actually listen for that notification that Ian mentioned earlier.

UIContentCategory sorry.

UIContentSizeCategoryDid ChangeNotification.

When that notification fires, it will call our PreferredContentSizeChanged method.

Lastly, I'll drop in an implementation of PreferredContentSizeChanged.

In this case, I wrote a method upfront that just grabs the new fonts, places them on the views.

Everything is happy.

So I'll build and run.

Now, you'll see that things are laid out a little bit differently.

And again, when your users goes to change their text size oh, actually, I think I yeah, I did build instead of a build and run.

Now we'll see that the content is different.

And as we go back down, everything lays out automatically.

In this case [ Applause ]

In this case, another thing we'd like to point out is that each of these UITextViews was actually positioned inside of the cell using Auto Layout.

So all we did was set the font on the UITextView and it automatically invalidated the intrinsic content size and caused layout to happen.

The next thing we'd like to show you is a design specification from a designer.

In this case, our designer wanted a profile picture in the upper left as you can see.

A name, some text, and then a large run of text below it.

I'd like to show you how we actually achieved that using Auto Layout.

In Xcode 5, we were able to select the picture which was the most important element.

Our designer had told us that the element needed to be exactly eight points from the key line and from the left-hand margin.

And if I show you here, you can see some of these constraints.

Then the label flows from that, it's eight points from the image view.

And then some of the rest of the layout flows from there.

This container is positioned based on the left-hand side of the label above it and the right-hand side of the label above it.

And the final TextView is eight points from the things above it, and it's left and right margins are aligned with the items above it.

The reason that we did this is that you can adjust just a few things at the top and all of the rest of your layout will flow from there.

So, if we build and run again just to show you, all right.

And in this case, I could show you that if I go in and set the preferred content size, it's not currently responding.

So we need to make that happen.

What I do there is I go into my view controller superclass and I implement the same PreferredContentSizeChanged method.

In viewDidLoad, I know that I need to listen for the notification again and call PreferredContentSizeChanged, and have a base implementation of that.

Lastly, in the view controller for our designed part, we know that we need to override that method and do some extra setting of fonts and things.

So, I build and run.

And now you'll see that if I go in and change my content size, everything lays out automatically.

[ Applause ]

Thank you.

The one thing that you might notice is that the short block of description text truncated in a way that wasn't very pleasing to our user.

We didn't like this and neither did our designer.

So we're going to implement one last thing, brand new in iOS 7.

We can now set the line break mode on the text container of the TextView to get truncation by the text container instead of by the line or paragraph.

So instead of truncating to a single line or even a single paragraph, I've inserted this single line of code.

I'll build and run.

And this time, you'll notice that we truncated nicely at the end of the text container itself.

So, going back over to what we saw in that demo, we saw how you can realize fairly complex designs still using Auto Layout in Xcode 5 with interface builder.

We saw how you can respond to the change notification when your user changes their preferred content size and cause layout to occur again.

And we saw how in iOS 7, you can now customize the text containers line break mode instead of having to do it yourself by line or paragraph.

Next, I'd like to bring out my colleague, Johannes Fortmann.

[ Applause ]

Thanks, Jordan.

Hi, I'm here to talk to you about Interactive Rich Text.

Now, what do I mean by that?

If you've used the UITextView on iOS 6 before, you may recall that there, we provided the new attribute to set the attributed text on a UITextView.

Now, this attribute means that when you set it, the entire text in this UITextView will get replaced by the new NSAttributedString that you set the attributes to.

In iOS 7, we now provide a new attribute, text storage, that allows you to directly modify the attributed text on the TextView.

The text storage is a subclass of NSMutableAttributedString which means that you can get it from the TextView and modify it in place.

We send change notifications that will inform the LayoutManager about the changes that you performed on the text storage and performed very specific invalidation on only the parts of the text storage that you've changed.

That's a big, big, big performance win, since now, we don't have to invalidate everything when just a single character has changed.

Let's walk through how one of these changes works.

As I said, since the NSTextStorage is simply a MutableAttributedString subclass, we can use the standard modifications on the MutableAttributedString to perform changes.

So, assume that we have a TextView already here, and in this case, we have the beginning of the story "Alice and Wonderland" and we want to modify the name Alice for example to be read, to call it out in a way.

What we do since we have multiple occasions by the name Alice comes up, it's about her, the story, anyway.

So, it happens often.

We don't want to perform an invalidation for each of these cases why we modify the text storage.

So what we do is we bracket the changes.

Let me show you how that works.

First, we call the Begin Editing method on the text storage.

That informs our text storage that we're going to perform a batch of changes now.

Next, what we're doing is we modify each instance.

For example, we loop over the string, find out the ranges, and set the foreground color on each instance of the word Alice.

And finally, once we're done with all our changes and are happy with them, we call the End Editing method on the text storage.

Now, until now, nothing has yet changed on the actual visual representation, the TextView.

Only after the End Editing method has been called, the text storage will process each and every edit and inform the LayoutManager which then is able to recompute the areas that have actually changed and redraw the actual changes.

Next, I'd like to talk to you about subclassing NSTextStorage.

Now, why would we want to do that?

Well, as Ian showed you before, we might be writing an app for a popular messaging system, and in that case, we want to call out a person by their identifier.

We do know that these identifiers have a certain formatting.

So, in that case, we already know what to do once we see these identifiers.

After the user has entered the identifier, we want to immediately, and I mean, immediately change the truth, effectively the contents of our text storage to for example change the colors of this identifier.

To do that, we modify the methods on the text storage that actually change text on the text storage.

Now, NSTextStorage is class cluster.

That means that we as Apple provide an implementation of a superclass, that's the NSTextStorage class that is public in the SDK.

And we also provide an implementation of that superclass, a subclass, that is private but that's still vended out to you, the developer, if you initialize one of these objects.

This subclass provides the actual storage and attribute modification parts of the text storage.

Now, if you as a third-party developer want to provide your own custom implementation of a text storage, what you need to do is provide certain primitive methods on the text storage.

There are four primitive methods.

Two of them deal with actual static storage.

You can inquire the string and inquire about attributes, and the next two deal with actual modifications.

To show you how to actually implement this, I'm going to do a demo.

I've already setup in the same demo app here a TextView that has the text we saw in the slides and already entered.

I've also already created an empty implementation for custom text storage.

We're now going to try to use this empty implementation.

Well, we're going to fill it before we use it of course.

First, I need to actually make on my view controller an outlet for the custom text storage and, of course, I need to create an instance of my implementation.

Now, I'm going to do something slightly complicated here.

In Ian's in one of Ian's slides, you've seen that the TextView is backed by a text container which in turn is backed by a LayoutManager which in turn his backed by a text storage.

That means that I have to recreate this entire hierarchy to be able to put my custom text storage in there.

This is really quite simple since we're not going to do anything custom with these LayoutManagers or text containers.

So I'm just going to create a stock LayoutManager.

I'm going to also create stock text container within the size of our TextView in an infinite height.

I'm going to setup the text container such that its width tracks that TextView in case we resize the TextView.

And finally, I'm going to hook these two app.

I'm going to add the text container to the LayoutManager and add the LayoutManager to the text storage.

Finally, instead of creating a simple TextView here, I'm going to use the new in iOS 7, designated initializer for your TextView that takes it to custom text container.

So, I'm creating the TextView with this specific text container that I just made, and I assign and add it.

If I were to run this now, we would have a TextView that is backed by text storage that does not actually store anything because we have not implemented any of the primitive methods.

So let's do that.

I'm switching over to the text storage implementation here.

And what we want to what we need first is an NSMutableAttributedString that actually stores the data.

We need something to store attributes and strings.

So I'm creating an instance variable for my backing store.

In my initializer, I create a new MutableAttributedString for that backing store, and that's it.

Next, I'm going to implement the static methods string, it just returns the backing store string, and attributes at index returns the back attributes at the specific index.

The mutable methods look similar.

They just fall back to the backing store, but there is something different here.

We also need to inform our superclass, the NSTextStorage class, that we actually did some edits.

So I'm going to do that calling the Edit method on or myself to inform my superclass about the range that has been changed.

Now, next, I want to if I've changed characters, I want to remember that and perform modifications on those characters.

So implement a flag to remember if I changed something.

In my replace characters and range method, I set that flag and then I'm going to implement the process editing method that gets called when the final end editing call has been sent to the text storage.

I'm going to call super in there, and if the flag is set, I'm going to perform certain replacements.

These replacements are simple.

I'm going to find the range of the line that has just been edited and I'm going to apply some tokens to those to this range depending on the words in there.

These tokens are just dictionary of dictionaries in fact that apply attributes to the string.

Finally, in my view controller, I set the tokens.

I'm going to choose the word Alice to get the program color red and the word rabbit to get the program color orange.

Let's run this.

And now, if I type, you can already see without me typing the word Alice is red, the word rabbit is orange, and if I type, as soon as I'm finished typing, the word turns red immediately, same for rabbit of course.

What you've seen in this demo is how to assemble the text system by hand.

We've assembled the stock classes and inserted custom text storage.

We subclass the NSTextStorage to perform certain well, first of all, to actually work, and then finally, to use the subclass of the text storage, specifically the process editing method element to perform interactive modifications on the content while the user is editing it.

And with that, let's wrap this up.

Text Kit is an extremely powerful and new feature of iOS 7.

UITextViews as well as UITextFields and labels are first class citizens of UIKit.

They are usable in table views and collection views.

They support all the attributes that previously in iOS 6 NSString supported, plus a few more like links.

Using exclusion paths and simple overrides on in this case for the exclusion path, the text container, but also on NSLayoutManager or text storage, we are able to provide very pleasing UI for our users.

And finally, we've seen how customizable and extensible it is.

We were able to, in just a few lines of code, provide an implementation for one of the classes here and leverage that to perform something that was not possible frankly in iOS 6 before at least not in a performance way.

With that, if you have any questions, we have our frameworks evangelist, Jake Behrens around here.

I think he's sitting down there.

He's yeah.

We've got extensive documentation already out, I believe.

And finally, all of us text guys are regularly reading the forums and are happy to answer questions.

We've got three more sessions.

Well, one of them is already over but the Advanced Text Layout session tomorrow where Aki and Peter will show you how to override certain things on NSLayoutManager and use delegation to customize your text layouts even further.

And on Friday, we've got a session on Using Fonts with Text Kit.

We've got awesome new Core Text features providing for interesting modifications on fonts.

And the last one on Tuesday, we had a session about the among other things, the new CSS Style Values.

Thank you.

[ Applause ]

[ Silence ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US