Swift(iOS) Development Introduction


Tools: XCode


Press 'Space' to continue

Press 'n' to show/hide notes

Press 's' for speaker mode

Benjamin Dumont

Language

  • Objective-C (legacy)
  • Swift

Both languages are interropable (with constraints).
We will work only on the Swift language on the following slides.

Variables and constants

                     
let string1 = "Hello World!"
let string2: String = "Hello World!"
var string3 = "Hello World!"
var string4: String = "Hello World!"
                     
                  

Array

                     
let array1 = ["Pierre", "Paul", "Jacques"]
let array2: [String] = ["Pierre", "Paul", "Jacques"]
var array3: [String] = [] // Empty array of strings
var array4 = [String]() // Empty array of strings
                     
                  

Optional

                     
var string1: String // Mandatory, must be initialized directly or inside constructor
var string2: String? // Optional, may be nil
var string3: String! // Mandatory, must not be initialized but must not be nil when used (to prevent crash)
                     
                  

Unwrap an Optional

                     
var string: String? = "Hello World!" // optional, even if initialized
if let string = string {
   print(string) // not optional
}
// Swift 5.7 version
if let string {
   print(string) // not optional
}
                     
                  

Guard

Guard statement is added to the common list of statements like if, else if, else ...
Its body must return something or throw an error

                     
var string: String?
guard let string else {
   print("string is nil")
   return
}
print("string is not nil")
                     
                  

Common array methods

  • forEach: iterates on each element
  • map: transforms each element
  • compactMap: transforms each element and remove nil value
  • reduce: convert the array to one value (e.g.: used to convert an array of Int to the sum of each element)

Access levels

                     
open var ... // Accessible outside and inside a module, allows to subclass and override
public var ... // Accessible outside and inside a module
internal var ... // Accessible inside a module (default, keyword not mandatory)
fileprivate var ... // Accessible inside the current file
private var ... // Accessible inside the entity and extensions inside the same file
                     
                  

Functions

                     
func fooBar() // Instance Void function
func fooBar(string: String) -> Int // Instance function taking a String argument and returning an Int
static func fooBar() // Class method, no instance
                     
                  

Class and Struct

  • Define properties to store values
  • Define methods to provide functionality
  • Define initializers to set up their initial state
  • Be extended to expand their functionality beyond a default implementation
  • Conform to protocols to provide standard functionality of a certain kind

Class additional capabilities

  • Inheritance enables one class to inherit the characteristics of another.
  • Type casting enables you to check and interpret the type of a class instance at runtime.
  • Deinitializers enable an instance of a class to free up any resources it has assigned.
  • Reference counting allows more than one reference to a class instance.
  • Class vs Struct (1/3)

    • Class: Reference
    • Struct: Value
    • Use Struct by default, Class when needed

    Class vs Struct (2/3)

                         
    class MyClass {
        var value: String
        
        init(value: String) {
            self.value = value
        }
    }
    
    var myClass1 = MyClass(value: "value")
    var myClass2 = myClass1
    myClass1.value = "new value"
    print("myClass1 value: \(myClass1.value)") // new value
    print("myClass2 value: \(myClass2.value)") // new value
                         
                      

    Class vs Struct (3/3)

                         
    struct MyStruct {
        var value: String
    }
    
    var myStruct1 = MyStruct(value: "value")
    var myStruct2 = myStruct1
    myStruct1.value = "new value"
    print("myStruct1 value: \(myStruct1.value)") // new value
    print("myStruct2 value: \(myStruct2.value)") // value
                         
                      

    Enum

                         
    enum Person {
       case Pierre
       case Paul
       case Jacques
    }
    
    // With raw value
    enum MyInt: Int {
       case one = 1
       case two
       case three
    }
                         
                      

    Extensions

    To extend Class/Struct/Enum capabilities

                         
    extension String {
       func appendCurrency() -> String {
          self + " €"
       }
    }
                         
                      

    Protocol

    To tell an entity its conformance

                         
    protocol MyProtocol {
       var myVar: String { get }
       func doSomething()
    }
    
    struct MyStruct: MyProtocol {
       var myVar: String {
          "Hello World!"
       }
    
       func doSomething() {
          print(myVar)
       }
    }
                         
                      

    Exercice

    • Create an array of integers from 1 to 100
    • Create an array from it containing "foo" when %3, "bar" when %5, "foobar" when %15, nil otherwise
    • Remove nil values

    Solution

                         
    Array(1...100).map { element -> String? in
        [(15, "foobar"), (3, "foo"), (5, "bar")].first(where: { element.isMultiple(of: $0.0) })?.1
    }.compactMap { $0 }
    // OR
    Array(1...100)
       .compactMap { element -> String? in [(15, "foobar"), (3, "foo"), (5, "bar")].first(where: { element.isMultiple(of: $0.0) })?.1 }
                         
                      

    Asynchonous code with delegate pattern

                         
    protocol DoSomething: AnyObject {
        func printSomething(_ string: String)
    }
    
    class Parent: DoSomething {
        func printSomething(_ str: String) {
            print(str)
        }
        func onClick() {
            Child(delegate: self).doSomething()
        }
    }
    
    class Child {
        weak private var delegate: DoSomething?
        init(delegate: DoSomething) {
            self.delegate = delegate
        }
        func doSomething() {
            delegate?.printSomething("Hello World!")
        }
    }
    
    Parent().onClick()
                         
                      

    Asynchonous code with closure

                         
    class Parent {
        
        func printSomething(_ str: String) {
            print(str)
        }
        func onClick() {
            Child { [weak self] string in
                self?.printSomething(string)
            }.doSomething()
        }
    }
    
    class Child {
        
        private var completion: (String) -> Void
        
        init(completion: @escaping (String) -> Void) {
            self.completion = completion
        }
        func doSomething() {
            completion("HelloWorld")
        }
    }
    Parent().onClick()
                         
                      

    Asynchonous code with Reactiv Programming

    • RxSwift (external library)
    • Combine (native, iOS 13 minimum)

    Asynchonous code async/await

    Since Swift 5.5

                         
    func fetchImages() async throws -> [UIImage] {
      // .. perform data request
    }
    ...
    let result = try await fetchImages()
                         
                      

    Github: benjdum59
    Website: benjdum59.github.io
    Mail: benjamin.dumont.pro@gmail.com

    Go to Homepage