| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- //
- // FoundationExtensions.swift
- // ReactiveSwift
- //
- // Created by Justin Spahr-Summers on 2014-10-19.
- // Copyright (c) 2014 GitHub. All rights reserved.
- //
- import Foundation
- import Dispatch
- import enum Result.NoError
- import struct Result.AnyError
- #if os(Linux)
- import let CDispatch.NSEC_PER_USEC
- import let CDispatch.NSEC_PER_SEC
- #endif
- extension NotificationCenter: ReactiveExtensionsProvider {}
- extension Reactive where Base: NotificationCenter {
- /// Returns a Signal to observe posting of the specified notification.
- ///
- /// - parameters:
- /// - name: name of the notification to observe
- /// - object: an instance which sends the notifications
- ///
- /// - returns: A Signal of notifications posted that match the given criteria.
- ///
- /// - note: The signal does not terminate naturally. Observers must be
- /// explicitly disposed to avoid leaks.
- public func notifications(forName name: Notification.Name?, object: AnyObject? = nil) -> Signal<Notification, NoError> {
- return Signal { [base = self.base] observer in
- let notificationObserver = base.addObserver(forName: name, object: object, queue: nil) { notification in
- observer.send(value: notification)
- }
- return ActionDisposable {
- base.removeObserver(notificationObserver)
- }
- }
- }
- }
- private let defaultSessionError = NSError(domain: "org.reactivecocoa.ReactiveSwift.Reactivity.URLSession.dataWithRequest",
- code: 1,
- userInfo: nil)
- extension URLSession: ReactiveExtensionsProvider {}
- extension Reactive where Base: URLSession {
- /// Returns a SignalProducer which performs the work associated with an
- /// `NSURLSession`
- ///
- /// - parameters:
- /// - request: A request that will be performed when the producer is
- /// started
- ///
- /// - returns: A producer that will execute the given request once for each
- /// invocation of `start()`.
- ///
- /// - note: This method will not send an error event in the case of a server
- /// side error (i.e. when a response with status code other than
- /// 200...299 is received).
- public func data(with request: URLRequest) -> SignalProducer<(Data, URLResponse), AnyError> {
- return SignalProducer { [base = self.base] observer, disposable in
- let task = base.dataTask(with: request) { data, response, error in
- if let data = data, let response = response {
- observer.send(value: (data, response))
- observer.sendCompleted()
- } else {
- observer.send(error: AnyError(error ?? defaultSessionError))
- }
- }
- disposable += {
- task.cancel()
- }
- task.resume()
- }
- }
- }
- extension Date {
- internal func addingTimeInterval(_ interval: DispatchTimeInterval) -> Date {
- return addingTimeInterval(interval.timeInterval)
- }
- }
- extension DispatchTimeInterval {
- internal var timeInterval: TimeInterval {
- switch self {
- case let .seconds(s):
- return TimeInterval(s)
- case let .milliseconds(ms):
- return TimeInterval(TimeInterval(ms) / 1000.0)
- case let .microseconds(us):
- return TimeInterval( UInt64(us) * NSEC_PER_USEC ) / TimeInterval(NSEC_PER_SEC)
- case let .nanoseconds(ns):
- return TimeInterval(ns) / TimeInterval(NSEC_PER_SEC)
- }
- }
- // This was added purely so that our test scheduler to "go backwards" in
- // time. See `TestScheduler.rewind(by interval: DispatchTimeInterval)`.
- internal static prefix func -(lhs: DispatchTimeInterval) -> DispatchTimeInterval {
- switch lhs {
- case let .seconds(s):
- return .seconds(-s)
- case let .milliseconds(ms):
- return .milliseconds(-ms)
- case let .microseconds(us):
- return .microseconds(-us)
- case let .nanoseconds(ns):
- return .nanoseconds(-ns)
- }
- }
- /// Scales a time interval by the given scalar specified in `rhs`.
- ///
- /// - note: This method is only used internally to "scale down" a time
- /// interval. Specifically it's used only to scale intervals to 10%
- /// of their original value for the default `leeway` parameter in
- /// `SchedulerProtocol.schedule(after:action:)` schedule and similar
- /// other methods.
- ///
- /// If seconds is over 200,000, 10% is ~2,000, and hence we end up
- /// with a value of ~2,000,000,000. Not quite overflowing a signed
- /// integer on 32-bit platforms, but close.
- ///
- /// Even still, 200,000 seconds should be a rarely (if ever)
- /// specified interval for our APIs. And even then, folks should be
- /// smart and specify their own `leeway` parameter.
- ///
- /// - returns: Scaled interval in microseconds
- internal static func *(lhs: DispatchTimeInterval, rhs: Double) -> DispatchTimeInterval {
- let seconds = lhs.timeInterval * rhs
- return .microseconds(Int(seconds * 1000 * 1000))
- }
- }
|