Skip to content

JA7. IOS

Part 1

Network Connection

How to make an internet connection in an iOS application and handle exceptions.

  • The code below fetches the https://jsonplaceholder.typicode.com/todos and parses the response into an array of TodoModel and appends it to todos array and displays all of that in the Todos App that we developed last week.
  • The code below constructs a URL first, then passes that URL to URLSession.shared.dataTask which returns a URLSessionDataTask object that we can use to fetch the data from the URL (Sundell, 2019).
 func fetchTodos () {
        // Construct a URL by assigning its parts to a URLComponents value
        var components = URLComponents()
        components.scheme = "https"
        components.host = "jsonplaceholder.typicode.com"
        components.path = "/todos"

        // This will give us the constructed URL as an optional
        let url = components.url!
        print(url)


        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)

            do { // convert json to array of `TodoModel` and append it to `todos`
                if let jsonArray = try JSONSerialization.jsonObject(with: data!, options: []) as? [[String: Any]] {
                    let newTodos = jsonArray.map { dictionary -> TodoModel in
                        let userId = dictionary["userId"] as? Int ?? 0
                        let id = dictionary["id"] as? Int ?? 0
                        let title = dictionary["title"] as? String ?? ""
                        let completed = dictionary["completed"] as? Bool ?? false
                        return TodoModel(
                            title: title,
                            status: completed ? TodoStatus.compeleted : TodoStatus.pending,
                            _id: id
                        )
                    }
                    print(newTodos)
                    self.todos.append(contentsOf: newTodos)
                }
            } catch {
                print("Error: Could not parse JSON: \(error)")
            }
        }

        task.resume()
    }


Part 2

Which error handling approach you have used in the app?

  • The way Swift handle errors is by throwing errors and catching them accordingly; however, you can not just throw where ever you can as this will crash the App and cause it to terminate which indicates a bad user experience.
  • Instead, you should throw errors only when you are sure that things are seriously bad and you can not recover.
  • Since I used swiftUI, which has a lot of utilities and helpers to raise issues to the user and drag their attention to problems. One way, is using Alerts.
  • Simply when a function withing a component faces an error it will stop executing and activate the alert; thus, we saved the component from crashing and the user gets notified.
// ... code
@State var error: String = ""
@State var showError: Bool = false

func signupHandler() {
    var isEmailValid = validateEmail(email: email)
    if(!isEmailValid) {
        error = "Invalid Email"
        showError = true
        return // terminate the function upon error
    }
}

// ...vew
ScrollView {
    // ... code
    .alert(isPresented: $showError) {
        Alert(
            title: Text("Error"),
            message: Text(error),
            dismissButton: .default(Text("OK"))
        )
    }
}
// ... code

What is the significance of the protocols used by you while developing the app?

  • 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
}
  • Protocols set a contract between the App components; in order for such a components to work together they should conform to the same protocol.
  • One of the most significant protocols is the Error protocol, which is used to represent errors that can be thrown by functions, methods, and initializers. Defining custom errors requires the newly defined type to adopt the Error protocol.
  • Another significant protocol is the ObservableObject protocol, which is used to make a class publish changes to its properties.
  • The Identifiable protocol is used to make a class identifiable by a unique ID.
  • The View protocol is used to mark a class as a SwiftUI view.
  • The App protocol is used to mark a class as a SwiftUI app.

Explain significance of the Generic code in your app.

  • 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
}
  • I did not define my own generics in my assignments; however I might have used some generic types in the libraries I used.
  • Example, the ForEach view in SwiftUI is a generic type that takes a generic type as a parameter and infers the type of the array passed to it, hence, it can infers the type of each element in the array and what fields are available in it.
ForEach(users) { user in
    Text(user.name)
}

References