Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
Daniel Steinberg: The Open World of Swift 3
Realm
April 25, 2016
Programming
2
24k
Daniel Steinberg: The Open World of Swift 3
Realm
April 25, 2016
Tweet
Share
More Decks by Realm
See All by Realm
realm
0
1.3k
realm
0
3.4k
realm
0
3.9k
realm
0
1.4k
realm
0
1.4k
realm
0
1.5k
realm
0
1.1k
realm
1
3.4k
realm
0
350
Other Decks in Programming
See All in Programming
xrdnk
0
130
kyonmm
2
2.2k
makicamel
1
190
takahi5
0
250
line_developers_tw
0
1.5k
rishitdagli
0
180
s_uryu
0
240
sullis
0
120
viteinfinite
0
210
yshrsmz
1
460
ajstarks
2
550
akatsukinewgrad
0
220
Featured
See All Featured
trallard
13
650
jeffersonlam
328
15k
holman
448
130k
yeseniaperezcruz
302
31k
qrush
285
18k
paulrobertlloyd
71
1.4k
smashingmag
283
47k
rmw
11
740
hursman
106
9.2k
reverentgeek
27
1.9k
philhawksworth
190
17k
eitanlees
111
9.9k
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