Created
November 17, 2015 12:56
-
-
Save mhuusko5/55471ea8b061475122ef to your computer and use it in GitHub Desktop.
toRACSignal() for SignalProducer of any type, for Obj-C shimming a project with a Swift ReactiveCocoa based API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public extension SignalProducerType { | |
func toRACSignal() -> RACSignal { | |
let signal = RACSignal.createSignal { subscriber in | |
let disposable = self.start { | |
switch $0 { | |
case let .Next(value): | |
guard let value = deepUnwrap(value) else { | |
subscriber.sendNext(nil) | |
break | |
} | |
do { | |
subscriber.sendNext(try asAnyObject(value)) | |
} catch _ { | |
fatalError("Cannot pass Swift value into Obj-C land.") | |
} | |
case let .Failed(error): | |
if let error = error as? AnyObjectBridgeable { | |
subscriber.sendError(error.toAnyObject() as! NSError) | |
} else { | |
subscriber.sendError(error as NSError) | |
} | |
case .Interrupted, .Completed: subscriber.sendCompleted() | |
} | |
} | |
return RACDisposable { | |
disposable.dispose() | |
} | |
} | |
signal.name = String(self.dynamicType) | |
return signal | |
} | |
} | |
public protocol AnyObjectBridgeable { | |
func toAnyObject() -> AnyObject | |
} | |
extension SignalProducer: AnyObjectBridgeable { | |
public func toAnyObject() -> AnyObject { | |
return toRACSignal() | |
} | |
} | |
private func asAnyObject(any: Any) throws -> AnyObject { | |
struct Error: ErrorType { } | |
guard let any = deepUnwrap(any) else { | |
return NSNull() | |
} | |
if any is Void { | |
throw Error() | |
} | |
if let value = any as? AnyObjectBridgeable { | |
return value.toAnyObject() | |
} else if let value = any as? AnyObject { | |
return value | |
} else if let values = asTuple(any) { | |
return RACTuple(objectsFromArray: try values.map { try asAnyObject($0) }, convertNullsToNils: true) | |
} else if let values = asArray(any) { | |
return try values.map { try asAnyObject($0) } | |
} else if let values = asDictionary(any) { | |
return try values.map { (key: $0, value: try asAnyObject($1)) } | |
} | |
throw Error() | |
} | |
private func deepUnwrap(any: Any) -> Any? { | |
let mirror = Mirror(reflecting: any) | |
if mirror.displayStyle != .Optional { | |
return any | |
} | |
if let child = mirror.children.first where child.label == "Some" { | |
return deepUnwrap(child.value) | |
} | |
return nil | |
} | |
private func asDictionary(any: Any) -> [String: Any]? { | |
let mirror = Mirror(reflecting: any) | |
guard let displayStyle = mirror.displayStyle where displayStyle == .Dictionary else { | |
return nil | |
} | |
var dictionary = [String: Any]() | |
for property in Array(mirror.children) { | |
let pair = Array(Mirror(reflecting: property.value).children) | |
if let key = pair[0].value as? String { | |
dictionary[key] = pair[1].value | |
} else { | |
return nil | |
} | |
} | |
return dictionary | |
} | |
private func asArray(any: Any) -> [Any]? { | |
let mirror = Mirror(reflecting: any) | |
guard let displayStyle = mirror.displayStyle where displayStyle == .Collection || displayStyle == .Set else { | |
return nil | |
} | |
return Array(mirror.children).map { $0.value } | |
} | |
private func asTuple(any: Any) -> [Any]? { | |
let mirror = Mirror(reflecting: any) | |
guard let displayStyle = mirror.displayStyle where displayStyle == .Tuple else { | |
return nil | |
} | |
return Array(mirror.children).map { $0.value } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment