Skip to content

7. IOS Development in Swift – Some Advance Concepts

1 TestFlight

  • Two accounts must be made with Apple Developer Program and App Store Connect.
  • The app must be archived (Product > Archive) and uploaded to App Store Connect.
  • The process of archiving requires signing the app with a certificate and provisioning profile.
  • Types of Testers:
    • Internal Testers: Members of the development team (up to 100 users). Managed from App Store Connect.
    • External Testers: Users outside the development team (up to 10,000 users).
  • Head to App Store Connect > My Apps > [App] > TestFlight > iOS > Test Information > External Testers > Add New Tester.

2 Persistent Storage

  • Persistent storage is used to store data locally on the device, and sync it with a remote server when the device is online or periodically.
  • Databases:
    • SQLite: lightweight file, does not load data to memory, does not require a separate server process.
    • Core Data: Native to IOS, default support for migrations and filters/search. nice interface. can be graph based or multithreaded. It is not compatible with Android stores and consumes memory.
    • Firebase: NoSQL. Realtime database with automatic syncing. Data stored as JSON. Compatible with all ios/android/web. All clients are notified when data changes.
    • Realm: Document based, can be shared between platforms. Compatible with all platforms. Relationships are not supported.
  • Configuration Stores:
    • NSUserDefaults: Not secure, Native, easy to use. save data as key-value pairs (text).
    • Plist (Property List): save data as XML or binary.
    • NsCoder: A protocol that enables an object to be encoded and decoded for archiving and distribution.

3 Running the App on a Device or Simulator

  • Simulators reflects the performance of the device running on and not the actual device (the user’s device).
  • Select the Build Scheme and Device from the top left corner of Xcode.
  • You can connect supported devices to your Mac using a cable or through a network (Wifi)

4 Core Data

  • Core Data is a framework that you use to manage the model layer objects in your application.
  • NsPersistentContainer is a container that encapsulates the Core Data stack in your application, and it has three members:
    • NsManagedObjectModel: The data model that you define for your app.
    • NsPersistentStoreCoordinator: The object that you use to interact with the underlying file system.
    • NsManagedObjectContext: The object that you use to manipulate and track changes to managed objects.

5 Networking

  • Building a url:
// Construct a URL by assigning its parts to a URLComponents value
var components = URLComponents()
components.scheme = "https"
components.host = "api.github.com"
components.path = "/users/johnsundell"

// This will give us the constructed URL as an optional
let url = components.url
  • Use that url to build a data task:
// Create a data task, which will handle downloading and
// managing the lifetime of any temporary data that's
// downloaded as part of the request
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    // Check for any errors
    guard error == nil else {
        print("Error: \(error!)")
        return
    }

    // Convert the data to a string (for display purposes)
    let dataString = String(data: data!, encoding: .utf8)
    print(dataString ?? "No data")

    // The data comes back in a raw, unprocessed form,
    // which we can turn into JSON quite easily
    let json = try! JSONSerialization.jsonObject(with: data!, options: [])
    print(json)
}
  • As Networking is an asynchronous operation, we don’t want to block the main thread. So we use a data task to perform the networking operation in the background, then we use Grand Central Dispatch to get back to the main thread when we’re done.
let task = URLSession.shared.dataTask(with: url) { data, response, error in
   DispatchQueue.main.async {
       // Update the UI
       if let data = data {
            label.text = String(decoding: data, as: UTF8.self)
       } else {
            label.text = error?.localizedDescription
       }
   }
}
  • then the task must be started:
task.resume()

6 Swift

Error Handling

  • Custom Errors must conform to the Error protocol.
  • Use throw to throw an error and throws to mark a function that can throw an error.
enum LoginError: Error {
    case invalidUsername
    case invalidPassword
}

enum MyError: Error {
    case error1
    case error2
}

func login(username: String, password: String) throws {
    guard username == "john" else {
        throw LoginError.invalidUsername
    }

    guard password == "password" else {
        throw LoginError.invalidPassword
    }

    print("Successfully logged in!")
}


do {
    try login(username: "john", password: "password")
} catch is LoginError {
    print("Login failed: \(error)")
} catch MyError.error1, MyError.error2 {
    print("Error 1")
} catch {
  print("Unexpected error: \(error)")
}

Generics

  • Generics allow us to write code that can work with any type, rather than just a single, specific type.
  • Generic swap function:
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}
  • Generic Stack:
struct Stack<Element> {
    var items = [Element]()

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element {
        return items.removeLast()
    }
}

// extending the generic stack with isEmpty(),and access to the `top` element
extension Stack {
    var isEmpty: Bool {
        return items.isEmpty
    }

    var top: Element? { // Element is available from the parent struct
        return items.last
    }
}

Protocols

  • A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.
  • Protocol is an interface in other languages that can be adopted (implemented) by a class, struct or enum.
  • A class/struct/enum conforms to a protocol by implementing all of its requirements.
  • Multiple protocols can be adopted by a class/struct/enum by separating them with a comma.
protocol SomeProtocol {
    // protocol definition goes here
}

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // structure definition goes here
}

References


  1. Katz, M. (2020, August 19). TestFlight tutorial: iOS beta testing. raywenderlich.com. https://www.raywenderlich.com/10868372-testflight-tutorial-ios-beta-testing 

  2. Muramshetty, D. (2019, May 7). Persistent storage options in iOS. Innominds. https://www.innominds.com/blog/persistent-storage-options-in-ios 

  3. Running your app in the simulator or on a device. (n.d.). Apple Developer. https://developer.apple.com/documentation/xcode/running-your-app-in-simulator-or-on-a-device/ 

  4. Setting up a core data stack. (n.d.). Apple Developer. https://developer.apple.com/documentation/coredata/setting_up_a_core_data_stack 

  5. Sundell, J. (2019, January 14). Networking. SwiftbySundell. https://www.swiftbysundell.com/basics/networking/ 

  6. The swift programming language swift 5.7. (n.d.). Apple Inc. https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html