Reputation: 473
I found a problem with designing result class in swift
struct Result<T>{
private let data: T?
let error: NSError?
var isSuccess: Bool {
get {
return data != nil
}
}
init(data: T) {
self.data = data
self.error = nil
}
init(error: NSError) {
self.data = nil
self.error = error
}
}
Usage should look like this
Result(data: "something") // T as string
The problem occurs when I want to pass an error
Result(error: errorFromSomewhere) //T is not specified
Below is real application usage:
class ParseRegistrationProvider: RegistrationProvider {
func register(model: RegistrationForm) -> Promise<Result<String>> {
return Promise { accept, reject in
let user = PFUser()
user.username = model.nickName
user.password = model.password
user.email = model.emailAdreess
user.signUpInBackgroundWithBlock({ (isSuccess, error) -> Void in
if isSuccess {
accept(Result(data: "OK"))
} else {
var errorResult = Result(error: error!) //causes error
reject(errorResult)
}
})
}
}
}
"errorResult" causes compiler error:
Generic parameter T could not be inferred
Update: this approch works correctly:
Result<String>(error: errorFromSomewhere)
Upvotes: 1
Views: 484
Reputation: 1285
To answer your question directly, you could just declare errorResult as:
var errorResult : Result<String>
That would fix the problem immediately. However, I think the better solution is to use an enum instead of a struct as it is more appropriate (unless there is more to it than you posted).
enum Result<T> {
case Data(T)
case Error(NSError)
var success : Bool {
switch self {
case .Data:
return true
case .Error:
return false
}
}
}
Upvotes: 0
Reputation: 788
I'd like to suggest to use variant type for Result like this cause it is more compact and can be used in pattern matching naturally:
enum Result<T>{
case Data(T?)
case Error(NSError)
var isSuccess: Bool{
get{
switch self{
case .Data(_?):
return true
default:
return false
}
}
} }
Your code may become like this:
class ParseRegistrationProvider: RegistrationProvider {
func register(model: RegistrationForm) -> Promise<Result<String>> {
return Promise { accept, reject in
let user = PFUser()
user.username = model.nickName
user.password = model.password
user.email = model.emailAdreess
user.signUpInBackgroundWithBlock({ (isSuccess, error) -> Void in
if isSuccess {
accept(Result<String>.Data("OK"))
} else {
var errorResult = Result<String>(error: error!) //causes error
reject(errorResult)
}
})
}
}
}
Upvotes: 1
Reputation: 869
When you use classes instead of structs, you can define one base class (e.g. ErrorResult
with init(error: NSError)
) and one derived Result<T>
) with init(data: T)
).
This way, you entirely side-step the generic parameter. However, you potentially add some run-time overhead because of using a class.
Upvotes: 0