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

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2012-230
$eventId
ID of event: wwdc2012
$eventContentId
ID of session without event part: 230
$eventShortId
Shortened ID of event: wwdc12
$year
Year of session: 2012
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2012] [Session 230] Advanced At...

WWDC12 • Session 230

Advanced Attributed Strings for iOS

Essentials • iOS • 48:47

Dive deeper into advanced techniques when using attributed strings on iOS 6. Learn about kerning, ligatures, and other advanced typographical features of string drawing to create compelling text effects.

Speakers: Ian Baird, Johannes Fortmann

Unlisted on Apple Developer site

Downloads from Apple

HD Video (360.7 MB)

Transcript

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

Good morning. I'm Ian Baird, label engineer for UIKit. And today I'm going to talk to you about advanced attributed strings for iOS or how to achieve desktop class effects on a mobile device. Let's get started. Today we're going to talk about three things. The first one is advanced attributes.

If you attended yesterday's introduction to attributed strings for iOS talk, you learned about some of the basic attributes. and today we're going to talk about more, of course. Next, we're going to talk about how to employ some of those attributes along with attributed strings to achieve awesome text effects for your app.

And then we're going to talk a little bit about the Extended String Drawing API, or more specifically, NSStringDrawingContext and NSStringDrawingOptions. So, let's get started. Advanced Attributes. Yesterday, Aki talked about some of the common attributes you would use when customizing an attributed string. I believe the first attribute he talked about was NSFontAttributeName. As you can see, we've changed our example text from using the system default font, which in this case was Helvetica Noia, to Heffler text using the NSFontAttributeName. also talked about how you could customize the color that we rendered the text in using NS foreground color attribute name.

We talked about NS paragraph style attribute name and some of the properties. I'll call out a couple right now. The first one we talked about was... The alignment property, which allows you to affect the alignment that we use to render the text. In this case, we've gone from center aligned to left aligned. Next, we talked about the line break mode, which allows you to affect truncation and word wrapping. We have allowed the text to word wrap in this case using NS paragraph style line break mode. So let's dive in.

The first advanced attribute I want to talk to you about today is, in my opinion, one of the coolest. It allows you to apply an outline to the glyphs we use to strike your text. So let's talk a bit about NSStrokeColorAttributeName and its partner, NSStrokeWithAttributeName. You can use them to achieve really cool effects in your app like this.

This was done by setting NS foreground color attribute name to yellow, which filled the glyphs with a yellow color, while setting NS stroke color attribute name to black. Now, there are a few points to remember about NSStroke with attribute name. We're going to go through them. If you supply a positive width, you're only going to get an outline on your glyph.

If you supply a negative width, we're going to stroke and fill your glyph. And if you don't supply a value, if you leave it nil, you're only going to get a filled glyph. We're not actually going to outline the glyph. Another really cool attribute that I'd like to talk to you about today is NSShadowAttributeName. This is also new in iOS 6.

It allows you to do cool things like apply a drop shadow to some or all of your text. You can see what this has done to the text here. It makes it appear to lift off the page, which is really, really cool. So how did we do this? Well, we brought over NSShadow from Mac OS.

If you've ever used an eyeshadow on Mac OS, you know that it can participate in drawing, and you can set it on a graphics context to set up a shadow. This is not the case on iOS. iOS uses a declarative model. So it's only used with attributed strings. We set up the shadow for you. We interpret the value. So it's only a value class on iOS. But there are some really cool customizations you can do. The first one being the shadow color. You can change the color we use to render the shadow.

Next, you can change the shadow offset by supplying a CG size to the shadow offset property of the NSShadow instance. And finally, you can change the shadow blur radius. Notice we've supplied a larger value to shadow blur radius, which has caused the shadow to appear to soften. Now, I know this is a big one for me and the designers in the crowd. In iOS 6, we now support proper text kerning.

I know we did it before in Cortex, but now we've brought it up to the level of UIKit and attributed string. This is done with NSKern attribute name. As you can see here in our example, we have changed our run of text to TwinVauses. And the reason we've done this is because it highlights a problem that you can currently see in the system. Notice that the words "twin" and "vauses" appear to have split off their beginning characters. The word "t" does not appear to be attached to "twin" and "v" does not appear to be attached to "vauses." Well, we can fix this by turning on auto-kerning like this.

Notice the "t" and the "w" have properly hugged together, and we fixed the issue of an improper distribution of horizontal space. So let's talk a bit more about some of the values you can supply to NSCurrentAttributeName. Now, it's important to remember that kerning will vary from font to font. For example, Heffler text may define kerning pairs which are not present in Helvetic Innoi.

You can enable auto-kerning by not supplying a value or using null. You can disable kerning by supplying the zero value to NSKern attribute name if you need to turn it off for some reason, such as to match WebKit rendering. and any other value is going to adjust the kerning by the specified number of points. In our example, we've set up an auto-kerned run of text, the big red dog. Let's see what happens when we supply a positive value. Notice that the text has loosened. Let's tighten it up. We use a negative value to tighten the text. That's NS Kern attribute name.

Another really cool attribute we have in iOS 6 makes its way to us from the world of classical typography. In the type case, you may have had one or more glyphs stacked together that when looked at did not appear to be naturally balanced. For example, FI. Now in iOS 6, you can turn on default ligatures and will start to substitute these two glyphs with their ligature glyphs. For example, FI is substituted by the FI ligature glyph. We have FF, FL, now we're getting cool here, FFI.

and for what I like to term the flying buttress effect, we have the FFL ligature. Cool, huh? So I've talked a bit about some of the beautiful, very designy sort of attributes, and now I want to talk about one that I consider to be a bit more utilitarian, NSBackgroundColorAttributeName. You may think it's redundant since you can specify the background color of a label, you could always use a UI rect fill to color the bounds of this app.

But that's not the case. Imagine if you want to achieve a selection effect. You want to get the color to wrap very closely to the text. Well, one way we could achieve this is to supply a light blue color to NSBackgroundColorAttributeName, which will very nicely highlight along the lines of text.

Sometimes it is advantageous to be able to underline all or some of your text, and you're going to use NS_style attribute name to achieve this. Next, another somewhat useful -- I hate to call anything somewhat useful, but it's good to have it when you need it sort of attribute in your grab bag of tools is NSStrikeThruStyleAttributeName.

Pretend I have a friend named Kyle, and we're talking about his dog here, Landis. And this dog is incredibly lazy, but I've offended him by putting this out here in front of all of you. And I want to show him that I have redacted this text from the document. Well, I would achieve this using NSStrikeThruStyleAttributeName. Notice how the text is redacted. We used NSForegroundColorAttributeName to also turn this little run of text red. So now he's not mad at me.

So Aki talked yesterday about NS paragraph style and a bunch of the properties. The first one that I want to talk to you about today are some properties that allow you to control the line height. I'm going to start by talking about the minimum line height and maximum line height property. The reason I'm talking about them at the same time is they're usually set to the same value.

What they're going to control is they're actually going to control the line fragment height that we use to render your text. And this is going to move the baseline. We're actually going to adjust the ascender proportionally to the value that you give us. So we're going to move your text.

And you can see an example of where we've used this in iOS 6 in the Stocks app. Notice that these cells are not very tall, and it would be difficult if we used the natural line height of the font to fit all of the text in the cell. So the Stocks team set up minimum line height and maximum line height to a value that was less than the natural line height of the font, achieving this effect.

The next value I want to talk to you about, or the next property, is another one that comes to us really from the world of classical typography, which is why you can see a type case next to it. And it controls the gap between lines. is a professor at the University of Michigan.

He's been working on a new project called Line Spacing. The reason I talk about classical typography, again, is you have to remember there used to be thin strips of lead that would separate the rows of glyphs in the type case, and this was called leading, also known as line spacing. So when you're interacting with your developer and she starts going on about leading, you now know what you need to adjust. Now, since we are in the world of computers, we can actually have negative line spacing, which will cause the lines to overlap.

and this value is going to be included in your line fragment heights. So, let's see how it works. We're going to supply a value of 30 to line spacing, which is going to give 30 points of vertical distance between these two lines. Talking more about spacing, you can also affect interparagraph spacing by setting a value on paragraph spacing. So you can see in this case, we've added 30 points of distance between the two paragraphs.

If you want to affect the amount of space which precedes the paragraph, you can set up paragraph spacing before. Again, in our example, we've given it a value of 30. If you want left and right margin control, you can use the head and tail indent properties. We'll talk about head indent a little bit.

You can see again we've set up a left margin of 30 by changing the head and end value of the paragraph style. And you can change the right margin by supplying a value to tail and end. In this case, it's negative because we're telling it how many points to come away from the right margin.

So, Aki talked yesterday a bit about the Reminders group and some of the stuff that they did to achieve some of the text effects in the Reminders application. If you've used Reminders on iOS 6, you'll notice that there's a priority glyph often on the first line of the text. The way they achieved this effect, the way they were able to knock over that first line of text was by customizing the first line head indent property of NSParagraphStyle.

Let's talk a bit about hyphenation. You can control hyphenation by customizing the hyphenation factor property of NS paragraph style. You can see here in our example, it's been disabled and we've supplied a value of zero. This is the default. And you can see in our text, we have a very, very tight bounding box, which has caused the layout to become, unfortunately, unbalanced vertically. So if we supply the value 1, you'll notice we now break lengthwise using a hyphen. This appears to be more vertically balanced in this case.

So all of these things are very cool, and you may be asking, how do I use these guys in my app? Well, we talked about that a little bit yesterday. The whole UI label is the nexus of power talk. And that really hasn't changed. As you can see here, we have a table view cell with a label, and this is only one label which bears an attributed string.

The attributed string is specifying a bold font for the word "Appleseed." In the past, this would have taken two labels to achieve or some custom drawing, and it would have been really difficult to get the spacing between the N and capital A glyphs correct. UI Text Field also takes an attributed string now in the Attributed Text property. and even UI TextView takes an attributed string in the attributed text property and allows users to interact with the attributes and customize them themselves.

UI Button can render an attributed string. And as you saw yesterday, Pickerview Caliente has been enhanced to show attributed strings. There are a few caveats to remember when using attributed strings with UIKit. And Aki talked about default values yesterday. UIKit will supply different default values when you're using attributed strings with label, for example. We're going to specify where you don't specify an NS font attribute name with using UI font system default font size and using the default font size for the widget. In this case, in iOS 6, UI label will specify 17 points.

We're also going to specify NS foreground color attribute name where you do not specify one, and we're going to supply the black color. We're also going to turn off kerning. The rest of the text system does not use kerning. The rest of the system does not use kerning. WebKit does not use kerning. So you should really only use it in cases where you have like a designer spec that says you need to adjust the kerning for your labels.

We're also going to turn off ligatures, again, in the aim of achieving system-wide text rendering consistency. So let me show you how all this stuff is used. You may have seen this table view very quickly yesterday during our introductory talk. I want to show you how we put it together today and what customizations we made to achieve these effects. First off, I'll show you the fancy header. You'll notice that we've achieved this effect by supplying an NS attributed string instance to the attributed text property of the text label of UI table view header footer view, which is new in iOS 6. Thanks.

We've also given this a gray drop shadow, which makes the text appear to sort of pop off of the grouped table view background. Next, you'll notice Twyla Brown's name would be inappropriately kerned if we had just let the system render it. So we've adjusted NSKernAttributeName by supplying the value null there. And notice the T and W glyphs are nicely kerned.

Next, in Susie Griffin's name, you'll notice we have that beautiful FFI ligature, and we've done this by enabling ligatures in our attributed string. Continuing on, Aki talked yesterday about the basic NSStringDrawing API, the simple methods draw in rect, draw at point, and size. Today we're going to talk about the extended drawing and sizing methods, draw with rect, and bounding rect with size.

The extended NSStringDrawing API is important because it gives you additional drawing and sizing capabilities over the simple APIs. You can specify baseline versus line fragment origin layouts, and we're going to talk more about that later. And you can also give us a constraining size by specifying a width and a height in the rect that you pass to us.

So, let's dive right into NSStringDrawing options. If you've ever worked with NSStringDrawing on the Mac, you may know a few of these already. I'll tell you about the ones that we brought over from the Mac to iOS 6. I have a few supported values. The first one is NSStringDrawing uses line fragment origin. We also support NSStringDrawing, Truncate's last visible line. And NSStringDrawing uses font-letting. We're not going to talk much about that today, but I'm told by my colleagues that it's very, very useful when dealing with Asian fonts.

You can specify multiple options because these guys are bit masks. So, for example, if I want to truncate the last visible line and use the line fragment origin, I can just or together and a string drawing truncates last visible line and a string drawing uses line fragment origin and supply that as the options parameter in my extended string drawing method. So, let's talk a bit about line fragment origin. So, the origin of the rect is going to determine where rendering begins, where we're going to start the pen.

So in Draw with Rect, we're going to take the Rect origin attribute, which is a CG point, and start from there. But we're going to interpret it differently based on the flags that you pass in Anna's string drawing options. For example, we're going to talk about baseline rendering first.

This is when the origin is at the baseline. You see we have this nice run of text, and we're taking the origin that you gave us and considering it to be at the beginning of the baseline. This is the default mode for the extended string drawing API. And it's usually used with a single line of text.

and in this case, NSStringDrawing uses line fragment origin is not going to be set. Let's talk about when you do set it, though. You can see we have a couple of lines of text, a couple of line fragments, and our origin now is going to be considered to be at the upper left of the line fragment.

This is the default mode for the simple API. So if you're using the extended API and you want to make it behave like the simple API, you will set this bit. And this is usually used with multiple lines of text. Now, I want to talk about controlling truncation. As you can see here, we have an overly long run of text that we're attempting to cram into the bounds of our app's main view. We can fix this by supplying the NSStringDrawing Truncate's last visible line option, which will do this. Simple.

Next, I'd like to talk about something new in iOS 6, which personally as a text geek I find rather exciting. It's the NSStringDrawingContext. Again, if you've used these things on the Mac before, if you've used NSStringDrawing and attributed strings, you may have run across things like LayoutManager. Well, we don't have LayoutManager right now on iOS 6, but this is a great analog for it. It allows you to specify more options about how you'd like the text system to lay out your text, and it can communicate back to you what we actually did to lay it out. So, let's talk about a few of the properties on this.

First, I'd like to talk about minimum scale factor. It tells the text system exactly how small it can scale all of the fonts in your attributed string before it begins to truncate when it's trying to fit it into the bounding box, the constraint. Next, we have the minimum tracking adjustment, which tells us exactly how small we can make all of the tracking, basically all of the spacing between your characters, again before we're going to begin to truncate. You don't have to use label to achieve these effects.

Now I want to talk about the read-only properties. This is the way that the text system can communicate with you and tell you what it did to render your text. First, there's the actual scale factor. You give us a minimum scale factor, we give you back the actual scale factor that we supplied when we were scaling your fonts. We will tell you the actual tracking adjustment we used. And I would say, maybe most importantly, we'll tell you the total bounds that were used to render your text.

So, how is this stuff useful? Well, the scale factor information can be used to achieve consistent font, label, sizes, and tracking. Example here, we have three names: Johannes, Jacob Appleseed, Twyla Brown, and Susie Griffin. Twyla and Susie have very short names, which easily fit in the balance of the label that have been supplied. However, Johannes' name, while it is a great name, and I love the name Johannes, is unfortunately very, very long and does not easily fit within the bounds of the given label.

So, what has the text system done? The text system has shrunk the fonts to 80% of their original size and used that to render Johannes' name. Now, this is fine. Everything fits. But now the font sizes are inconsistent. Let's take that scale factor of 80% and apply it to the rest of the text. Since we know what scale factor was used, we can do this to the other strings, and then we can achieve this consistent look to our table view.

So you can see we have a screenshot from iOS 6's YouTube app. And I'm going to use this to talk about one pass layout. So this is actually done in our YouTube app. You can see we have four keyframes, four descriptions, four dates that the movies were uploaded, a number of views, and because we're Apple, most importantly, a rating.

How would we lay all of this out? In the past, well, you know how big the keyframes are, but you don't have upfront knowledge of how big these strings will be. So you'd probably render the keyframes, do a bunch of sizing passes over all of the text, and then actually draw the text.

You can do this in one pass now on iOS 6 using the total balance property of NSStringDrawingContext, and let me show you how this would work. So, as I said, we know the size of the keyframe, so we can start from there. We know the maximum vertical extent.

And we can render the runtime. Now that we know about how big of an area we have to render the description, we can render that. And then we can move the Y coordinate again to supply the origin for the date that it was uploaded. Then, we can render the number of views. And now that we know just about how big the entire cell is going to be, we can drop in the rating.

We know the bounds of the entire cell, and we can rinse and repeat for the rest of the UI. That's one pass layout. You can do it on iOS 6 with the total bounds property of NSStringDrawingContext. Next, I'd like to tell you about the concurrency considerations of NSString drawing. First, you'll be happy to know, and as string drawing calls, are thread safe.

However, NSStringDrawingContext instances are not. Don't share these between queues, please. There could be really interesting object subgraphs hiding behind an NSStringDrawingContext which may not necessarily be thread safe. Now, to show you how to use all of this cool new technology in your app, we've prepared a demo. And I'd like to introduce my colleague, Johannes Fortmann, who's going to show it to you.

Thanks, Ian. Hi, I'm Johannes Fortmann from the Yoike team. And if you've been to the intro talk yesterday, you already know our little demo app. For those of you who haven't been here, it's an app which renders pages from various plays. And you can select a page and, for example, learn the text on the bus if you're an actor or just marvel at the typography and the beautiful writing. I'm just going to run this app.

And this is the state we got this in yesterday. What we did here, we have a collection view to actually show a selection of pages. And what we did was we switched this label here to use the attributed rendering and added a bold font. And zooming out, we switched the text rendering. And we're going to use the attribute rendering to use beautiful ligatures like the waffles here.

I don't think he actually says that. Well, let's go back to this overview slide here. And well, you notice this label is while much more beautiful than it was yesterday before we started, it's still kind of lying flat on the page. So I want to add a shadow to make this stand out a little more. And to do that, I'm going to Xcode and opening my page preview cell here.

This is where we are formatting our label. We are creating an attributed string with a red color. We are looking for the range of our scene name and setting a bold font. And then we're finally setting the attributed title. To actually set the shadow here, what we need to do is create one of these NSShadowValueClass objects. Now, value class means that we are only using this to actually store values like the offset, the blur radius, or the shadow color.

So what we need to do here is actually create our shadow object, set the parameters we want to set. In my case, I want to set an offset, and I want to set the blur radius, change that from the default. I'm not changing the shadow color. That's the default of 50% gray, and I kind of like that color.

The final step I have to do is actually change my attributes dictionary to have this shadow color set. So I'm going to remove this and replace it by an attributes dictionary with now two keys, the red color, foreground color, and the shadow attribute. Let's see how that looks.

We see that we now have a really, really beautiful shadow here. That looks nice. And tasteful. All right. Let's go back to this rendering here. Now, if you were in the intro session, you might still remember how this rendering works. We are doing -- we have our page representation, which contains several paragraphs. And we are rendering this paragraph by paragraph going through the list. And after each paragraph, we add up the Y height of the paragraph to advance our page cursor.

And for that, we had to do an unfortunate sizing step. We got the paragraph size and added it to our remaining page rect. Now, as Ian just told you, we can actually use the -- in a string drawing context to find out -- -- find out the total bounds of the paragraph we just rendered.

So we don't have to do the sizing step, which is very nice, because that way we don't actually have to size this, throw away the layout information, and then render it and recreate the layout information. So let's move this to use the actual sizing. And keep in mind how this looks, because we want to compare afterwards, of course. To go to the rendering code, we open the page view, and there we have a render page with size method.

And this is where we do the drawing. You can see the sizing step here and the drawing step here. Instead, we want to create the context that we are using to render, which will be filled in by the rendering step to contain the size. So I'm creating the context here. And then all that is left for me to do is do the actual rendering. So I can remove this.

and call my rendering method. Now, you see we're using the line fragment origin parameter here. That is because our rendering is going to start at the current cursor position downwards. We don't want to render from our current cursor position upwards like having a baseline and having the glyphs balanced on that. But rather we want to render down from the current position. So we have to use this line fragment origin.

And of course, afterwards, we have to still stow away our paragraph size. And let's have a look at how that looks. I hope it still looks the same. And it actually does. That is very nice. Now, we've also talked about other attributes like the background selection color. And to demonstrate that, I have put in a neat feature here.

I'm going to show you here. I'm doing a long tap on this. And you see there's a little copy pop over here. I've actually put in a hit testing method which tests against these paragraphs. And we can select one and actually copy it. But we don't see a selection.

So let's use the background color attribute to display the selection. To do that, I'm going to switch to the page class, that is my model class, which contains the paragraphs and the code to format the attributed string. Let me switch there. And we have a method, attributed string for paragraph, which we'll use here.

Now, I already have written the code to actually propagate the paragraph selection index down into this page class. So the only thing I need to do is actually check if the index of the paragraph I'm currently rendering, that's the index of this paragraph in my paragraphs array, is equal to the selected paragraph.

And in that case, I have to format this paragraph properly. So I'll set the background color. And because I'm setting a light blue background color, I also have to set the foreground color to match that, to have proper contrast here. So I'm also setting the foreground color. Let's see how that looks.

And now if I select one of these, you can actually see which one I'm selecting. And I can go here and select another one. And now I know which paragraph I copied. And you notice how this nicely follows the actual extents of the text here. Specifically, we see that it doesn't go over at the end. All right. Now, looking back at this slide, this page, we notice that this text seems kind of -- still seems kind of unbalanced. That is because our line spacing is, I think, a bit off. I don't know what I did there.

But What we might want to do is adjust the line spacing here for legibility. You might also want to use this if you're, for example, printing something to a PDF or so and want to leave space for commands or... Well, this case, improving legibility is a very good idea, too.

And I've already put in a slider so I can actually adjust the line spacing here to see how that would actually look. But this slider is still nonfunctional. That's because while I have hooked that up and propagated my value down to my paragraph already, I don't actually adjust the line spacing. So let's do that.

We're going to do this one. Now we have to actually do something clever here because as you remember from the last session, we are actually using different paragraph styles here. The line spacing is a property on the paragraph style. And we are already using the paragraph style for our stage directions to create a We've moved them to center alignment. Our text, on the other hand, is using the default paragraph style with a left alignment, and we haven't changed that.

Now, having these two different paragraph styles means that we can't just smash over a new paragraph style with the correct line spacing, minimum and maximum line spacing, over all of this, because that would override our text alignment. That would be very unfortunate. So what we have to do is enumerate the line spacings and modify them. So I'm going to do an enumeration here. I'm enumerating the paragraph style attribute in the whole range of the text using a block. And this block gets as its parameters the current value of the paragraph style, the range, and a stop point.

And I'm going to do a pointer if I want to stop this prematurely. We're not going to do that. Now, for the default, we will actually be getting a value of nil here. That is because we haven't actually set a paragraph style. That means that we have to take that into consideration. And I'm going to do that, actually.

So what I'm doing here is I look if we actually have a value, in which case we want to do a mutable copy of this value to be able to mutate it. And if we don't have a value, I want to use a new mutable paragraph style. Of course.

The only thing that's left for me to do is to set my minimum and maximum line spacing on this paragraph style and then apply it back to my attributed string. That is it. Let's see how that works and if we can figure out a better value for our line spacing. and now our slider adjusts our line spacing so we can see the value of 31 seems to be pretty good here.

Let's have a look at this overview page here for a minute. We are currently rendering these pages Loading them from disk and then immediately rendering them. And that's pretty quick. It's certainly fast enough for this demo. And it's actually -- the text rendering system is very fast. So there aren't any problems here.

But you might imagine situations where the text you want to render is coming from the network. It might be a whole lot of tweets, for example, that you get from Twitter. And those might be coming in one after the other. And for making your app really responsive and awesome so your customers will love it, you want to -- Offload this loading from the network to a background queue. If you've seen the concurrency in iOS talk yesterday, you already know how to do that properly.

And as Ian told you, the rendering here is actually thread safe. So apart from just loading these tweets or whatever you are rendering from the network in the background, you can also render them in the background. And I want to move our rendering code to the background queue now to show you how that goes. Our rendering code for this overview lives in the page preview cell. And I'm going to pull that up.

This is actually here the whole rendering code. I'm going to emphasize this so you can see it. And what we're doing here is we're rendering the page preview. and setting it on our current preview cell. Now, parts of this are able to be moved in the background, specifically the rendering. Parts of this aren't.

We cannot interact with UIKit controls, with view instances from the background queue. That would be fatal and a very bad idea to do. So what we have to do is first dispatch this rendering to the background. So I'm going to dispatch this on dispatch queue. You could also, of course, use an NS operation queue for this.

And now if we look at this render call, you'll notice we're calling this on the page view. So this is a class method. We're not interacting with any page view instance because that would be an interaction with the UIKit control and, as I said, not a good idea.

But we're still sizing this up by calling this getter here. We're getting the frame size. We cannot do that in the background, but luckily that's also a very fast operation. So we can just do that here in the foreground before we dispatch asynchronously. Now that we have this page size, we want to render in the background.

And then we want to set this, but that again is an interaction with UIKit proper with a view. And so we have to dispatch that to the foreground queue, the main queue. So I'm dispatching this to the main queue. And there I'm setting my image. These can go now because we actually have accomplished our to-do. So let's look at how that looks.

And as you can see here, well, you can see nothing because this was already fast. It wouldn't have been a good demo if I hadn't made it fast enough to be actually responsive. So to show you how this might look if we actually have a long-running operation like a lengthy computation or fetch from the network, I'm going to just put in a method call here that does some work that takes really long. And after I do that, you can see these renderings fade in one after the other, rendered on the background, and our app is still responsive.

[Transcript missing]

Now, you've seen how to use the advanced text rendering attributes to convey things like the emphasis we used for the selection, but also to beautify your app. We've used the shadow to make our label stand out. You've seen how to use the paragraph style advanced attributes like minimum and maximum line height to make your text more legible.

In this case, we've spaced out our lines to make the page on the whole look more balanced and to be able to quickly distinguish between these lines. And you've seen how to move things to the background queue. Now in moving this to the background queue, we've only used text rendering system and UI image to actually pass the rendered stuff back.

And let me emphasize this again. You should not manipulate UI elements from the background queue. That is a really, really bad idea. You should render in the background, and after you've done your rendering, pass the rendered image back to the main queue and set your image there. And with that, I'd like to give back to Ian. Thanks.

Thank you, Johannes. We've talked about a lot of things today. First, we talked about some of the advanced attributes. We talked about how to apply outlines or strokes to your text. We talked about drop shadows. We talked about kerning and ligature adjustments. And we talked about some of the cool things you can do with NS paragraph style customizations. Then we talked about how to use these text effects in your app. We talked about customizing table view headers. We talked about customizing table view cells.

And then we talked about the extended string drawing API. We introduced you to the notion of NSStringDrawingContext, which is new in iOS 6 and exclusive currently to iOS 6. And we also talked about NSStringDrawingOptions. If you still need more information, you can talk to our evangelist, Jake Behrens, or go look at the UIKit framework documentation online. Finally, if you haven't been to the Apple Developer Forums, I would urge you to go there today and sign up. You can give and receive peer-to-peer support, as well as interact with employees like myself, Johannes, and Aki.

There are some related sessions. We have our Introduction to Attributed Strings for iOS talk. If you missed that, I urge you to watch that. Aki's going to show you how to create, modify, and replace attributes in attributed strings, as well as draw them to the screen using the simple NSStringDrawing API. There was a great Core Text and Fonts session yesterday that you should definitely catch if you're interested in knowing more about Core Text.

And then there was the Keyboard Input and Output session. There was a Keyboard Input and Output session yesterday that you should definitely catch if you're interested in knowing more about Core Text. input in iOS talk which will tell you more about how to interact with UI text field and UI text view with respect to attributed strings.