How to use Result type to store success/failure states in Swift - TagMerge
3How to use Result type to store success/failure states in SwiftHow to use Result type to store success/failure states in Swift

How to use Result type to store success/failure states in Swift

Asked 1 years ago
1
3 answers

I think you need to do a lot more reading up on the Result type and how to use it because you have some very strange code above.

Here is my cleaned up version of your code, without a redefinition of Result and a proper way to handle .success

let lexer = Lexer(input: "1 + 2 + 3")
let tokensResult = try lexer.lex()

var tokens =  [Token]()
switch tokensResult {
case let .success(result):
    print("Found \(tokens.count) tokens \(tokens)")
    tokens = result
case let .failure(error):
    print("Could not lex \(lexer.input): \(error)")
}

let numbersResult = tokens.compactMap { token in
    switch token {
    case let .number(digit): return digit
    default: return nil
    }
}

Source: link

0

In my LoginViewController,
class LoginViewController: UIViewController {

    private let loginView = LoginView()

    @objc func loginButtonAction() {
        let idInputValue = loginView.loginIdTextField.text!
        let passInputValue = loginView.passwordTextField.text!
        
        LoginAPI().login(with: idInputValue, and: passInputValue, errorCompletion: show(message:)) { _ in
            let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as! SceneDelegate
            sceneDelegate.setRootVC(to: HomeViewController())
        }

    func showAlert(message: String) {
        let okAction = UIAlertAction(title: Alert.ButtonTitle.ok, style: .default, handler: nil)
        showAlert(title: Alert.Title.loginError, message: message, actions: [okAction], style: .alert)
    }

}
and my LoginAPI class,
import Alamofire
class LoginAPI {
    
    static var accountInfo: AccountInfo?
    private let loginEndpoint = "https://example.com"
    
    func login(with id: String, and password: String, errorCompletion: @escaping (_ m: String) -> Void?, successCompletion: @escaping () -> Void) {
        let parameter: [String: Any] = ["id": id, "password": password]
        
        AF.request(loginEndpoint, method: .post, parameters: parameter)
            .validate()
            .responseJSON { response in
                guard let data = response.data else {
                    errorCompletion(response.error)
                    return
                }
                
                let decoder: JSONDecoder = JSONDecoder()
                var accountInfo: AccountInfo?
                
                do {
                    accountInfo = try decoder.decode(AccountInfo.self, from: data)
                } catch {
                    errorCompletion(error)
                }
               
                LoginAPI.accountInfo = accountInfo
                
                DispatchQueue.main.async {
                    successCompletion()
                }
            }
    }
}
updated the function
func login(with id: String, and password: String, completed: @escaping (Result<AccountInfo, LoginError>) -> Void) {
    
    let parameter: [String: Any] = ["id": id, "password": password]
    AF.request(loginEndpoint, method: .post, parameters: parameter)
        .responseDecodable(of: AccountInfo.self) { response in

            switch(response.result) {
            case .success(let data):
                completed(.success(data))
            case .failure(let error):
                completed(.failure(.test))
            }
        }
}

Source: link

0

For example, if we wanted to write code that fetched 100,000 weather records from a server, processes them to calculate the average temperature over time, then uploaded the resulting average back to a server, we might have written this:
func fetchWeatherHistory(completion: @escaping ([Double]) -> Void) {
    // Complex networking code here; we'll just send back 100,000 random temperatures
    DispatchQueue.global().async {
        let results = (1...100_000).map { _ in Double.random(in: -10...30) }
        completion(results)
    }
}

func calculateAverageTemperature(for records: [Double], completion: @escaping (Double) -> Void) {
    // Sum our array then divide by the array size
    DispatchQueue.global().async {
        let total = records.reduce(0, +)
        let average = total / Double(records.count)
        completion(average)
    }
}

func upload(result: Double, completion: @escaping (String) -> Void) {
    // More complex networking code; we'll just send back "OK"
    DispatchQueue.global().async {
        completion("OK")
    }
}
When it comes to using that code, we need to call them one by one in a chain, providing completion closures for each one to continue the chain, like this:
fetchWeatherHistory { records in
    calculateAverageTemperature(for: records) { average in
        upload(result: average) { response in
            print("Server response: \(response)")
        }
    }
}
From Swift 5.5, we can now clean up our functions by marking them as asynchronously returning a value rather than relying on completion handlers, like this:
func fetchWeatherHistory() async -> [Double] {
    (1...100_000).map { _ in Double.random(in: -10...30) }
}

func calculateAverageTemperature(for records: [Double]) async -> Double {
    let total = records.reduce(0, +)
    let average = total / Double(records.count)
    return average
}

func upload(result: Double) async -> String {
    "OK"
}
That has already removed a lot of the syntax around returning values asynchronously, but at the call site it’s even cleaner:
func processWeather() async {
    let records = await fetchWeatherHistory()
    let average = await calculateAverageTemperature(for: records)
    let response = await upload(result: average)
    print("Server response: \(response)")
}
For example, we might have functions that attempt to fetch a number of users from a server, and save them to disk, both of which might fail by throwing errors:
enum UserError: Error {
    case invalidCount, dataTooLong
}

func fetchUsers(count: Int) async throws -> [String] {
    if count > 3 {
        // Don't attempt to fetch too many users
        throw UserError.invalidCount
    }

    // Complex networking code here; we'll just send back up to `count` users
    return Array(["Antoni", "Karamo", "Tan"].prefix(count))
}

func save(users: [String]) async throws -> String {
    let savedUsers = users.joined(separator: ",")

    if savedUsers.count > 32 {
        throw UserError.dataTooLong
    } else {
        // Actual saving code would go here
        return "Saved \(savedUsers)!"
    }
}

Source: link

Recent Questions on swift

    Programming Languages