Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Bridges and How They Impact Your 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
Bridges and How They Impact Your App For whom the 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
Bridges and How They Impact Your App For whom the bridge tolls
Toll-free bridgingbull 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
Bridges and How They Impact Your App For whom the bridge tolls
Toll-free bridgingbull From 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
Bridges and How They Impact Your App For whom the bridge tolls
Toll-free bridgingbull From 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
Bridges and How They Impact Your App For whom the bridge tolls
Toll-free bridgingbull From 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
Bridges and How They Impact Your App For whom the bridge tolls
Toll-free bridgingbull From 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
Bridges and How They Impact Your App For whom the bridge tolls
Toll-free bridgingbull From 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
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
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
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
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
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
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
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
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
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
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
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
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
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
Swift Bridging
let data = 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
Swift Bridging
let data = 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
Swift Bridging
let data = 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
Swift Bridging
let data = 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
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
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
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
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
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
$
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
String Ranges Example 1 Working with NSAttributedString
ldquoWhat a 127881128169rdquo
let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = 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
String Ranges Example 1 Working with NSAttributedString
ldquoWhat a 127881128169rdquo
let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = 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
String Ranges Example 1 Working with NSAttributedString
ldquoWhat a 127881128169rdquo
let string = What a 127881128169 let nsstring = string as NSString let nsrange = nsstringrangeOfString(128169) var attributedString = 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
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
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
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
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
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
Improved String Ranges Working with NSRegularExpression
import Foundation
func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][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
Improved String Ranges Working with NSRegularExpression
import Foundation
func findTags(in stringString) -gt [RangeltStringIndexgt] var found = [RangeltStringIndexgt]() let re = try NSRegularExpression(pattern lt([a-z][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
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
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
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
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
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
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
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
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
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
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
Millennium Park Loop
Tribune Tower Near North Side
Union Park West Loop
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
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
Millennium Park Loop
Tribune Tower Near North Side
Union Park West Loop
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
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
长城 北北京
紫禁城 北北京
天安门广场 北北京
颐和园 北北京
天坛 北北京
大同
虎跳峡 丽江
龙门石窟 洛洛阳
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
大同
虎跳峡 丽江
龙门石窟 洛洛阳
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Labs
Cocoa Lab Technology Lab B Fri 150PMndash320PM