Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Daniel Steinberg: The Open World of Swift 3
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Realm
April 25, 2016
Programming
25k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Daniel Steinberg: The Open World of Swift 3
Realm
April 25, 2016
More Decks by Realm
See All by Realm
WWDC 2017 Review
realm
0
2.2k
Xcode shortcuts
realm
0
4.7k
Self Branding with GitHub
realm
0
4.3k
Realm Mobile Platform overview and demo
realm
0
2.1k
Realm advanced topics and demo
realm
0
2k
Realm introduction Seoul meetup 10
realm
0
2.2k
Stuart Hall: How I got 2.3 Million App Downloads
realm
0
2k
James Majors: What the Swiftly Func?
realm
1
4.3k
Simina Pasat: Continuous everything for iOS apps
realm
0
660
Other Decks in Programming
See All in Programming
A2UI という光を覗いてみる
satohjohn
1
120
Lessons from Spec-Driven Development
simas
PRO
0
150
Vite+ Unified Toolchain for the Web
naokihaba
0
180
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
150
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
190
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
330
CLIであることを活かしたGitHub Copilot CLI活用術 / GitHub Copilot CLI Pro Tips & Tricks
nao_mk2
1
1.2k
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
530
Webフレームワークの ベンチマークについて
yusukebe
0
150
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
120
The NotImplementedError Problem in Ruby
koic
1
660
スマートグラスで並列バイブコーディング
hyshu
0
100
Featured
See All Featured
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
190
Agile that works and the tools we love
rasmusluckow
331
21k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
270
How to Ace a Technical Interview
jacobian
281
24k
So, you think you're a good person
axbom
PRO
2
2.1k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
71
40k
HDC tutorial
michielstock
2
700
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
sira's awesome portfolio website redesign presentation
elsirapls
0
270
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
280
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
Transcript
The Open World of Swift 3 AppBuilders 2016 Daniel H
Steinberg @dimsumthinking
Swift
Open
Open?
Open!
Future
Future?
Future!
What can we see?
0025 - Scoped Access Levels
public internal private
public internal private
public internal private
public internal private
public internal fileprivate
public internal fileprivate private
class MyClass { private var myProperty = "Hello" private func
myPrivateMethod() { print(myProperty) } fileprivate func myFilePrivateMethod(numberOfTimes times: Int) { for _ in 1 ... times { myPrivateMethod() } } } extension MyClass { func myExtensionMethod(numberOfTimes times: Int) { myInternalMethod(numberOfTimes: times) } }
class MyClass { private var myProperty = "Hello" private func
myPrivateMethod() { print(myProperty) } fileprivate func myFilePrivateMethod(numberOfTimes times: Int) { for _ in 1 ... times { myPrivateMethod() } } } extension MyClass { func myExtensionMethod(numberOfTimes times: Int) { myInternalMethod(numberOfTimes: times) } }
class MyClass { private var myProperty = "Hello" private func
myPrivateMethod() { print(myProperty) } fileprivate func myFilePrivateMethod(numberOfTimes times: Int) { for _ in 1 ... times { myPrivateMethod() } } } extension MyClass { func myExtensionMethod(numberOfTimes times: Int) { myInternalMethod(numberOfTimes: times) } }
class MyClass { private var myProperty = "Hello" private func
myPrivateMethod() { print(myProperty) } fileprivate func myFilePrivateMethod(numberOfTimes times: Int) { for _ in 1 ... times { myPrivateMethod() } } } extension MyClass { func myExtensionMethod(numberOfTimes times: Int) { myInternalMethod(numberOfTimes: times) } }
class MyClass { private var myProperty = "Hello" private func
myPrivateMethod() { print(myProperty) } fileprivate func myFilePrivateMethod(numberOfTimes times: Int) { for _ in 1 ... times { myPrivateMethod() } } } extension MyClass { func myExtensionMethod(numberOfTimes times: Int) { myInternalMethod(numberOfTimes: times) } }
public internal fileprivate private
0004 - Remove ++ and —
while count < upperLimit { print( myArray[count++]) }
while count < upperLimit { print( myArray[count++]) }
while count < upperLimit { print( myArray[count]) count += 1
}
0007 - Remove C Style for loops with conditions and
incrementors
for (int i = 0; i < array.count; i++)
for (int i = 0; i < array.count; i++)
0053 - Remove explicit use of let from Function Parameters
func double(input: Int) -> Int { // ... }
func double(let input: Int) -> Int { // ... }
func double(let input: Int) -> Int { // ... }
0003 - Remove var from Function Parameters
func double(input: Int) -> Int { input = input *
2 return input }
func double(var input: Int) -> Int { input = input
* 2 return input }
func double(var input: Int) -> Int { input = input
* 2 return input }
func double(input: Int) -> Int { var localInput = input
localInput = localInput * 2 return localInput }
func double(input: Int) -> Int { var localInput = input
localInput = localInput * 2 return localInput }
func double(input: Int) -> Int { var input = input
input = input * 2 return input } Name Shadowing
func double(input: Int) -> Int { var input = input
input = input * 2 return input }
0031 - Adjusting inout Declarations for Type Decoration
func double(input: Int) { input = input * 2 }
func double(inout input: Int) { input = input * 2
}
func double(inout input: Int) { input = input * 2
}
func double(input: inout Int) { input = input * 2
}
0053 - Limiting inout capture to @noescape context
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func noEscape(@noescape f: () -> ()) {} func example(inout x:
Int) { noEscape { _ = x } }
func noEscape(@noescape f: () -> ()) {} func example(inout x:
Int) { noEscape { _ = x } } safe because @noescape => closure can't be called after function returns
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape { _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape {[x] in _ = x } }
func escape(f: () -> ()) {} func example(inout x: Int)
{ escape {[x] in _ = x } } [x] is a capture list a constant is initialized to have the value of x
0049 - Move @noescape and @autoclosure to be type attributes
func noEscape(@noescape f: () -> ()) {}
func noEscape(f: @noescape () -> ()) {}
func noEscape(f: @autoclosure () -> ()) {}
0002 - Remove currying func declaration syntax
0002 - Remove currying func declaration syntax
0002 - Remove currying func declaration syntax
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8)
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8)
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8)
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8)
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8) 7 * y
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8) 7 * 8
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8)
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8)
func curried(x: Int)(y: Int) -> Int { return {(y: Int)
-> Int in return x * y } } curried(7)(8)
func curried(x: Int) -> (y: Int) -> Int { return
{(y: Int) -> Int in return x * y } } curried(7)(8)
func curried(x: Int) -> (y: Int) -> Int { return
{(y: Int) -> Int in return x * y } } curried(7)(8)
func curried(x: Int) -> (y: Int) -> Int { return
{(y: Int) -> Int in return x * y } } curried(7)(8)
func curried(x: Int) -> (y: Int) -> Int { return
{(y: Int) -> Int in return x * y } } curried(7)(8)
func curried(x: Int) -> (y: Int) -> Int { return
{(y: Int) -> Int in return x * y } } curried(7)(8)
Testing
Playgrounds
Package Manager
Objective-C
0022 - Referencing the Obj-C selector of a method
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: "callbackMethod", name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: "callbackMethod", name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: "callbackMethod", name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: "callbackMethod", name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: "callbackMethod", name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: "callbackMethod", name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: #selector(callbackMethod), name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(with notification: NSNotification){} func
setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: #selector(MyClass.callbackMethod), name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(){} func callbackMethod(with notification:
NSNotification){} func setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: #selector(MyClass.callbackMethod), name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(){} func callbackMethod(with notification:
NSNotification){} func setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: #selector(MyClass.callbackMethod), name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
class MyClass : NSObject { func callbackMethod(){} func callbackMethod(with notification:
NSNotification){} func setNotification() { let center = NSNotificationCenter.defaultCenter() center .addObserver(self, selector: #selector(MyClass.callbackMethod(with:)), name: NSApplicationWillResignActiveNotification, object: NSApplication.sharedApplication()) } }
0033 - Import Obj-C constants as Swift types
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMassIndex; HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyFatPercentage;
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeight; HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMass; HK_EXTERN NSString * const HKQuantityTypeIdentifierLeanBodyMass;
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMassIndex; HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyFatPercentage;
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeight; HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMass; HK_EXTERN NSString * const HKQuantityTypeIdentifierLeanBodyMass;
enum HKQuantityTypeIdentifier : String { case BodyMassIndex case BodyFatPercentage case
Height case BodyMass case LeanBodyMass }
enum HKQuantityTypeIdentifier : String { case BodyMassIndex case BodyFatPercentage case
Height case BodyMass case LeanBodyMass }
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMassIndex; HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyFatPercentage;
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeight; HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMass; HK_EXTERN NSString * const HKQuantityTypeIdentifierLeanBodyMass;
enum HKQuantityTypeIdentifier : String { case BodyMassIndex case BodyFatPercentage case
Height case BodyMass case LeanBodyMass }
enum HKQuantityTypeIdentifier : String { case BodyMassIndex case BodyFatPercentage case
Height case BodyMass case LeanBodyMass }
0005 - Better translation of Obj-C APIs into Swift
let color = NSColor.blueColor()
let color = NSColor.blueColor()
let color = NSColor.blueColor() Prune redundant type names
let color = NSColor.blue()
rootViewController .presentViewController(alert, animated: true, completion: nil)
rootViewController .presentViewController(alert, animated: true, completion: nil) Add default arguments
rootViewController .presentViewController(alert, animated: true, completion: nil) Nullable trailing closures default
= nil
rootViewController .presentViewController(alert, animated: true)
rootViewController .presentViewController(alert, animated: true) Shouldn't animated default = true
rootViewController.presentViewController(alert)
rootViewController.presentViewController(alert) Prune redundant type names
rootViewController.present(alert)
var empty: Bool
var empty: Bool Prepend "is" to Bools
var isEmpty: Bool
addLineToPoint(myPoint)
addLineToPoint(myPoint) func addLineToPoint(_: CGPoint)
addLineToPoint(myPoint) func addLineToPoint(_: CGPoint) Add first argument labels
addLineToPoint(myPoint) func addLineToPoint(_: CGPoint) Add first argument labels
addLine(to: myPoint) func addLine(to point: CGPoint) Add first argument labels
addLine(to: myPoint) func addLine(to point: CGPoint) Add first argument labels
Add first argument labels
Add first argument labels
var URLHandler
var URLHandler Lower case imported types
var urlHandler Lower case imported types
enum Currency { case Dollars case Euros case Pounds case
Yen } Lower case imported types
enum Currency { case Dollars case Euros case Pounds case
Yen } Lower case imported types
enum Currency { case dollars case euros case pounds case
yen } Lower case imported types
0036 - Requiring Leading Dot Prefixes for Enum Instance Member
Implementations
enum Currency { case dollars case euros case pounds case
yen var symbol: String { switch self { case dollars: return "$" default: return "I don't know" } } }
enum Currency { case dollars case euros case pounds case
yen var symbol: String { switch self { case .dollars: return "$" default: return "I don't know" } } }
enum Currency { case dollars case euros case pounds case
yen var symbol: String { switch self { case dollars: return "$" default: return "I don't know" } } }
enum Currency { case dollars case euros case pounds case
yen var symbol: String { switch self { case .dollars: return "$" default: return "I don't know" } } }
enum Currency { case dollars case euros case pounds case
yen var symbol: String { switch self { case .dollars: return "$" default: return "I don't know" } } }
0043 - Declare variables in 'case' labels with multiple patterns
enum MyEnum { case case1(Int,Float) case case2(Float,Int) } switch value
{ case let .case1(x, 2), let .case2(2, x): print(x) case .case1, .case2: break }
enum MyEnum { case case1(Int,Float) case case2(Float,Int) } switch value
{ case let .case1(x, 2), let .case2(2, x): print(x) case .case1, .case2: break }
enum MyEnum { case case1(Int,Float) case case2(Float,Int) } switch value
{ case let .case1(x, 2), let .case2(2, x): print(x) case .case1, .case2: break }
enum MyEnum { case case1(Int,Float) case case2(Float,Int) } switch value
{ case let .case1(x, 2), let .case2(2, x): print(x) case .case1, .case2: break }
enum MyEnum { case case1(Int,Float) case case2(Float,Int) } switch value
{ case let .case1(x, 2), let .case2(2, x): print(x) case .case1, .case2: break }
enum MyEnum { case case1(Int,Float) case case2(Float,Int) } switch value
{ case let .case1(x, 2), let .case2(2, x): print(x) case .case1, .case2: break }
enum MyEnum { case case1(Int,Float) case case2(Float,Int) } switch value
{ case let .case1(x, 2), let .case2(2, x): print(x) case .case1, .case2: break }
0001 - Allow (most) keywords as argument labels
calculateRevenue(for sales: Int, in currency: Currency)
calculateRevenue(for sales: Int, in currency: Currency)
calculateRevenue(for numberOfCopies, in .dollars)
0009 - Require self for accessing instance members
struct Friend { let name: String let location: String func
nameBadge() { print("I'm", name, "from", location) } }
struct Friend { let name: String let location: String func
nameBadge() { print("I'm", name, "from", location) } }
struct Friend { let name: String let location: String func
nameBadge() { print("I'm", name, "from", location) } }
struct Friend { let name: String let location: String func
nameBadge() { print("I'm", self.name, "from", self.location) } }
struct Friend { let name: String let location: String func
nameBadge() { print("I'm", self.name, "from", self.location) } } Require self for accessing instance members REJECTED
0011 - Replace typealias keyword with associatedtype for associated type
declarations
0011 - Replace typealias keyword with associatedtype for associated type
declarations
protocol Prot { typealias Container : SequenceType } extension Prot
{ typealias Element = Container.Generator.Element }
protocol Prot { typealias Container : SequenceType } extension Prot
{ typealias Element = Container.Generator.Element }
protocol Prot { associatedtype Container : SequenceType } extension Prot
{ typealias Element = Container.Generator.Element }
0046 Establish consistent label behavior across all parameters including first
labels
func increase(ourNumber: Int, delta: Int) -> Int { } increase(6,
delta: 3)
func increase(ourNumber: Int, delta: Int) -> Int { } increase(6,
delta: 3)
func increase(ourNumber: Int, delta: Int) -> Int { } increase(6,
delta: 3)
func increase(ourNumber: Int, delta: Int) -> Int { } increase(6,
delta: 3)
func increase(ourNumber: Int, delta: Int) -> Int { } increase(ourNumber:
6, delta: 3)
func increase(_ ourNumber: Int, delta: Int) -> Int { }
increase(6, delta: 3)
0023 - Swift API Guidelines
Swift API Design Guidelines
myArray.sort()
sort() sorted()
sortInPlace() sort()
sort() sorted()
sort() sorted() Name functions and methods according to their side-effects
x.distance(to: y) i.successor() Those without side-effects should read as noun
phrases
x.sort() x.append(y) Those with side-effects should read as imperative noun
phrases
sort() sorted()/sorting() Use the “ed/ing” rule to name the nonmutating
counterpart of a mutating method
Prefer methods to free functions
Prefer methods to free functions Protocol Extensions in Swift 2
Prefer methods to free functions Protocol Extensions in Swift 2
Except …
min(x, y, z) When there's no obvious self
print(x) When the function is an unconstrained generic
sin(x) When the function is part of the established domain
notation
Methods can share a base name
Methods can share a base name Good when they do
analogous things
Methods can share a base name Not good (tableView!) when
they don't
Choose good parameter names
func move(from startingIndex: Int, to endingIndex: Int) Choose good parameter
names
Take advantage of default values
Take advantage of default values func hello(name: String = "World")
Take advantage of default values init(name: String, hometown: String? =
nil)
Prefer to locate parameters with defaults at the end init(name:
String, hometown: String? = nil)
External Argument Labels func move(from startingIndex: Int, to endingIndex: Int)
move(from: here to: there)
Argument Labels Exceptions
min(number1, number2) Omit labels when arguments can't be distinguished
Double(someInt) Omit labels in full width inits
Double(_ anInt: someInt) Omit labels in full width inits
func move(from startingIndex: Int, to endingIndex: Int) When the preposition
applies to the whole
func moveTo(x: Int, y: Int) When the preposition applies to
the whole
x.removeBoxes(having Length: 12) When the preposition applies to the whole
None
The Open World of Swift 3 AppBuilders 2016 Daniel H
Steinberg @dimsumthinking