165
#WWDC17 © 2017 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple. Philippe Hausler, Foundation Donna Tom, TextKit Efficient Interaction with Frameworks Performance case studies Session 244 App Frameworks

Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

WWDC17

copy 2017 Apple Inc All rights reserved Redistribution or public display not permitted without written permission from Apple

Philippe Hausler Foundation Donna Tom TextKit

bullEfficient Interaction with Frameworks bullPerformance case studies bull Session 244

App Frameworks

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 2: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 3: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 4: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 5: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

I

IVIII

II

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 6: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 7: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 8: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 9: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 10: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullImprovements in Foundation bullBridges and how they affect your app bullStrings ranges and text

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 11: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Improvements in Foundation

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 12: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Improvements in Foundation

NSCalendar

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 13: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Improvements in Foundation

NSCalendar

Internal locking improvements

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 14: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 15: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Improvements in Foundation

NSCalendar

Internal locking improvements

NSOperation and NSOperationQueue

Copy on write collections

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 16: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 17: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections There is a CoW level

What is copy on write

How does it work

How can I improve my code to work better and safer with it

implementation Container

NSMutableArrayltItem gt _elements

- (NSArrayltItem gt )elements

return [_elements copy]

end

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 18: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 19: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 20: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 21: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 22: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 23: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 24: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 25: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 26: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 27: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Copy on Write Collections Letrsquos milk this joke a bit more

a = [NSMutableArray new] a 128004 []

128004 []b = [a copy] a

b

[a addObjectA]

a

b

128004 [A]

128004 []

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 28: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 29: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 30: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 31: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 32: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 33: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Copy-on-write Steer your code in the right direction WARNING Donrsquot pass any NSMutableArrays into hereproperty (strong) NSArrayltItem gt items

Copies are saferproperty (copy) NSArrayltItem gt items

- (NSArrayltItem gt )items NSMutableArray items = [[NSMutableArray alloc] init] [self buildItemsitems] WARNING Dont mutate this it is declared as NSArray so it should be safe return items

This will copyaNSArray as [Any]

The copy is completely safe here and also is nearly free so avoid bad things later return [items copy]

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 34: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Data The best type for dealing with bytes

Data is its own slice

Indexing is only a few instructions in optimized builds

Appending is dramatically faster

Replacing regions is faster too

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 35: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 36: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Subscripting Data

func findZeroByte(_ data Data) -gt DataIndex

for index in dataindices

if data[index] == 0 return index

return nil

Nan

osec

onds

02468

1012141618

Samples

Swift 3Swift 4

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 37: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 38: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 39: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 40: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 41: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 42: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 43: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 44: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 45: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Leveraging Data Donrsquot Believe the Lore

var bytes [UInt8] = [0xcf 0xfa 0xed 0xfe]var bytes = Data(bytes [0xcf 0xfa 0xed 0xfe])

var buffer = malloc(250)assumingMemoryBound(to UInt8self)defer free(buffer) var buffer = Data(count 250)

let header = buffersubdata(in bufferstartIndexltbufferstartIndexadvanced(by 4))

let header = buffer[ltbufferstartIndexadvanced(by 4)]

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 46: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 47: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridging

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 48: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 49: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 50: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at cast

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 51: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 52: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridges

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 53: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a struct

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 54: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference type

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 55: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advance

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 56: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Bridges and How They Impact Your App For whom the bridge tolls

Toll-free bridgingbull From a CF type to a NS typebull From a NS type to a CF typebull Zero cost at castbull Extra cost at usage

Swift bridgesbull From a reference type to a structbull From a struct to a reference typebull Cost is paid in advancebull Normal cost at usage

NSArray array = []

CFArrayGetCount((CFArrayRef)array)let data = NSData()

let d = data as Data

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 57: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 58: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 59: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID() CFIndex (NSArray )array count) return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 60: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (CF_IS_OBJC(CFArrayGetTypeID() array) return [(NSArray )obj count] return array-gtcount

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 61: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

CFIndex CFArrayGetCount(CFArrayRef array) if (object_getClass(array) = CFClasses[CFArrayGetTypeID()]) return [(NSArray )obj count] return array-gtcount

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 62: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 63: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 64: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 65: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

CF Bridging

NSArray array = [] CFArrayGetCount((CFArrayRef)array)

Small and Unknown Frequency

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 66: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

extension Data _ObjectiveCBridgeable hellip public static func _conditionallyBridgeFromObjectiveC(_ input NSData result inout Data) -gt Bool We must copy the input because it might be mutable just like storing a value type in ObjC result = Data(referencing input) return true hellip

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 67: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

struct Data hellip public init(referencing reference NSData) _backing = _DataStorage(immutableReference referencecopy() as NSData) _sliceRange = 0ltreferencelength hellip

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 68: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 69: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

let data = NSData() let d = data as Data

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 70: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 71: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 72: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 73: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 74: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Swift Bridging

let data = NSData() let d = data as Data

Usually small and infrequenthellip

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 75: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Donna Tom TextKit

bullStrings Ranges and Text

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 76: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Strings are everywhere

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 77: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Invest in performancethat matters to your users

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 78: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Frequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 79: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

$

cent

measure

measure

I

IVIII

II

Short Length Long Length

Runs Frequently

Runs Infrequently

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 80: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullString bridging bullRanges bullText layout and rendering

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 81: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullString bridging bullRanges bullText layout and rendering

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 82: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Example 1 UILabel

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 83: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 1 UILabel

Swift var text = labeltext

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 84: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 1 UILabel

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 85: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 86: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 1 UILabel

Objective-C - UIKit

interface UILabel UIView

property(nullable nonatomic copy) NSString text

bridge

Swift Interface - UIKit open class UILabel UIView open var text String

Swift var text = labeltext

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 87: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 1 UILabel

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 88: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 89: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 1 UILabel

Swift Framework

class NSString struct String class NSString

var text = labeltext

copy

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 90: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 91: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltext I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 92: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = labeltextcent I

IVIII

II

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 93: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Example 2 NSTextStorage

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 94: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 95: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

pretend there is a lot of text here Irsquod like to get an animation of a scrolling

text view with lots of text

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 96: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 97: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 98: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Swift Interface - UIKit

class NSTextStorage NSMutableAttributedString

open class NSMutableAttributedString

NSAttributedString

open var string NSString

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 99: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 100: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

Swift

var text = textViewtextStoragestring

Objective-C - UIKit

interface NSTextStorage NSMutableAttributedString

Objective-C - Foundation

interface NSMutableAttributedString

NSAttributedString

property(readonly copy) NSString string

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 101: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragestring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 102: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSString struct String class NSString

var text = textViewtextStoragestring

copy

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 103: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

var text = textViewtextStoragemutableString

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 104: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Bridging Example 2 NSTextStorage

Swift Framework

class NSMutableString

var text = textViewtextStoragemutableString

no copyclass NSMutableString

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 105: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 106: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 107: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 108: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB

$ I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 109: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

var text = textViewtextStoragestring

1 KB1 MB1 GB

$128181128181128181128181128181128181128181

128181I

IVIII

II

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 110: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullString bridging bullRanges bullText layout and rendering

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 111: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Rangesrdquo rdquo

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 112: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

rdquo rdquo

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 113: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Visible Components 129318 127995

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 114: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 115: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 116: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Visible Components 129318 127995

Unicode Scalar Value 0x1F926 0x1F3FB 0x200D 0x2640 0xFE0F

Unicode Name

FACE PALM EMOJI MODIFIER FITZPATRICK TYPE-1-2

ZERO WIDTH JOINER FEMALE SIGN VARIATION

SELECTOR-16

UTF-16 0xD83E 0xDD26 0xD83C 0xDFFB 0x200D 0x2640 0xFE0F

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 117: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 118: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

ldquoWhat a 127881128169rdquo

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 119: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

ldquoWhat a 127881128169rdquo

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 120: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 121: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 122: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = NSMutableAttributedString(string string) attributedStringaddAttribute(backgroundColor value color range nsrange)

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 123: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 124: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Ranges Example 1 Working with NSAttributedString

ldquoWhat a 127881128169rdquo

let string = What a 127881128169 var attributedString = NSMutableAttributedString(string string)let backgroundRange = stringrange(of ldquo128169) attributedStringaddAttribute(backgroundColor value color range NSRange(backgroundRange in string))

NEW

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 125: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Example 2 Working with NSRegularExpression

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 126: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Ranges Working with NSRegularExpression

lthtmlgt ltbodygt ltdivgt

ltspangtHelloltspangt ltbgtSwiftltspangttestltspangtltbgt ltdivgt ltbodygt lthtmlgt

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 127: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

String Ranges Working with NSRegularExpression

extension String func rangeFromNSRange(nsRange NSRange) -gt RangeltIndexgt guard nsRangelocation = NSNotFound else return nil let from16 = utf16startIndexadvanced(by nsRangelocation) let to16 = from16advanced(by nsRangelength) if let from = Index(from16 within self) let to = Index(to16 within self) return fromltto return nil

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 128: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 129: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Improved String Ranges Working with NSRegularExpression

import Foundation

func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][a-z0-9])gt) for match in rematches(in string range NSRange(stringstartIndexltstringendIndex in string)) foundappend(Range(matchrangeAt(1) in string)) return found

NEW

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 130: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

bullString bridging bullRanges bullText layout and rendering

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 131: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Text is hard

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 132: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

40 iOS localizations

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 133: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

40 iOS localizations

35 macOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 134: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 135: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 136: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

40 tvOS localizations

35 macOS localizations

40 iOS localizations

39 watchOS localizations

More than 300 other languages

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 137: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Font Leading

Tracking

Emoji

Truncation

Line Breaking

Unicode

BidirectionalCursor Positioning Dynamic Type Shaping Metrics

Hyphenation Widows Grapheme Cluster

Precomposed Characters

Script

RTL

LTR

Gamma

Tightening Orphans

Decomposed Characters

Spacing

Uncached

Orientation Glyph Bounds

Text MatrixEven-Odd

Kerning

Locale FontsFont Smoothing Margin

Non-Zero

FlippednessPattern Fill

Attributes

Writing Direction

Language

Screen Size Ligature FringingStroke

Glyph Dilation

Optical AlignmentLetterpress

EmAnti-Aliasing

Shadow

Line Height Clipping Legibility

Exclusion PathsLinear Blending

Glyph Bounds

Selection

Glyph Substitution

Encoding

AttachmentsLetterpress Bounding Boxes Baselines

Ascenders

DescendersAccessibility

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 138: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Example A Tale of Two Labels

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 139: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Millennium Park Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 140: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 141: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 142: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Millennium Park Loop

Tribune Tower Near North Side

Union Park West Loop

Rookery Building Loop

North Ave Beach Lincoln Park

Water Tower River North

Conservatory

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 143: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Robie House Hyde Park

Burnham Park Museum Campus

Union Station Loop

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 144: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

长城 北北京

紫禁城 北北京

天安门广场 北北京

颐和园 北北京

天坛 北北京

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 145: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

大同

虎跳峡 丽江

龙门石窟 洛洛阳

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 146: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 147: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Runs Frequently

Runs Infrequently

Long LengthShort Length

I

IVIII

II

measure

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 148: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 149: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 150: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Postmortem Example A Tale of Two Labels

Initial conditions qualified for fast rendering

Input change forced rendering to slower path

App used older layout practices

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 151: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

What You Can Do Higher-level strategies

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 152: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

What You Can Do Higher-level strategies

Use standard label controls

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 153: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

What You Can Do Higher-level strategies

Use standard label controls

3xfaster rendering with

NSTextField in macOS 1013

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 154: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

What You Can Do Higher-level strategies

Use modern layout practices

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 155: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

What You Can Do Lower-level tips

Set rendering attributes for attributed strings

let attributes [NSAttributedStringKey Any] = [ font UIFontsystemFont(ofSizesystemFontSize)

paragraphStyle NSParagraphStyledefault foregroundColor UIColordarkText]

let myString = NSAttributedString(string Hello attributes attributes)

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 156: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

What You Can Do Lower-level tips

Specify alignment and writing direction if known

Only do this if yoursquore absolutely sure your text doesnrsquot have mixed writing directions var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylebaseWritingDirection = leftToRight myParagraphStylealignment = left

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 157: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

What You Can Do Lower-level tips

Use clipping line break mode for single line labels

Only do this if yoursquore sure your text doesnrsquot require wrapping var myParagraphStyle = NSMutableParagraphStyle() myParagraphStylelineBreakMode = byClipping

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 158: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

SummaryFrequently Occurring

Infrequently Occurring

Large SizeSmall Size

$

cent

measure

measure

I

IVIII

II

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 159: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

More Informationhttpsdeveloperapplecomwwdc17244

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 160: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Related Sessions

Understanding Swift Performance WWDC 2016

Whatrsquos New in Cocoa WWDC 2017

Whatrsquos New in Foundation WWDC 2017

Modernizing Grand Central Dispatch Usage WWDC 2017

Cocoa Development Tips WWDC 2017

Writing Energy Efficient Apps WWDC 2017

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 161: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring

Labs

Cocoa Lab Technology Lab B Fri 150PMndash320PM

Page 162: Performance case studies...• Performance case studies • Session 244 App Frameworks Frequently Occurring Infrequently Occurring Small Size Large Size I III IV II Frequently Occurring