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 totodos
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 aURLSessionDataTask
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 theError
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¶
- Sundell, J. (2019, January 14). Networking. SwiftbySundell. https://www.swiftbysundell.com/basics/networking/
- The swift programming language swift 5.7. (n.d.). Apple Inc. https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html