@jacksoncheek
let name: String = "Jackson Cheek"
print("My name is \(name)")
// My name is Jackson Cheek
val name: String = "Jackson Cheek”
print("My name is $name”)
// My name is Jackson Cheek
Swift Kotlin
Slide 10
Slide 10 text
@jacksoncheek
enum Language {
case kotlin
case swift
case java
case objective_c
}
enum class Language {
KOTLIN,
SWIFT,
JAVA,
OBJECTIVE_C
}
Swift Kotlin
Slide 11
Slide 11 text
@jacksoncheek
enum class Language(name: String) {
KOTLIN("kotlin"),
SWIFT("swift"),
JAVA("java"),
OBJECTIVE_C("objective-c")
}
enum Language: String {
case kotlin = "kotlin"
case swift = "swift"
case java = "java"
case objective_c = "objective-c"
}
Swift Kotlin
@jacksoncheek
protocol Developer {
func languages() -> Set
}
interface Developer {
fun languages(): Set
}
Swift Kotlin
Slide 14
Slide 14 text
@jacksoncheek
class Person {
init() {
}
}
class Person(
) {
}
Swift Kotlin
Slide 15
Slide 15 text
@jacksoncheek
class Person {
let name: String
let languages: Array
init(name: String, _ languages: Language...) {
self.name = name
self.languages = languages
}
}
class Person(
val name: String,
vararg val languages: Language
) {
}
Swift Kotlin
Slide 16
Slide 16 text
@jacksoncheek
class Person: Developer {
let name: String
let languages: Array
init(name: String, _ languages: Language...) {
self.name = name
self.languages = languages
}
}
class Person(
val name: String,
vararg val languages: Language
): Developer {
}
Swift Kotlin
Slide 17
Slide 17 text
@jacksoncheek
class Person: Developer {
let name: String
let languages: Array
init(name: String, _ languages: Language...) {
self.name = name
self.languages = languages
}
func languages() -> Set {
}
}
class Person(
val name: String,
vararg val languages: Language
): Developer {
override fun languages(): Set {
}
}
Swift Kotlin
Slide 18
Slide 18 text
@jacksoncheek
class Person: Developer {
let name: String
let languages: Array
init(name: String, _ languages: Language...) {
self.name = name
self.languages = languages
}
func languages() -> Set {
var unique: Set = Set()
return unique
}
}
class Person(
val name: String,
vararg val languages: Language
): Developer {
override fun languages(): Set {
val unique: Set = setOf()
return unique
}
}
Swift Kotlin
Slide 19
Slide 19 text
@jacksoncheek
class Person: Developer {
let name: String
let languages: Array
init(name: String, _ languages: Language...) {
self.name = name
self.languages = languages
}
func languages() -> Set {
var unique: Set = Set()
for language in _languages {
}
return unique
}
}
class Person(
val name: String,
vararg val languages: Language
): Developer {
override fun languages(): Set {
val unique: Set = setOf()
for (language in languages) {
}
return unique
}
}
Swift Kotlin
Slide 20
Slide 20 text
@jacksoncheek
class Person: Developer {
let name: String
let languages: Array
init(name: String, _ languages: Language...) {
self.name = name
self.languages = languages
}
func languages() -> Set {
var unique: Set = Set()
for language in _languages {
unique.insert(language)
}
return unique
}
}
class Person(
val name: String,
vararg val languages: Language
): Developer {
override fun languages(): Set {
val unique: Set = setOf()
for (language in languages) {
unique.plus(language)
}
return unique
}
}
Swift Kotlin
Slide 21
Slide 21 text
@jacksoncheek
let jackson: Person = Person(
name: "Jackson Cheek",
.kotlin,
.java,
.swift
)
val jackson: Person = Person(
"Jackson Cheek",
Language.KOTLIN,
Language.JAVA,
Language.SWIFT
)
Swift Kotlin
Slide 22
Slide 22 text
Kotlin != Swift
Slide 23
Slide 23 text
guard
Preference for early return and
optional unwrapping
Slide 24
Slide 24 text
@jacksoncheek
guard [expression|condition] else {
[statement]
return
}
Swift
Slide 25
Slide 25 text
@jacksoncheek
var optName: String? = "Jackson Cheek"
guard let name = optName else {
print("Oops")
return
}
print("My name is \(name)")
// My name is Jackson Cheek
Swift
Slide 26
Slide 26 text
@jacksoncheek
var optName: String? = "Jackson Cheek"
guard let name = optName else {
print("Oops")
return
}
print("My name is \(name)")
// My name is Jackson Cheek
var optName: String? = "Jackson Cheek"
val name = optName?.let {
it
}
if (name != null) {
print("My name is $name")
} else {
print("Oops")
}
// My name is Jackson Cheek
Swift Kotlin
Slide 27
Slide 27 text
@jacksoncheek
var optName: String? = "Jackson Cheek"
let age = 30
guard let name = optName, age > 21 else {
print("Conditions not met")
return
}
print("Conditions met”)
// Conditions met
Swift
Slide 28
Slide 28 text
@jacksoncheek
var optName: String? = "Jackson Cheek"
let age = 30
guard let name = optName, age > 21 else {
print("Conditions not met")
return
}
print("Conditions met”)
// Conditions met
var optName: String? = "Jackson Cheek"
val age = 30
val name = optName?.let {
it
}
if (name != null && age > 21) {
print("Conditions met")
} else {
print("Conditions not met")
}
// Conditions met
Swift Kotlin
Slide 29
Slide 29 text
swizzle
Changing an implementation at
runtime
(dangerous)
@jacksoncheek
• viewDidLoad
• viewWillAppear
• viewDidAppear
• viewWillDisappear
• viewDidDisappear
Product Manager:
“I want to track every time a user
lands on a new screen!”
Slide 33
Slide 33 text
@jacksoncheek
@objc func swizzledViewDidAppear() {
guard let screenName = className else {
return
}
analyticsService.trackScreen(screenName: screenName)
}
Swift
Slide 34
Slide 34 text
@jacksoncheek
@objc func swizzledViewDidAppear() {
guard let screenName = className else {
return
}
analyticsService.trackScreen(screenName: screenName)
}
class func swizzle() {
guard self === UIViewController.self else { return }
let original = class_getInstanceMethod(
self,
#selector(viewDidAppear(_:))
)
}
Swift
Slide 35
Slide 35 text
@jacksoncheek
@objc func swizzledViewDidAppear() {
guard let screenName = className else {
return
}
analyticsService.trackScreen(screenName: screenName)
}
class func swizzle() {
guard self === UIViewController.self else { return }
let original = class_getInstanceMethod(
self,
#selector(viewDidAppear(_:))
)
} #selector
Reference to method in compiled code
Swift
Slide 36
Slide 36 text
@jacksoncheek
@objc func swizzledViewDidAppear() {
guard let screenName = className else {
return
}
analyticsService.trackScreen(screenName: screenName)
}
class func swizzle() {
guard self === UIViewController.self else { return }
let original = class_getInstanceMethod(
self,
#selector(viewDidAppear(_:))
)
let swizzled = class_getInstanceMethod(
self,
#selector(swizzledViewDidAppear)
)
}
Swift
Slide 37
Slide 37 text
@jacksoncheek
@objc func swizzledViewDidAppear() {
guard let screenName = className else {
return
}
analyticsService.trackScreen(screenName: screenName)
}
class func swizzle() {
guard self === UIViewController.self else { return }
let original = class_getInstanceMethod(
self,
#selector(viewDidAppear(_:))
)
let swizzled = class_getInstanceMethod(
self,
#selector(swizzledViewDidAppear)
)
method_exchangeImplementations(original!, swizzled!)
}
Swift
Slide 38
Slide 38 text
retain cycle
Just a memory leak
Slide 39
Slide 39 text
@jacksoncheek
• No garbage collector
Memory Management
@jacksoncheek
• No garbage collector
• Automatic Reference Counting
• Memory allocated for an object when initialized
Memory Management
Slide 42
Slide 42 text
@jacksoncheek
• No garbage collector
• Automatic Reference Counting
• Memory allocated for an object when initialized
• Memory deallocated when there are no more strong references
to that object
Memory Management
Slide 43
Slide 43 text
@jacksoncheek
• No garbage collector
• Automatic Reference Counting
• Memory allocated for an object when initialized
• Memory deallocated when there are no more strong references
to that object
• Leak when all references aren’t cleaned up
Memory Management
Slide 44
Slide 44 text
@jacksoncheek
class Person {
let name: String
var phone: Phone? = nil
init(name: String) { self.name = name }
}
class Phone {
let model: String
var owner: Person? = nil
init(model: String) { self.model = model }
}
Swift
Slide 45
Slide 45 text
@jacksoncheek
class Person {
let name: String
var phone: Phone? = nil
init(name: String) { self.name = name }
}
class Phone {
let model: String
var owner: Person? = nil
init(model: String) { self.model = model }
}
var jackson: Person? = Person(name: "Jackson")
var pixel3: Phone? = Phone(model: "Pixel 3")
Swift
Slide 46
Slide 46 text
@jacksoncheek
class Person {
let name: String
var phone: Phone? = nil
init(name: String) { self.name = name }
}
class Phone {
let model: String
var owner: Person? = nil
init(model: String) { self.model = model }
}
var jackson: Person? = Person(name: "Jackson")
var pixel3: Phone? = Phone(model: "Pixel 3")
jackson!.phone = pixel3
pixel3!.owner = jackson
Swift
Slide 47
Slide 47 text
@jacksoncheek
var jackson var pixel3
name: “Jackson”
phone: nil
model: “Pixel 3”
owner: nil
strong strong
1 1
var jackson: Person? = Person(name: "Jackson")
var pixel3: Phone? = Phone(model: "Pixel 3")
Swift
Slide 48
Slide 48 text
@jacksoncheek
var jackson var pixel3
name: “Jackson”
phone:
model: “Pixel 3”
owner:
strong strong
strong
strong
2 2
var jackson: Person? = Person(name: "Jackson")
var pixel3: Phone? = Phone(model: "Pixel 3")
jackson!.phone = pixel3
pixel3!.owner = jackson
Swift
Slide 49
Slide 49 text
@jacksoncheek
var jackson var pixel3
strong
strong
name: “Jackson”
phone:
model: “Pixel 3”
owner:
1 1
var jackson: Person? = Person(name: "Jackson")
var pixel3: Phone? = Phone(model: "Pixel 3")
jackson!.phone = pixel3
pixel3!.owner = jackson
jackson = nil
pixel3 = nil
Swift
Slide 50
Slide 50 text
@jacksoncheek
class Phone {
let model: String
weak var owner: Person? = nil
init(model: String) { self.model = model }
}
Swift
var jackson var pixel3
name: “Jackson”
phone:
model: “Pixel 3”
owner:
strong strong
strong
strong
2 2
Slide 51
Slide 51 text
@jacksoncheek
var jackson var pixel3
name: “Jackson”
phone:
model: “Pixel 3”
owner:
strong strong
strong
weak
1 2
class Phone {
let model: String
weak var owner: Person? = nil
init(model: String) { self.model = model }
}
Swift
Slide 52
Slide 52 text
@jacksoncheek
var jackson var pixel3
name: “Jackson”
phone:
model: “Pixel 3”
owner:
strong
strong
weak
0 2
jackson = nil
Swift
Slide 53
Slide 53 text
@jacksoncheek
jackson = nil
Swift
var jackson var pixel3
strong
model: “Pixel 3”
owner: nil
1
Slide 54
Slide 54 text
@jacksoncheek
var jackson var pixel3
model: “Pixel 3”
owner: nil
0
jackson = nil
pixel3 = nil
Swift
Slide 55
Slide 55 text
@jacksoncheek
var jackson var pixel3
jackson = nil
pixel3 = nil
Swift
Slide 56
Slide 56 text
struct
Basically an object reference-less
data class
Slide 57
Slide 57 text
@jacksoncheek
struct State {
var isLoading: Bool
}
data class State(
var isLoading: Boolean
)
Swift Kotlin
Slide 58
Slide 58 text
@jacksoncheek
struct State {
var isLoading: Bool
}
var initial = State(isLoading: false)
data class State(
var isLoading: Boolean
)
var initial = State(isLoading = false)
Swift Kotlin
Slide 59
Slide 59 text
@jacksoncheek
struct State {
var isLoading: Bool
}
var initial = State(isLoading: false)
var copy = initial
data class State(
var isLoading: Boolean
)
var initial = State(isLoading = false)
var copy = initial
Swift Kotlin
Slide 60
Slide 60 text
@jacksoncheek
struct State {
var isLoading: Bool
}
var initial = State(isLoading: false)
var copy = initial
initial.isLoading = true
data class State(
var isLoading: Boolean
)
var initial = State(isLoading = false)
var copy = initial
initial.isLoading = true
Swift Kotlin
Slide 61
Slide 61 text
@jacksoncheek
struct State {
var isLoading: Bool
}
var initial = State(isLoading: false)
var copy = initial
initial.isLoading = true
print("Loading state: \(copy.isLoading)")
// Loading state: false
data class State(
var isLoading: Boolean
)
var initial = State(isLoading = false)
var copy = initial
initial.isLoading = true
print("Loading state: ${copy.isLoading}")
// Loading state: true
Swift Kotlin
Slide 62
Slide 62 text
argument labels
Syntactic sugar
Slide 63
Slide 63 text
@jacksoncheek
enum AccountType {
case credit
case debit
}
class Shopper {
func payBill(accountType: AccountType) {
print("Thank you!")
}
}
enum class AccountType {
CREDIT,
DEBIT
}
class Shopper {
fun payBill(accountType: AccountType) {
print("Thank you!")
}
}
Swift Kotlin
Slide 64
Slide 64 text
@jacksoncheek
enum AccountType {
case credit
case debit
}
class Shopper {
func payBill(accountType: AccountType) {
print("Thank you!")
}
}
let shopper: Shopper = Shopper()
shopper.payBill(accountType: .credit)
// Thank you!
enum class AccountType {
CREDIT,
DEBIT
}
class Shopper {
fun payBill(accountType: AccountType) {
print("Thank you!")
}
}
val shopper: Shopper = Shopper()
shopper.payBill(accountType = CREDIT)
// Thank you!
Swift Kotlin
Slide 65
Slide 65 text
@jacksoncheek
enum AccountType {
case credit
case debit
}
class Shopper {
func payBill(_ accountType: AccountType) {
print("Thank you!")
}
}
let shopper: Shopper = Shopper()
shopper.payBill(.credit)
// Thank you!
enum class AccountType {
CREDIT,
DEBIT
}
class Shopper {
fun payBill(accountType: AccountType) {
print("Thank you!")
}
}
val shopper: Shopper = Shopper()
shopper.payBill(CREDIT)
// Thank you!
Swift Kotlin
Slide 66
Slide 66 text
@jacksoncheek
enum AccountType {
case credit
case debit
}
class Shopper {
func payBill(with accountType: AccountType) {
print("Thank you!”)
}
}
let shopper: Shopper = Shopper()
shopper.payBill(with: .credit)
// Thank you!
enum class AccountType {
CREDIT,
DEBIT
}
class Shopper {
fun payBill(with accountType: AccountType) {
print("Thank you!")
}
}
val shopper: Shopper = Shopper()
shopper.payBill(with = CREDIT)
// Not possible!
❌
Swift Kotlin