Swift 5 Result Type

Specifying custom error type within the Result type in Swift 5

Just create Result manually:

let result: Result<Model, CustomError>
if (number < 20) {
result = .failure(.somethingBadHappened)
} else {
result = .success(Model(value: number))
}
completion(result)

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

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
}
}

How to use new Result type introduced in swift 5 URLSession?

You want to create an enum that specifies the possible cases in your result (e.g. success or failure). Then you add a completion to your getCategorByAPI() method that is of type Result<Data, Error>. From there, inside url session, you will call your completion handler passing in either the data on .success or the error on .failure.

You can also do cool things like override Result's get() method and extend Result to decode your data :D

Check it out:

enum Result<Success, Error: Swift.Error> {
case success(Success)
case failure(Error)
}

// override the Result.get() method
extension Result {
func get() throws -> Success {
switch self {
case .success(let value):
return value
case .failure(let error):
throw error
}
}
}

// use generics - this is where you can decode your data
extension Result where Success == Data {
func decoded<T: Decodable>(using decoder: JSONDecoder = .init()) throws -> T {
let data = try get()
return try decoder.decode(T.self, from: data)
}
}

func getCategorByAPI(completion: (Result<Data, Error>) -> Void)
{
// You might want to stick this into another method
let url = URL(string: URLManager.aPIBaseURL+"category")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in

if error != nil {
completion(.failure(error))
return
}

if !(200...299).contains(httpResponse.statusCode) && !(httpResponse.statusCode == 304) {
let httpError = // ... convert httpResponse.statusCode into a more readable error
completion(.failure(httpError))
}

if let data = data {
completion(.success(data))
}
}.resume()
}

I haven't tested the above but have something like this implemented in a current project. Here are some articles I read to learn about how to implement:

https://www.hackingwithswift.com/articles/161/how-to-use-result-in-swift

https://medium.com/@pavlepesic/how-to-use-swift-5-result-with-codable-protocol-824c9a951af9

Result type with generic Success Type

func request<String>(completion: @escaping (Result<String, Error>) -> Void) {

This is a classic generics mistake in Swift. This does not mean "request requires T==String." This means "there is an arbitrary type called String that this function accepts." There is no relationship between this String and Swift.String.

What you're trying to do here violates the protocol. The protocol says that the caller gets to pick any T they want. You can't conform to that protocol with a restricted T.

If you want the conforming type (RandomFetcher) to get to decide the type of T, then you have to use an associatedType (that's what associatedType means).

The thing you're trying to build is pretty common, but not trivial, and requires a different way of thinking about the problem. I walk through it step-by-step in this series.

How to create an array of Result type in swift?

Result has a mapError method you can call.

let results = [
nameResult.mapError { $0 as Error },
phoneNoResult.mapError { $0 as Error },
]

If you like you can create an extension to simplify things:

extension Result {
func hidingErrorType() -> Result<Success, Error> {
mapError { $0 as Error }
}
}

let results2 = [
nameResult.hidingErrorType(),
phoneNoResult.hidingErrorType(),
]

Converting From Swift 5 Type Result to Swift 3 Equivalent

The Result type in Swift 5 is basically

enum Result<Success, Failure> where Failure : Error {
case success(Success), failure(Failure)
}

If you don't need the init(catching or get() functionality or the map stuff the basic enum is sufficient

Getting error when trying to use Result type with delegate

Well, you have two problems, having to do with the question "what type is this?" Swift is very strict about types, so you need to get clear about that.

  • .networkConnectionLost is not an Error. It is an error code. You need to pass an Error object to a Result when you want to package up the error. For example, URLError(URLError.networkConnectionLost) is an Error.

  • The phrase Result<T, NetworkError> makes no sense. Result is already a generic. Your job is to resolve the generic that it already is. You do that by specifying the type.

So for example, you might declare:

func decodableResponce(_ result: Result<Decodable, Error>)

It is then possible to say (as tests):

decodableResponce(.failure(URLError(URLError.networkConnectionLost)))

or (assuming Movie is Decodable):

decodableResponce(.success([Movie()]))

That proves we have our types right, and you can proceed to build up your actual code around that example code.



Related Topics



Leave a reply



Submit