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
More Precision Than Double in Swift
Location Access Request in iOS 11
Uidatepicker 15 Minute Increments Swift
How to Initialize UIbezierpath to Draw a Circle in Swift
Sknode Subclass Generates Error: Cannot Invoke Initializer for Type "X" with No Arguments
Error "[Sharesheet] Connection Invalidated" Error iOS13+ But Not on iOS 11.4
How to Use @Fetchrequest Outside a View
Why Does Cabasicanimation Try to Initialize Another Instance of My Custom Calayer
Easiest Way to Truncate Float to 2 Decimal Places
Swift Error: Failed to Get Module 'My_App' from Ast Context
Move Button When Keyboard Appears Swift
Can't Get Throws to Work with Function with Completion Handler