initial
This commit is contained in:
68
Pods/RxCocoa/RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift
generated
Normal file
68
Pods/RxCocoa/RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift
generated
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// KVORepresentable+CoreGraphics.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 11/14/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import RxSwift
|
||||
import CoreGraphics
|
||||
|
||||
import Foundation
|
||||
|
||||
#if arch(x86_64) || arch(arm64)
|
||||
let CGRectType = "{CGRect={CGPoint=dd}{CGSize=dd}}"
|
||||
let CGSizeType = "{CGSize=dd}"
|
||||
let CGPointType = "{CGPoint=dd}"
|
||||
#elseif arch(i386) || arch(arm) || os(watchOS)
|
||||
let CGRectType = "{CGRect={CGPoint=ff}{CGSize=ff}}"
|
||||
let CGSizeType = "{CGSize=ff}"
|
||||
let CGPointType = "{CGPoint=ff}"
|
||||
#endif
|
||||
|
||||
extension CGRect : KVORepresentable {
|
||||
public typealias KVOType = NSValue
|
||||
|
||||
/// Constructs self from `NSValue`.
|
||||
public init?(KVOValue: KVOType) {
|
||||
if strcmp(KVOValue.objCType, CGRectType) != 0 {
|
||||
return nil
|
||||
}
|
||||
var typedValue = CGRect(x: 0, y: 0, width: 0, height: 0)
|
||||
KVOValue.getValue(&typedValue)
|
||||
self = typedValue
|
||||
}
|
||||
}
|
||||
|
||||
extension CGPoint : KVORepresentable {
|
||||
public typealias KVOType = NSValue
|
||||
|
||||
/// Constructs self from `NSValue`.
|
||||
public init?(KVOValue: KVOType) {
|
||||
if strcmp(KVOValue.objCType, CGPointType) != 0 {
|
||||
return nil
|
||||
}
|
||||
var typedValue = CGPoint(x: 0, y: 0)
|
||||
KVOValue.getValue(&typedValue)
|
||||
self = typedValue
|
||||
}
|
||||
}
|
||||
|
||||
extension CGSize : KVORepresentable {
|
||||
public typealias KVOType = NSValue
|
||||
|
||||
/// Constructs self from `NSValue`.
|
||||
public init?(KVOValue: KVOType) {
|
||||
if strcmp(KVOValue.objCType, CGSizeType) != 0 {
|
||||
return nil
|
||||
}
|
||||
var typedValue = CGSize(width: 0, height: 0)
|
||||
KVOValue.getValue(&typedValue)
|
||||
self = typedValue
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
88
Pods/RxCocoa/RxCocoa/Foundation/KVORepresentable+Swift.swift
generated
Normal file
88
Pods/RxCocoa/RxCocoa/Foundation/KVORepresentable+Swift.swift
generated
Normal file
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// KVORepresentable+Swift.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 11/14/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Int : KVORepresentable {
|
||||
public typealias KVOType = NSNumber
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
public init?(KVOValue: KVOType) {
|
||||
self.init(KVOValue.int32Value)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int32 : KVORepresentable {
|
||||
public typealias KVOType = NSNumber
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
public init?(KVOValue: KVOType) {
|
||||
self.init(KVOValue.int32Value)
|
||||
}
|
||||
}
|
||||
|
||||
extension Int64 : KVORepresentable {
|
||||
public typealias KVOType = NSNumber
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
public init?(KVOValue: KVOType) {
|
||||
self.init(KVOValue.int64Value)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt : KVORepresentable {
|
||||
public typealias KVOType = NSNumber
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
public init?(KVOValue: KVOType) {
|
||||
self.init(KVOValue.uintValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt32 : KVORepresentable {
|
||||
public typealias KVOType = NSNumber
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
public init?(KVOValue: KVOType) {
|
||||
self.init(KVOValue.uint32Value)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt64 : KVORepresentable {
|
||||
public typealias KVOType = NSNumber
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
public init?(KVOValue: KVOType) {
|
||||
self.init(KVOValue.uint64Value)
|
||||
}
|
||||
}
|
||||
|
||||
extension Bool : KVORepresentable {
|
||||
public typealias KVOType = NSNumber
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
public init?(KVOValue: KVOType) {
|
||||
self.init(KVOValue.boolValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension RawRepresentable where RawValue: KVORepresentable {
|
||||
/// Constructs `Self` using optional KVO value.
|
||||
init?(KVOValue: RawValue.KVOType?) {
|
||||
guard let KVOValue = KVOValue else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let rawValue = RawValue(KVOValue: KVOValue) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.init(rawValue: rawValue)
|
||||
}
|
||||
}
|
||||
28
Pods/RxCocoa/RxCocoa/Foundation/KVORepresentable.swift
generated
Normal file
28
Pods/RxCocoa/RxCocoa/Foundation/KVORepresentable.swift
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// KVORepresentable.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 11/14/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
/// Type that is KVO representable (KVO mechanism can be used to observe it).
|
||||
public protocol KVORepresentable {
|
||||
/// Associated KVO type.
|
||||
associatedtype KVOType
|
||||
|
||||
/// Constructs `Self` using KVO value.
|
||||
init?(KVOValue: KVOType)
|
||||
}
|
||||
|
||||
extension KVORepresentable {
|
||||
/// Initializes `KVORepresentable` with optional value.
|
||||
init?(KVOValue: KVOType?) {
|
||||
guard let KVOValue = KVOValue else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.init(KVOValue: KVOValue)
|
||||
}
|
||||
}
|
||||
|
||||
60
Pods/RxCocoa/RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift
generated
Normal file
60
Pods/RxCocoa/RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// NSObject+Rx+KVORepresentable.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 11/14/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
|
||||
/// Key value observing options
|
||||
public struct KeyValueObservingOptions: OptionSet {
|
||||
/// Raw value
|
||||
public let rawValue: UInt
|
||||
|
||||
public init(rawValue: UInt) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
/// Whether a sequence element should be sent to the observer immediately, before the subscribe method even returns.
|
||||
public static let initial = KeyValueObservingOptions(rawValue: 1 << 0)
|
||||
/// Whether to send updated values.
|
||||
public static let new = KeyValueObservingOptions(rawValue: 1 << 1)
|
||||
}
|
||||
|
||||
extension Reactive where Base: NSObject {
|
||||
|
||||
/**
|
||||
Specialization of generic `observe` method.
|
||||
|
||||
This is a special overload because to observe values of some type (for example `Int`), first values of KVO type
|
||||
need to be observed (`NSNumber`), and then converted to result type.
|
||||
|
||||
For more information take a look at `observe` method.
|
||||
*/
|
||||
public func observe<Element: KVORepresentable>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial], retainSelf: Bool = true) -> Observable<Element?> {
|
||||
return self.observe(Element.KVOType.self, keyPath, options: options, retainSelf: retainSelf)
|
||||
.map(Element.init)
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_SWIZZLING && !os(Linux)
|
||||
// KVO
|
||||
extension Reactive where Base: NSObject {
|
||||
/**
|
||||
Specialization of generic `observeWeakly` method.
|
||||
|
||||
For more information take a look at `observeWeakly` method.
|
||||
*/
|
||||
public func observeWeakly<Element: KVORepresentable>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable<Element?> {
|
||||
return self.observeWeakly(Element.KVOType.self, keyPath, options: options)
|
||||
.map(Element.init)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
52
Pods/RxCocoa/RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift
generated
Normal file
52
Pods/RxCocoa/RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// NSObject+Rx+RawRepresentable.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 11/9/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import RxSwift
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Reactive where Base: NSObject {
|
||||
/**
|
||||
Specialization of generic `observe` method.
|
||||
|
||||
This specialization first observes `KVORepresentable` value and then converts it to `RawRepresentable` value.
|
||||
|
||||
It is useful for observing bridged ObjC enum values.
|
||||
|
||||
For more information take a look at `observe` method.
|
||||
*/
|
||||
public func observe<Element: RawRepresentable>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial], retainSelf: Bool = true) -> Observable<Element?> where Element.RawValue: KVORepresentable {
|
||||
return self.observe(Element.RawValue.KVOType.self, keyPath, options: options, retainSelf: retainSelf)
|
||||
.map(Element.init)
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_SWIZZLING
|
||||
|
||||
// observeWeakly + RawRepresentable
|
||||
extension Reactive where Base: NSObject {
|
||||
|
||||
/**
|
||||
Specialization of generic `observeWeakly` method.
|
||||
|
||||
This specialization first observes `KVORepresentable` value and then converts it to `RawRepresentable` value.
|
||||
|
||||
It is useful for observing bridged ObjC enum values.
|
||||
|
||||
For more information take a look at `observeWeakly` method.
|
||||
*/
|
||||
public func observeWeakly<Element: RawRepresentable>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable<Element?> where Element.RawValue: KVORepresentable {
|
||||
return self.observeWeakly(Element.RawValue.KVOType.self, keyPath, options: options)
|
||||
.map(Element.init)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
569
Pods/RxCocoa/RxCocoa/Foundation/NSObject+Rx.swift
generated
Normal file
569
Pods/RxCocoa/RxCocoa/Foundation/NSObject+Rx.swift
generated
Normal file
@@ -0,0 +1,569 @@
|
||||
//
|
||||
// NSObject+Rx.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 2/21/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
#if SWIFT_PACKAGE && !DISABLE_SWIZZLING && !os(Linux)
|
||||
import RxCocoaRuntime
|
||||
#endif
|
||||
|
||||
#if !DISABLE_SWIZZLING && !os(Linux)
|
||||
private var deallocatingSubjectTriggerContext: UInt8 = 0
|
||||
private var deallocatingSubjectContext: UInt8 = 0
|
||||
#endif
|
||||
private var deallocatedSubjectTriggerContext: UInt8 = 0
|
||||
private var deallocatedSubjectContext: UInt8 = 0
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
/**
|
||||
KVO is a tricky mechanism.
|
||||
|
||||
When observing child in a ownership hierarchy, usually retaining observing target is wanted behavior.
|
||||
When observing parent in a ownership hierarchy, usually retaining target isn't wanter behavior.
|
||||
|
||||
KVO with weak references is especially tricky. For it to work, some kind of swizzling is required.
|
||||
That can be done by
|
||||
* replacing object class dynamically (like KVO does)
|
||||
* by swizzling `dealloc` method on all instances for a class.
|
||||
* some third method ...
|
||||
|
||||
Both approaches can fail in certain scenarios:
|
||||
* problems arise when swizzlers return original object class (like KVO does when nobody is observing)
|
||||
* Problems can arise because replacing dealloc method isn't atomic operation (get implementation,
|
||||
set implementation).
|
||||
|
||||
Second approach is chosen. It can fail in case there are multiple libraries dynamically trying
|
||||
to replace dealloc method. In case that isn't the case, it should be ok.
|
||||
*/
|
||||
extension Reactive where Base: NSObject {
|
||||
|
||||
|
||||
/**
|
||||
Observes values on `keyPath` starting from `self` with `options` and retains `self` if `retainSelf` is set.
|
||||
|
||||
`observe` is just a simple and performant wrapper around KVO mechanism.
|
||||
|
||||
* it can be used to observe paths starting from `self` or from ancestors in ownership graph (`retainSelf = false`)
|
||||
* it can be used to observe paths starting from descendants in ownership graph (`retainSelf = true`)
|
||||
* the paths have to consist only of `strong` properties, otherwise you are risking crashing the system by not unregistering KVO observer before dealloc.
|
||||
|
||||
If support for weak properties is needed or observing arbitrary or unknown relationships in the
|
||||
ownership tree, `observeWeakly` is the preferred option.
|
||||
- parameter type: Optional type hint of the observed sequence elements.
|
||||
- parameter keyPath: Key path of property names to observe.
|
||||
- parameter options: KVO mechanism notification options.
|
||||
- parameter retainSelf: Retains self during observation if set `true`.
|
||||
- returns: Observable sequence of objects on `keyPath`.
|
||||
*/
|
||||
public func observe<Element>(_ type: Element.Type,
|
||||
_ keyPath: String,
|
||||
options: KeyValueObservingOptions = [.new, .initial],
|
||||
retainSelf: Bool = true) -> Observable<Element?> {
|
||||
KVOObservable(object: self.base, keyPath: keyPath, options: options, retainTarget: retainSelf).asObservable()
|
||||
}
|
||||
|
||||
/**
|
||||
Observes values at the provided key path using the provided options.
|
||||
|
||||
- parameter keyPath: A key path between the object and one of its properties.
|
||||
- parameter options: Key-value observation options, defaults to `.new` and `.initial`.
|
||||
|
||||
- note: When the object is deallocated, a completion event is emitted.
|
||||
|
||||
- returns: An observable emitting value changes at the provided key path.
|
||||
*/
|
||||
public func observe<Element>(_ keyPath: KeyPath<Base, Element>,
|
||||
options: NSKeyValueObservingOptions = [.new, .initial]) -> Observable<Element> {
|
||||
Observable<Element>.create { [weak base] observer in
|
||||
let observation = base?.observe(keyPath, options: options) { obj, _ in
|
||||
observer.on(.next(obj[keyPath: keyPath]))
|
||||
}
|
||||
|
||||
return Disposables.create { observation?.invalidate() }
|
||||
}
|
||||
.take(until: base.rx.deallocated)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !DISABLE_SWIZZLING && !os(Linux)
|
||||
// KVO
|
||||
extension Reactive where Base: NSObject {
|
||||
/**
|
||||
Observes values on `keyPath` starting from `self` with `options` and doesn't retain `self`.
|
||||
|
||||
It can be used in all cases where `observe` can be used and additionally
|
||||
|
||||
* because it won't retain observed target, it can be used to observe arbitrary object graph whose ownership relation is unknown
|
||||
* it can be used to observe `weak` properties
|
||||
|
||||
**Since it needs to intercept object deallocation process it needs to perform swizzling of `dealloc` method on observed object.**
|
||||
- parameter type: Optional type hint of the observed sequence elements.
|
||||
- parameter keyPath: Key path of property names to observe.
|
||||
- parameter options: KVO mechanism notification options.
|
||||
- returns: Observable sequence of objects on `keyPath`.
|
||||
*/
|
||||
public func observeWeakly<Element>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable<Element?> {
|
||||
return observeWeaklyKeyPathFor(self.base, keyPath: keyPath, options: options)
|
||||
.map { n in
|
||||
return n as? Element
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Dealloc
|
||||
extension Reactive where Base: AnyObject {
|
||||
|
||||
/**
|
||||
Observable sequence of object deallocated events.
|
||||
|
||||
After object is deallocated one `()` element will be produced and sequence will immediately complete.
|
||||
|
||||
- returns: Observable sequence of object deallocated events.
|
||||
*/
|
||||
public var deallocated: Observable<Void> {
|
||||
return self.synchronized {
|
||||
if let deallocObservable = objc_getAssociatedObject(self.base, &deallocatedSubjectContext) as? DeallocObservable {
|
||||
return deallocObservable.subject
|
||||
}
|
||||
|
||||
let deallocObservable = DeallocObservable()
|
||||
|
||||
objc_setAssociatedObject(self.base, &deallocatedSubjectContext, deallocObservable, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
return deallocObservable.subject
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_SWIZZLING && !os(Linux)
|
||||
|
||||
/**
|
||||
Observable sequence of message arguments that completes when object is deallocated.
|
||||
|
||||
Each element is produced before message is invoked on target object. `methodInvoked`
|
||||
exists in case observing of invoked messages is needed.
|
||||
|
||||
In case an error occurs sequence will fail with `RxCocoaObjCRuntimeError`.
|
||||
|
||||
In case some argument is `nil`, instance of `NSNull()` will be sent.
|
||||
|
||||
- returns: Observable sequence of arguments passed to `selector` method.
|
||||
*/
|
||||
public func sentMessage(_ selector: Selector) -> Observable<[Any]> {
|
||||
return self.synchronized {
|
||||
// in case of dealloc selector replay subject behavior needs to be used
|
||||
if selector == deallocSelector {
|
||||
return self.deallocating.map { _ in [] }
|
||||
}
|
||||
|
||||
do {
|
||||
let proxy: MessageSentProxy = try self.registerMessageInterceptor(selector)
|
||||
return proxy.messageSent.asObservable()
|
||||
}
|
||||
catch let e {
|
||||
return Observable.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Observable sequence of message arguments that completes when object is deallocated.
|
||||
|
||||
Each element is produced after message is invoked on target object. `sentMessage`
|
||||
exists in case interception of sent messages before they were invoked is needed.
|
||||
|
||||
In case an error occurs sequence will fail with `RxCocoaObjCRuntimeError`.
|
||||
|
||||
In case some argument is `nil`, instance of `NSNull()` will be sent.
|
||||
|
||||
- returns: Observable sequence of arguments passed to `selector` method.
|
||||
*/
|
||||
public func methodInvoked(_ selector: Selector) -> Observable<[Any]> {
|
||||
return self.synchronized {
|
||||
// in case of dealloc selector replay subject behavior needs to be used
|
||||
if selector == deallocSelector {
|
||||
return self.deallocated.map { _ in [] }
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
let proxy: MessageSentProxy = try self.registerMessageInterceptor(selector)
|
||||
return proxy.methodInvoked.asObservable()
|
||||
}
|
||||
catch let e {
|
||||
return Observable.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Observable sequence of object deallocating events.
|
||||
|
||||
When `dealloc` message is sent to `self` one `()` element will be produced and after object is deallocated sequence
|
||||
will immediately complete.
|
||||
|
||||
In case an error occurs sequence will fail with `RxCocoaObjCRuntimeError`.
|
||||
|
||||
- returns: Observable sequence of object deallocating events.
|
||||
*/
|
||||
public var deallocating: Observable<()> {
|
||||
return self.synchronized {
|
||||
do {
|
||||
let proxy: DeallocatingProxy = try self.registerMessageInterceptor(deallocSelector)
|
||||
return proxy.messageSent.asObservable()
|
||||
}
|
||||
catch let e {
|
||||
return Observable.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func registerMessageInterceptor<T: MessageInterceptorSubject>(_ selector: Selector) throws -> T {
|
||||
let rxSelector = RX_selector(selector)
|
||||
let selectorReference = RX_reference_from_selector(rxSelector)
|
||||
|
||||
let subject: T
|
||||
if let existingSubject = objc_getAssociatedObject(self.base, selectorReference) as? T {
|
||||
subject = existingSubject
|
||||
}
|
||||
else {
|
||||
subject = T()
|
||||
objc_setAssociatedObject(
|
||||
self.base,
|
||||
selectorReference,
|
||||
subject,
|
||||
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
||||
)
|
||||
}
|
||||
|
||||
if subject.isActive {
|
||||
return subject
|
||||
}
|
||||
|
||||
var error: NSError?
|
||||
let targetImplementation = RX_ensure_observing(self.base, selector, &error)
|
||||
if targetImplementation == nil {
|
||||
throw error?.rxCocoaErrorForTarget(self.base) ?? RxCocoaError.unknown
|
||||
}
|
||||
|
||||
subject.targetImplementation = targetImplementation!
|
||||
|
||||
return subject
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: Message interceptors
|
||||
|
||||
#if !DISABLE_SWIZZLING && !os(Linux)
|
||||
|
||||
private protocol MessageInterceptorSubject: AnyObject {
|
||||
init()
|
||||
|
||||
var isActive: Bool {
|
||||
get
|
||||
}
|
||||
|
||||
var targetImplementation: IMP { get set }
|
||||
}
|
||||
|
||||
private final class DeallocatingProxy
|
||||
: MessageInterceptorSubject
|
||||
, RXDeallocatingObserver {
|
||||
typealias Element = ()
|
||||
|
||||
let messageSent = ReplaySubject<()>.create(bufferSize: 1)
|
||||
|
||||
@objc var targetImplementation: IMP = RX_default_target_implementation()
|
||||
|
||||
var isActive: Bool {
|
||||
return self.targetImplementation != RX_default_target_implementation()
|
||||
}
|
||||
|
||||
init() {
|
||||
}
|
||||
|
||||
@objc func deallocating() {
|
||||
self.messageSent.on(.next(()))
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.messageSent.on(.completed)
|
||||
}
|
||||
}
|
||||
|
||||
private final class MessageSentProxy
|
||||
: MessageInterceptorSubject
|
||||
, RXMessageSentObserver {
|
||||
typealias Element = [AnyObject]
|
||||
|
||||
let messageSent = PublishSubject<[Any]>()
|
||||
let methodInvoked = PublishSubject<[Any]>()
|
||||
|
||||
@objc var targetImplementation: IMP = RX_default_target_implementation()
|
||||
|
||||
var isActive: Bool {
|
||||
return self.targetImplementation != RX_default_target_implementation()
|
||||
}
|
||||
|
||||
init() {
|
||||
}
|
||||
|
||||
@objc func messageSent(withArguments arguments: [Any]) {
|
||||
self.messageSent.on(.next(arguments))
|
||||
}
|
||||
|
||||
@objc func methodInvoked(withArguments arguments: [Any]) {
|
||||
self.methodInvoked.on(.next(arguments))
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.messageSent.on(.completed)
|
||||
self.methodInvoked.on(.completed)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
private final class DeallocObservable {
|
||||
let subject = ReplaySubject<Void>.create(bufferSize:1)
|
||||
|
||||
init() {
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.subject.on(.next(()))
|
||||
self.subject.on(.completed)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: KVO
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
private protocol KVOObservableProtocol {
|
||||
var target: AnyObject { get }
|
||||
var keyPath: String { get }
|
||||
var retainTarget: Bool { get }
|
||||
var options: KeyValueObservingOptions { get }
|
||||
}
|
||||
|
||||
private final class KVOObserver
|
||||
: _RXKVOObserver
|
||||
, Disposable {
|
||||
typealias Callback = (Any?) -> Void
|
||||
|
||||
var retainSelf: KVOObserver?
|
||||
|
||||
init(parent: KVOObservableProtocol, callback: @escaping Callback) {
|
||||
#if TRACE_RESOURCES
|
||||
_ = Resources.incrementTotal()
|
||||
#endif
|
||||
|
||||
super.init(target: parent.target, retainTarget: parent.retainTarget, keyPath: parent.keyPath, options: parent.options.nsOptions, callback: callback)
|
||||
self.retainSelf = self
|
||||
}
|
||||
|
||||
override func dispose() {
|
||||
super.dispose()
|
||||
self.retainSelf = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
#if TRACE_RESOURCES
|
||||
_ = Resources.decrementTotal()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private final class KVOObservable<Element>
|
||||
: ObservableType
|
||||
, KVOObservableProtocol {
|
||||
typealias Element = Element?
|
||||
|
||||
unowned var target: AnyObject
|
||||
var strongTarget: AnyObject?
|
||||
|
||||
var keyPath: String
|
||||
var options: KeyValueObservingOptions
|
||||
var retainTarget: Bool
|
||||
|
||||
init(object: AnyObject, keyPath: String, options: KeyValueObservingOptions, retainTarget: Bool) {
|
||||
self.target = object
|
||||
self.keyPath = keyPath
|
||||
self.options = options
|
||||
self.retainTarget = retainTarget
|
||||
if retainTarget {
|
||||
self.strongTarget = object
|
||||
}
|
||||
}
|
||||
|
||||
func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element? {
|
||||
let observer = KVOObserver(parent: self) { value in
|
||||
if value as? NSNull != nil {
|
||||
observer.on(.next(nil))
|
||||
return
|
||||
}
|
||||
observer.on(.next(value as? Element))
|
||||
}
|
||||
|
||||
return Disposables.create(with: observer.dispose)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension KeyValueObservingOptions {
|
||||
var nsOptions: NSKeyValueObservingOptions {
|
||||
var result: UInt = 0
|
||||
if self.contains(.new) {
|
||||
result |= NSKeyValueObservingOptions.new.rawValue
|
||||
}
|
||||
if self.contains(.initial) {
|
||||
result |= NSKeyValueObservingOptions.initial.rawValue
|
||||
}
|
||||
|
||||
return NSKeyValueObservingOptions(rawValue: result)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !DISABLE_SWIZZLING && !os(Linux)
|
||||
|
||||
private func observeWeaklyKeyPathFor(_ target: NSObject, keyPath: String, options: KeyValueObservingOptions) -> Observable<AnyObject?> {
|
||||
let components = keyPath.components(separatedBy: ".").filter { $0 != "self" }
|
||||
|
||||
let observable = observeWeaklyKeyPathFor(target, keyPathSections: components, options: options)
|
||||
.finishWithNilWhenDealloc(target)
|
||||
|
||||
if !options.isDisjoint(with: .initial) {
|
||||
return observable
|
||||
}
|
||||
else {
|
||||
return observable
|
||||
.skip(1)
|
||||
}
|
||||
}
|
||||
|
||||
// This should work correctly
|
||||
// Identifiers can't contain `,`, so the only place where `,` can appear
|
||||
// is as a delimiter.
|
||||
// This means there is `W` as element in an array of property attributes.
|
||||
private func isWeakProperty(_ properyRuntimeInfo: String) -> Bool {
|
||||
properyRuntimeInfo.range(of: ",W,") != nil
|
||||
}
|
||||
|
||||
private extension ObservableType where Element == AnyObject? {
|
||||
func finishWithNilWhenDealloc(_ target: NSObject)
|
||||
-> Observable<AnyObject?> {
|
||||
let deallocating = target.rx.deallocating
|
||||
|
||||
return deallocating
|
||||
.map { _ in
|
||||
return Observable.just(nil)
|
||||
}
|
||||
.startWith(self.asObservable())
|
||||
.switchLatest()
|
||||
}
|
||||
}
|
||||
|
||||
private func observeWeaklyKeyPathFor(
|
||||
_ target: NSObject,
|
||||
keyPathSections: [String],
|
||||
options: KeyValueObservingOptions
|
||||
) -> Observable<AnyObject?> {
|
||||
|
||||
weak var weakTarget: AnyObject? = target
|
||||
|
||||
let propertyName = keyPathSections[0]
|
||||
let remainingPaths = Array(keyPathSections[1..<keyPathSections.count])
|
||||
|
||||
let property = class_getProperty(object_getClass(target), propertyName)
|
||||
if property == nil {
|
||||
return Observable.error(RxCocoaError.invalidPropertyName(object: target, propertyName: propertyName))
|
||||
}
|
||||
let propertyAttributes = property_getAttributes(property!)
|
||||
|
||||
// should dealloc hook be in place if week property, or just create strong reference because it doesn't matter
|
||||
let isWeak = isWeakProperty(propertyAttributes.map(String.init) ?? "")
|
||||
let propertyObservable = KVOObservable(object: target, keyPath: propertyName, options: options.union(.initial), retainTarget: false) as KVOObservable<AnyObject>
|
||||
|
||||
// KVO recursion for value changes
|
||||
return propertyObservable
|
||||
.flatMapLatest { (nextTarget: AnyObject?) -> Observable<AnyObject?> in
|
||||
if nextTarget == nil {
|
||||
return Observable.just(nil)
|
||||
}
|
||||
let nextObject = nextTarget! as? NSObject
|
||||
|
||||
let strongTarget: AnyObject? = weakTarget
|
||||
|
||||
if nextObject == nil {
|
||||
return Observable.error(RxCocoaError.invalidObjectOnKeyPath(object: nextTarget!, sourceObject: strongTarget ?? NSNull(), propertyName: propertyName))
|
||||
}
|
||||
|
||||
// if target is alive, then send change
|
||||
// if it's deallocated, don't send anything
|
||||
if strongTarget == nil {
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
let nextElementsObservable = keyPathSections.count == 1
|
||||
? Observable.just(nextTarget)
|
||||
: observeWeaklyKeyPathFor(nextObject!, keyPathSections: remainingPaths, options: options)
|
||||
|
||||
if isWeak {
|
||||
return nextElementsObservable
|
||||
.finishWithNilWhenDealloc(nextObject!)
|
||||
}
|
||||
else {
|
||||
return nextElementsObservable
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: Constants
|
||||
|
||||
private let deallocSelector = NSSelectorFromString("dealloc")
|
||||
|
||||
// MARK: AnyObject + Reactive
|
||||
|
||||
extension Reactive where Base: AnyObject {
|
||||
func synchronized<T>( _ action: () -> T) -> T {
|
||||
objc_sync_enter(self.base)
|
||||
let result = action()
|
||||
objc_sync_exit(self.base)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
extension Reactive where Base: AnyObject {
|
||||
/**
|
||||
Helper to make sure that `Observable` returned from `createCachedObservable` is only created once.
|
||||
This is important because there is only one `target` and `action` properties on `NSControl` or `UIBarButtonItem`.
|
||||
*/
|
||||
func lazyInstanceObservable<T: AnyObject>(_ key: UnsafeRawPointer, createCachedObservable: () -> T) -> T {
|
||||
if let value = objc_getAssociatedObject(self.base, key) {
|
||||
return value as! T
|
||||
}
|
||||
|
||||
let observable = createCachedObservable()
|
||||
|
||||
objc_setAssociatedObject(self.base, key, observable, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
|
||||
return observable
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
31
Pods/RxCocoa/RxCocoa/Foundation/NotificationCenter+Rx.swift
generated
Normal file
31
Pods/RxCocoa/RxCocoa/Foundation/NotificationCenter+Rx.swift
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// NotificationCenter+Rx.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 5/2/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
|
||||
extension Reactive where Base: NotificationCenter {
|
||||
/**
|
||||
Transforms notifications posted to notification center to observable sequence of notifications.
|
||||
|
||||
- parameter name: Optional name used to filter notifications.
|
||||
- parameter object: Optional object used to filter notifications.
|
||||
- returns: Observable sequence of posted notifications.
|
||||
*/
|
||||
public func notification(_ name: Notification.Name?, object: AnyObject? = nil) -> Observable<Notification> {
|
||||
return Observable.create { [weak object] observer in
|
||||
let nsObserver = self.base.addObserver(forName: name, object: object, queue: nil) { notification in
|
||||
observer.on(.next(notification))
|
||||
}
|
||||
|
||||
return Disposables.create {
|
||||
self.base.removeObserver(nsObserver)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
240
Pods/RxCocoa/RxCocoa/Foundation/URLSession+Rx.swift
generated
Normal file
240
Pods/RxCocoa/RxCocoa/Foundation/URLSession+Rx.swift
generated
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// URLSession+Rx.swift
|
||||
// RxCocoa
|
||||
//
|
||||
// Created by Krunoslav Zaher on 3/23/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
|
||||
#if canImport(FoundationNetworking)
|
||||
import FoundationNetworking
|
||||
#endif
|
||||
|
||||
/// RxCocoa URL errors.
|
||||
public enum RxCocoaURLError
|
||||
: Swift.Error {
|
||||
/// Unknown error occurred.
|
||||
case unknown
|
||||
/// Response is not NSHTTPURLResponse
|
||||
case nonHTTPResponse(response: URLResponse)
|
||||
/// Response is not successful. (not in `200 ..< 300` range)
|
||||
case httpRequestFailed(response: HTTPURLResponse, data: Data?)
|
||||
/// Deserialization error.
|
||||
case deserializationError(error: Swift.Error)
|
||||
}
|
||||
|
||||
extension RxCocoaURLError
|
||||
: CustomDebugStringConvertible {
|
||||
/// A textual representation of `self`, suitable for debugging.
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case .unknown:
|
||||
return "Unknown error has occurred."
|
||||
case let .nonHTTPResponse(response):
|
||||
return "Response is not NSHTTPURLResponse `\(response)`."
|
||||
case let .httpRequestFailed(response, _):
|
||||
return "HTTP request failed with `\(response.statusCode)`."
|
||||
case let .deserializationError(error):
|
||||
return "Error during deserialization of the response: \(error)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func escapeTerminalString(_ value: String) -> String {
|
||||
return value.replacingOccurrences(of: "\"", with: "\\\"", options:[], range: nil)
|
||||
}
|
||||
|
||||
private func convertURLRequestToCurlCommand(_ request: URLRequest) -> String {
|
||||
let method = request.httpMethod ?? "GET"
|
||||
var returnValue = "curl -X \(method) "
|
||||
|
||||
if let httpBody = request.httpBody {
|
||||
let maybeBody = String(data: httpBody, encoding: String.Encoding.utf8)
|
||||
if let body = maybeBody {
|
||||
returnValue += "-d \"\(escapeTerminalString(body))\" "
|
||||
}
|
||||
}
|
||||
|
||||
for (key, value) in request.allHTTPHeaderFields ?? [:] {
|
||||
let escapedKey = escapeTerminalString(key as String)
|
||||
let escapedValue = escapeTerminalString(value as String)
|
||||
returnValue += "\n -H \"\(escapedKey): \(escapedValue)\" "
|
||||
}
|
||||
|
||||
let URLString = request.url?.absoluteString ?? "<unknown url>"
|
||||
|
||||
returnValue += "\n\"\(escapeTerminalString(URLString))\""
|
||||
|
||||
returnValue += " -i -v"
|
||||
|
||||
return returnValue
|
||||
}
|
||||
|
||||
private func convertResponseToString(_ response: URLResponse?, _ error: NSError?, _ interval: TimeInterval) -> String {
|
||||
let ms = Int(interval * 1000)
|
||||
|
||||
if let response = response as? HTTPURLResponse {
|
||||
if 200 ..< 300 ~= response.statusCode {
|
||||
return "Success (\(ms)ms): Status \(response.statusCode)"
|
||||
}
|
||||
else {
|
||||
return "Failure (\(ms)ms): Status \(response.statusCode)"
|
||||
}
|
||||
}
|
||||
|
||||
if let error = error {
|
||||
if error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled {
|
||||
return "Canceled (\(ms)ms)"
|
||||
}
|
||||
return "Failure (\(ms)ms): NSError > \(error)"
|
||||
}
|
||||
|
||||
return "<Unhandled response from server>"
|
||||
}
|
||||
|
||||
extension Reactive where Base: URLSession {
|
||||
/**
|
||||
Observable sequence of responses for URL request.
|
||||
|
||||
Performing of request starts after observer is subscribed and not after invoking this method.
|
||||
|
||||
**URL requests will be performed per subscribed observer.**
|
||||
|
||||
Any error during fetching of the response will cause observed sequence to terminate with error.
|
||||
|
||||
- parameter request: URL request.
|
||||
- returns: Observable sequence of URL responses.
|
||||
*/
|
||||
public func response(request: URLRequest) -> Observable<(response: HTTPURLResponse, data: Data)> {
|
||||
return Observable.create { observer in
|
||||
|
||||
// smart compiler should be able to optimize this out
|
||||
let d: Date?
|
||||
|
||||
if URLSession.rx.shouldLogRequest(request) {
|
||||
d = Date()
|
||||
}
|
||||
else {
|
||||
d = nil
|
||||
}
|
||||
|
||||
let task = self.base.dataTask(with: request) { data, response, error in
|
||||
|
||||
if URLSession.rx.shouldLogRequest(request) {
|
||||
let interval = Date().timeIntervalSince(d ?? Date())
|
||||
print(convertURLRequestToCurlCommand(request))
|
||||
#if os(Linux)
|
||||
print(convertResponseToString(response, error.flatMap { $0 as NSError }, interval))
|
||||
#else
|
||||
print(convertResponseToString(response, error.map { $0 as NSError }, interval))
|
||||
#endif
|
||||
}
|
||||
|
||||
guard let response = response, let data = data else {
|
||||
observer.on(.error(error ?? RxCocoaURLError.unknown))
|
||||
return
|
||||
}
|
||||
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
observer.on(.error(RxCocoaURLError.nonHTTPResponse(response: response)))
|
||||
return
|
||||
}
|
||||
|
||||
observer.on(.next((httpResponse, data)))
|
||||
observer.on(.completed)
|
||||
}
|
||||
|
||||
task.resume()
|
||||
|
||||
return Disposables.create(with: task.cancel)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Observable sequence of response data for URL request.
|
||||
|
||||
Performing of request starts after observer is subscribed and not after invoking this method.
|
||||
|
||||
**URL requests will be performed per subscribed observer.**
|
||||
|
||||
Any error during fetching of the response will cause observed sequence to terminate with error.
|
||||
|
||||
If response is not HTTP response with status code in the range of `200 ..< 300`, sequence
|
||||
will terminate with `(RxCocoaErrorDomain, RxCocoaError.NetworkError)`.
|
||||
|
||||
- parameter request: URL request.
|
||||
- returns: Observable sequence of response data.
|
||||
*/
|
||||
public func data(request: URLRequest) -> Observable<Data> {
|
||||
return self.response(request: request).map { pair -> Data in
|
||||
if 200 ..< 300 ~= pair.0.statusCode {
|
||||
return pair.1
|
||||
}
|
||||
else {
|
||||
throw RxCocoaURLError.httpRequestFailed(response: pair.0, data: pair.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Observable sequence of response JSON for URL request.
|
||||
|
||||
Performing of request starts after observer is subscribed and not after invoking this method.
|
||||
|
||||
**URL requests will be performed per subscribed observer.**
|
||||
|
||||
Any error during fetching of the response will cause observed sequence to terminate with error.
|
||||
|
||||
If response is not HTTP response with status code in the range of `200 ..< 300`, sequence
|
||||
will terminate with `(RxCocoaErrorDomain, RxCocoaError.NetworkError)`.
|
||||
|
||||
If there is an error during JSON deserialization observable sequence will fail with that error.
|
||||
|
||||
- parameter request: URL request.
|
||||
- returns: Observable sequence of response JSON.
|
||||
*/
|
||||
public func json(request: URLRequest, options: JSONSerialization.ReadingOptions = []) -> Observable<Any> {
|
||||
return self.data(request: request).map { data -> Any in
|
||||
do {
|
||||
return try JSONSerialization.jsonObject(with: data, options: options)
|
||||
} catch let error {
|
||||
throw RxCocoaURLError.deserializationError(error: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Observable sequence of response JSON for GET request with `URL`.
|
||||
|
||||
Performing of request starts after observer is subscribed and not after invoking this method.
|
||||
|
||||
**URL requests will be performed per subscribed observer.**
|
||||
|
||||
Any error during fetching of the response will cause observed sequence to terminate with error.
|
||||
|
||||
If response is not HTTP response with status code in the range of `200 ..< 300`, sequence
|
||||
will terminate with `(RxCocoaErrorDomain, RxCocoaError.NetworkError)`.
|
||||
|
||||
If there is an error during JSON deserialization observable sequence will fail with that error.
|
||||
|
||||
- parameter url: URL of `NSURLRequest` request.
|
||||
- returns: Observable sequence of response JSON.
|
||||
*/
|
||||
public func json(url: Foundation.URL) -> Observable<Any> {
|
||||
self.json(request: URLRequest(url: url))
|
||||
}
|
||||
}
|
||||
|
||||
extension Reactive where Base == URLSession {
|
||||
/// Log URL requests to standard output in curl format.
|
||||
public static var shouldLogRequest: (URLRequest) -> Bool = { _ in
|
||||
#if DEBUG
|
||||
return true
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user