Startseite Optimizing an iOS Application: Case Study of the Parkplatzmanager App
Eintrag
Abbrechen

Optimizing an iOS Application: Case Study of the Parkplatzmanager App

In the last couple of days, we’ve embarked on an exciting journey of improving and optimizing an iOS application, the parkplatzmanager app. In this blog post, we will walk you through some of the changes we made and how they led to a more efficient and well-structured app.

Introduction

The parkplatzmanager app had been initially developed with a basic architecture, and as it grew in complexity, there were areas in the code that needed optimization and restructuring. Some of the issues we identified included ambiguous type inference, a lack of email validation, handling cache expiration, and dealing with data inconsistencies due to incorrect key-value mapping in the JSON response.

Let’s walk through how we tackled each of these issues.

1. Resolving Ambiguous Type Inference

Swift, like many other languages, performs type inference to determine the type of an expression when it’s not explicitly provided. However, sometimes the compiler might face difficulties in inferring the type of an expression, especially when multiple type possibilities exist. We encountered such an issue in the ParkingService.swift file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
return Promise { seal in
    firstly {
        RealDataRepository.shared.fetchUserData(userId: userId, groupId: groupId)
    }.done { vehicleData in
        do {
            // Process the data
            seal.fulfill(())
        } catch let error {
            seal.reject(error)
        }
    }.catch { error in
        seal.reject(error)
    }
}

Here, Swift was unable to infer the type of vehicleData. To resolve this, we explicitly provided the type of the vehicleData:

1
2
3
4
5
6
7
8
RealDataRepository.shared.fetchUserData(userId: userId, groupId: groupId)
}.done { (vehicleData: [Vehicle]) in
    do {
        // Process the data
        seal.fulfill(())
    } catch let error {
        seal.reject(error)
    }

2. Enforcing Email Validation

In the InviteView.swift file, we observed that the app did not validate emails, potentially leading to incorrect or invalid email addresses being accepted.

We first introduced a method isValidEmail(_ email: String) -> Bool which was initially left as a placeholder. Later, we added a simple email validation logic:

1
2
3
4
5
private func isValidEmail(_ email: String) -> Bool {
    let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
    let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegex)
    return emailTest.evaluate(with: email)
}

Furthermore, we made the text field in SwiftUI ignore auto-capitalization, ensuring that only lower case characters are allowed:

1
2
3
TextField("Email", text: $email)
    .keyboardType(.emailAddress)
    .autocapitalization(.none)

3. Handling Cache Expiration

Our app uses Redis for caching, and we identified a need to set a time-to-live (TTL) or expiration for our keys to control the freshness of the data. This can be done using the EXPIRE command in Redis:

1
2
await redis.set(cache_key, json.dumps(vehicle))
await redis.expire(cache_key, 300)  # Set a TTL of 300 seconds

4. Addressing JSON Key-Value Mapping Inconsistencies

The application experienced crashes due to mismatches between the expected and received JSON data, particularly a missing vehicle key. We realized that the received JSON’s structure was not what the app expected.

To fix this, we updated our model to match

the actual data received, ensuring that the keys in the Swift model matched the keys in the JSON data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct ResponseData: Codable {
    let status: String
    let data: [Vehicle]
}

struct Vehicle: Codable {
    let _id: String
    let fullName: String?
    let groupId: String
    let latitude: Double
    let licensePlate: String
    let longitude: Double
    let timestamp: String
    let userId: String
    let vehicleStatus: String
    let vin: String?
    
    enum CodingKeys: String, CodingKey {
        case _id
        case fullName
        case groupId = "group_id"
        case latitude
        case licensePlate = "license_plate"
        case longitude
        case timestamp
        case userId = "user_id"
        case vehicleStatus = "vehicle_status"
        case vin
    }
}

Conclusion

Optimizing an app often involves refactoring and improving the existing code to ensure it’s efficient, scalable, and maintainable. In our case, we were able to solve type inference ambiguity, improve data validation, handle cache expiration, and deal with JSON key-value inconsistencies. These changes significantly improved the parkplatzmanager app’s robustness and efficiency, and we hope this walkthrough was insightful and helpful!

Dieser Eintrag ist vom Autor unter CC BY 4.0 lizensiert.