Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swift Cheatsheet for
Android/Kotlin Developers

Swift Cheatsheet for
Android/Kotlin Developers

Presented at droidcon London 2024

Knowing common Swift patterns and how they translate to Kotlin can help us understand better what the code does. Whether to see how some feature is implemented on the neighbor platform, perform code reviews, review or write tech specifications/proposals, or work with Kotlin Multiplatform.

We will go over some of the basics of the Swift language and how it compares to Kotlin. Additionally, we will cover common patterns that you might find in a typical iOS project like optional bindings, dictionaries, extensions, structures, and protocols.

Leave this talk confident you can read, understand, and review Swift/iOS code. It will also help you start with Kotlin Multiplatform where knowledge of Swift and SwiftUI is important.

Domen Lanišnik

October 31, 2024
Tweet

More Decks by Domen Lanišnik

Other Decks in Programming

Transcript

  1. Why Swift? • To be able to read and understand

    iOS code • To provide code reviews for iOS teammates • To better collaborate with iOS teammates • Kotlin Multiplatform, Flutter, other cross-platform frameworks • *Also applies to iOS developers looking at Kotlin/Android code
  2. Variables and constants Basics let animDurationMillis: Int = 500 var

    clickCount = 0 val animDurationMillis: Int = 500 var clickCount = 0
  3. Fallback / default value Basics - Optionals / Nullability let

    actualFoundItem = foundItem ?? "empty" val actualFoundItem = foundItem ?: "empty"
  4. Control flow Basics if foundItem != nil { // do

    something } if (foundItem != null) { // do something }
  5. Control flow cont. Basics let description = if delta <=

    10 { "low" } else if delta >= 50 { "high" } else { "medium" }
  6. For loop Basics let names = ["Alice", "Bob", "Charlie"] for

    name in names { print(name) } val names = listOf("Alice", "Bob", "Charlie") for (name in names) { println(name) }
  7. Functions Basics func addTwoNumbers(a: Int, b: Int) -> Int {

    return a + b } fun addTwoNumbers(a: Int, b: Int): Int { return a + b }
  8. If let Optional Binding let fetchedUserId: String? = "user_id" if

    let userId = fetchedUserId { updateUser(id: userId) } else { throw Error("Missing user id") }
  9. If let Optional Binding if let userId = fetchedUserId {

    updateUser(id: userId) } else { throw Error("Missing user id") } let fetchedUserId: String? = "user_id"
  10. If let Optional Binding updateUser(id: userId) } else { throw

    Error("Missing user id") } if let userId = fetchedUserId { let fetchedUserId: String? = "user_id"
  11. If let Optional Binding } else { throw Error("Missing user

    id") } if let userId = fetchedUserId { let fetchedUserId: String? = "user_id" updateUser(id: userId)
  12. If let Optional Binding } else { throw Error("Missing user

    id") } let fetchedUserId: String? = "user_id" if let userId = fetchedUserId { updateUser(id: userId)
  13. If let Optional Binding let fetchedUserId: String? = "user_id" if

    let fetchedUserId { // can be used as non-optional constant updateUser(id: fetchedUserId) }
  14. If let Optional Binding val fetchedUserId: String? = "user_id" if

    (fetchedUserId != null) { updateUser(fetchedUserId) } else { throw Exception("Missing user id") }
  15. Guard Optional Binding func isUsernameValid(username: String?) -> Bool { guard

    let username else { return false } return username.count > 3 }
  16. func isUsernameValid(username: String?) -> Bool { return username.count > 3

    } Guard Optional Binding guard let username else { return false }
  17. func isUsernameValid(username: String?) -> Bool { } Guard Optional Binding

    guard let username else { return false } return username.count > 3
  18. Types of collections Collections Array Indexes Values 0 1 2

    3 4 Alice Bob Charlie Dean Eve Set Values Alice Bob Eve Dictionary Keys Values LAX DUB LHR Los Angeles Intl. London Heathrow Dublin Airport
  19. Arrays Collections var names = ["Alice", "Bob", "Charlie"] names +=

    [“John"] for name in names { print(name) }
  20. Sets Collections var favoriteNames: Set = ["Alice", "Eve", "Bob"] if

    !favoriteNames.contains("John") { favoriteNames.insert("John") }
  21. Dictionary / Map Collections var httpErrorCodes: [Int: String] = [

    404: "Not found", 401: "Unauthorized" ] httpErrorCodes[500] = "Internal Server Error" let requestError = httpErrorCodes[400] ?? “Unknown"
  22. Structures vs Classes Structures and classes • Similar when modeling

    data (properties and functions) • Classes are pass-by-reference • Structures are pass-by-value • O ffi cial recommendation is to use structures by default • Use classes for inheritance, Objective-C compatibility and others
  23. Structures Structures and Classes struct VehicleStructure { var maxSpeed =

    0 func printInfo() { print("Max speed \(maxSpeed)") } }
  24. Classes Structures and Classes class VehicleClass { var maxSpeed =

    0 func printInfo() { print("Max speed \(maxSpeed)") } }
  25. Structures and Classes Structures and Classes class Vehicle(var maxSpeed: Int)

    { fun printInfo(){ println("Max speed is $maxSpeed") } } val car = Vehicle(250) car.printInfo()
  26. Declaration Enums enum Direction { case left case up case

    right case down } enum Direction { case left, up, right, down }
  27. Checking for values Enums switch(selectedDirection){ case .left: goLeft() case .up:

    goForward() case .right: goRight() case .down: goBackward() }
  28. Associated Values Enums enum ColorType { case rgb(Int, Int, Int)

    case hex(String) } var buttonColor = ColorType.rgb(0, 255, 0) buttonColor = .hex(“#00FF00")
  29. Associated Values Enums switch buttonColor { case .rgb(let red, let

    green, let blue): print("RGB: \(red), \(green), \(blue)") case .hex(let code): print("Hex code: \(code)") }
  30. Associated Values Enums switch buttonColor { case let .rgb(red, green,

    blue): print("RGB: \(red), \(green), \(blue)") case let .hex(code): print("Hex code: \(code)") }
  31. Declaration and usage Enums enum class Direction { LEFT, UP,

    RIGHT, DOWN } var selectedDirection = Direction.UP when(selectedDirection){ Direction.LEFT -> goLeft() Direction.UP -> goForward() Direction.RIGHT -> goRight() Direction.DOWN -> goBackward() }
  32. Associated values Enums sealed class ColorType { data class Rgb(

    val red: Int, val green: Int, val blue: Int ) : ColorType() data class Hex( val hex: String ) : ColorType() }
  33. Extensions Extensions extension String { func doubled() -> String {

    return self + self } } let doubledStr = "Swift".doubled() print(doubledStr) // prints "SwiftSwift"
  34. Extensions Extensions fun String.doubled(): String { return this + this

    } val doubledStr = "Kotlin".doubled() println(doubledStr) // prints "KotlinKotlin"
  35. What is a protocol? Protocols • Set of properties, methods,

    and other requirements that a class, structure, or enumeration can adopt by providing actual implementation of those requirements • Can have readable or writable properties • Support inheritance, composition, associated types, generics and more
  36. Example Protocols protocol RequestError { var errorCode: Int { get

    } var isRecoverable: Bool { get set} } protocol PrintableError { func buildErrorMessage() -> String }
  37. Adoption Protocols struct ConnectionError: RequestError, PrintableError { var errorCode: Int

    var isRecoverable: Bool func buildErrorMessage() -> String { return "Local connection error" } } let error = ConnectionError(errorCode: 404, isRecoverable: true)
  38. Adoption Protocols func onRequestError(error: RequestError) { if let printableError =

    error as? PrintableError { print(printableError.buildErrorMessage()) } print("Is recoverable: \(error.isRecoverable)") }
  39. Kotlin Protocols interface RequestError { val errorCode: Int var isRecoverable:

    Boolean } interface PrintableError { fun buildErrorMessage(): String }
  40. Kotlin Protocols class ConnectionError( override val errorCode: Int, override var

    isRecoverable: Boolean ) : RequestError, PrintableError { override fun buildErrorMessage(): String { return "Local connection error" } } val error = ConnectionError(errorCode = 404, isRecoverable = true)
  41. Closures Closures func someFunctionThatTakesAClosure(closure: () -> Void) { // function

    body goes here } someFunctionThatTakesAClosure() { // trailing closure's body goes here }
  42. Overview Concurrency • Swift has built-in support for writing asynchronous

    code in a structured way • Asynchronous code can be suspended and resumed later • Asynchronous function is a special kind of function that can be suspended while it’s partway through execution
  43. Example Concurrency func fetchUser(id: Int) async -> User { return

    // async network request } let user = await fetchUser(id: 1)
  44. Kotlin Concurrency suspend fun fetchUser(id: Int): User { return //

    network request } coroutineScope.launch { val user = fetchUser(1) }
  45. Example Concurrency async let firstUser = fetchUser(id: 1) async let

    secondUser = fetchUser(id: 2) let users = await [firstUser, secondUser]
  46. Summary • Swift syntax is quite similar to Kotlin •

    Mental mapping from Swift to Kotlin • Helps with understanding code, code reviews, tech speci fi cations • Helps with cross-platform (SwiftUI)
  47. Thank you! LinkedIn Twitter / X droidcon London 24 Swift

    Cheatsheet for
 Android/Kotlin Developers