Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Attempt at a wrapper for NSError** parameter calls (as typically seen when calling objc APIs)
// https://gist.github.com/feinstruktur/2f427934e171a8ab13af
import Foundation
public class Box<T> {
let unbox: T
init(_ value: T) { self.unbox = value }
}
public enum Result<T> {
case Success(Box<T>)
case Failure(NSError)
public init(_ value: T) { self = .Success(Box(value)) }
public init(_ error: NSError) { self = .Failure(error) }
public var succeeded: Bool {
switch self {
case .Success:
return true
default:
return false
}
}
public var failed: Bool {
return !self.succeeded
}
public var value: T? {
switch self {
case .Success(let value):
return value.unbox
default:
return nil
}
}
public var error: NSError? {
switch self {
case .Failure(let error):
return error
default:
return nil
}
}
}
func try(block: NSErrorPointer -> Void) -> NSError? {
var error: NSError?
block(&error)
return error
}
func try<T>(block: NSErrorPointer -> T) -> Result<T> {
var error: NSError?
let res = block(&error)
if error == nil {
return Result(res)
} else {
return Result(error!)
}
}
// specialisation for Bool, because Bool return values signal stronger than NSError (for example in Core Data)
public func try(block: NSErrorPointer -> Bool) -> Result<Bool> {
var error: NSError?
let res = block(&error)
if res {
return Result(res)
} else {
return Result(error!)
}
}
// -----------------------------------------------------------
// Usage
// -----------------------------------------------------------
// - Helpers to create test cases
enum Param {
case Good, Bad
}
func doSomething(param: Param, error: NSErrorPointer) -> Bool {
switch param {
case .Good:
error.memory = nil
return true
case .Bad:
error.memory = NSError(domain: "Test", code: 42, userInfo: ["Key": "Value"])
return false
}
}
func doSomething2(param: Param, error: NSErrorPointer) -> String {
switch param {
case .Good:
error.memory = nil
return "Success"
case .Bad:
error.memory = NSError(domain: "Test", code: 42, userInfo: ["Key": "Value"])
return "Failure"
}
}
// - end of test helpers
// first version
if let error = try({ error in
let res = doSomething(.Good, error)
"above should be true"
}) {
"should not be reached"
}
if let error = try({ error in
let res = doSomething(.Bad, error)
}) {
error.code
"above should be 42"
}
// second version
// short circuit
if let res = try({ error in doSomething2(.Good, error) }).value {
res
"above should be 'Success'"
} else {
"should not be reached"
}
if let res = try({ error in doSomething2(.Bad, error) }).value {
"should not be reached"
} else {
"ok"
}
// long form
switch try({ error in doSomething(.Good, error) }) {
case .Success(let value):
value.unbox
"above should be true"
case .Failure(let error):
"should not be reached"
}
switch try({ error in doSomething(.Bad, error) }) {
case .Success(let value):
"should not be reached"
case .Failure(let error):
error.code
"above should be 42"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment