Skip to content

Instantly share code, notes, and snippets.

@mhuusko5
Created November 17, 2015 12:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mhuusko5/55471ea8b061475122ef to your computer and use it in GitHub Desktop.
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
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