You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
4.7 KiB
155 lines
4.7 KiB
//
|
|
// RxCocoa.swift
|
|
// RxCocoa
|
|
//
|
|
// Created by Krunoslav Zaher on 2/21/15.
|
|
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
// Importing RxCocoa also imports RxRelay
|
|
@_exported import RxRelay
|
|
|
|
import RxSwift
|
|
#if os(iOS)
|
|
import UIKit
|
|
#endif
|
|
|
|
/// RxCocoa errors.
|
|
public enum RxCocoaError
|
|
: Swift.Error
|
|
, CustomDebugStringConvertible {
|
|
/// Unknown error has occurred.
|
|
case unknown
|
|
/// Invalid operation was attempted.
|
|
case invalidOperation(object: Any)
|
|
/// Items are not yet bound to user interface but have been requested.
|
|
case itemsNotYetBound(object: Any)
|
|
/// Invalid KVO Path.
|
|
case invalidPropertyName(object: Any, propertyName: String)
|
|
/// Invalid object on key path.
|
|
case invalidObjectOnKeyPath(object: Any, sourceObject: AnyObject, propertyName: String)
|
|
/// Error during swizzling.
|
|
case errorDuringSwizzling
|
|
/// Casting error.
|
|
case castingError(object: Any, targetType: Any.Type)
|
|
}
|
|
|
|
|
|
// MARK: Debug descriptions
|
|
|
|
extension RxCocoaError {
|
|
/// A textual representation of `self`, suitable for debugging.
|
|
public var debugDescription: String {
|
|
switch self {
|
|
case .unknown:
|
|
return "Unknown error occurred."
|
|
case let .invalidOperation(object):
|
|
return "Invalid operation was attempted on `\(object)`."
|
|
case let .itemsNotYetBound(object):
|
|
return "Data source is set, but items are not yet bound to user interface for `\(object)`."
|
|
case let .invalidPropertyName(object, propertyName):
|
|
return "Object `\(object)` doesn't have a property named `\(propertyName)`."
|
|
case let .invalidObjectOnKeyPath(object, sourceObject, propertyName):
|
|
return "Unobservable object `\(object)` was observed as `\(propertyName)` of `\(sourceObject)`."
|
|
case .errorDuringSwizzling:
|
|
return "Error during swizzling."
|
|
case let .castingError(object, targetType):
|
|
return "Error casting `\(object)` to `\(targetType)`"
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// MARK: Error binding policies
|
|
|
|
func bindingError(_ error: Swift.Error) {
|
|
let error = "Binding error: \(error)"
|
|
#if DEBUG
|
|
rxFatalError(error)
|
|
#else
|
|
print(error)
|
|
#endif
|
|
}
|
|
|
|
/// Swift does not implement abstract methods. This method is used as a runtime check to ensure that methods which intended to be abstract (i.e., they should be implemented in subclasses) are not called directly on the superclass.
|
|
func rxAbstractMethod(message: String = "Abstract method", file: StaticString = #file, line: UInt = #line) -> Swift.Never {
|
|
rxFatalError(message, file: file, line: line)
|
|
}
|
|
|
|
func rxFatalError(_ lastMessage: @autoclosure () -> String, file: StaticString = #file, line: UInt = #line) -> Swift.Never {
|
|
// The temptation to comment this line is great, but please don't, it's for your own good. The choice is yours.
|
|
fatalError(lastMessage(), file: file, line: line)
|
|
}
|
|
|
|
func rxFatalErrorInDebug(_ lastMessage: @autoclosure () -> String, file: StaticString = #file, line: UInt = #line) {
|
|
#if DEBUG
|
|
fatalError(lastMessage(), file: file, line: line)
|
|
#else
|
|
print("\(file):\(line): \(lastMessage())")
|
|
#endif
|
|
}
|
|
|
|
// MARK: casts or fatal error
|
|
|
|
// workaround for Swift compiler bug, cheers compiler team :)
|
|
func castOptionalOrFatalError<T>(_ value: Any?) -> T? {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
let v: T = castOrFatalError(value)
|
|
return v
|
|
}
|
|
|
|
func castOrThrow<T>(_ resultType: T.Type, _ object: Any) throws -> T {
|
|
guard let returnValue = object as? T else {
|
|
throw RxCocoaError.castingError(object: object, targetType: resultType)
|
|
}
|
|
|
|
return returnValue
|
|
}
|
|
|
|
func castOptionalOrThrow<T>(_ resultType: T.Type, _ object: AnyObject) throws -> T? {
|
|
if NSNull().isEqual(object) {
|
|
return nil
|
|
}
|
|
|
|
guard let returnValue = object as? T else {
|
|
throw RxCocoaError.castingError(object: object, targetType: resultType)
|
|
}
|
|
|
|
return returnValue
|
|
}
|
|
|
|
func castOrFatalError<T>(_ value: AnyObject!, message: String) -> T {
|
|
let maybeResult: T? = value as? T
|
|
guard let result = maybeResult else {
|
|
rxFatalError(message)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func castOrFatalError<T>(_ value: Any!) -> T {
|
|
let maybeResult: T? = value as? T
|
|
guard let result = maybeResult else {
|
|
rxFatalError("Failure converting from \(String(describing: value)) to \(T.self)")
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// MARK: Error messages
|
|
|
|
let dataSourceNotSet = "DataSource not set"
|
|
let delegateNotSet = "Delegate not set"
|
|
|
|
// MARK: Shared with RxSwift
|
|
|
|
func rxFatalError(_ lastMessage: String) -> Never {
|
|
// The temptation to comment this line is great, but please don't, it's for your own good. The choice is yours.
|
|
fatalError(lastMessage)
|
|
}
|
|
|