artman / signals Goto Github PK
View Code? Open in Web Editor NEWA micro-library for creating and observing events.
License: MIT License
A micro-library for creating and observing events.
License: MIT License
I am currently passing a signal-emitting class using Dependency Injection to one of my view controllers. This class is being instantiated in AppDelegate and then injected to view controllers where appropriate.
I am currently subscribing to the signal in viewDidLoad
of my view controller using:
unowned var unownedSelf = self
globalModelsCoordinator.onLinkedIdentityDeletedSignal.subscribe(on: unownedSelf) {
(deletedIdentity) in
self.didReceiveLinkedIdentityDeletedSignal(identity: deletedIdentity)
}
However when the view controller is about dismissed, I am not getting any logs out of deinit
. Seems the issue is the subscription on globalModelsCoordinator
.
Any ways to mitigate this? Canceling on viewWillDissapear()
or something is not an option since other view controllers along the stack might create events that will trigger signals my initial vc needs to be aware of.
Thanks!
Would it be useful to have a ListenPastOnce function as well? I'm currently using Signals for creating some data in a remote backend and listening for the return message, but that message might have been received before the create()
function returns (slim chance, but chance nonetheless). However, I definitely want the trigger to occur only once.
I could code this and submit a PR, but maybe you've got different ideas so I thought I'd check before coding.
In a Signals-heavy application, old retained data can consume a lot of memory and extend the lifecycle of fired objects implicitly. Retaining data should be opt-in.
It looks like 6.0.0 was completed and tagged, but never released through CocoaPods. Could we please get that pushed so we can use it? Thanks in advance!
Hiya!
Love this lib. I have it as a dependency for a few of my own libs.
Wanting to add support for the Swift Package Manager and discovered that you need to push a new tag to this repo to mark where the Package.swift file becomes available (it came in post 4.0.0 tag).
Can you tag the latest as 4.0.1 or something?
Thanks!
Is it possible review my PR #38 ?
How do one able to use NotificationCenter with Signals?
For example observing UIApplicationWillResignActiveNotification
.
@artman, would you be supportive of adding a readOnly
Signal? When exposing a Signal
from a subsystem, it is difficult to reason about who might be calling fire
on a given Signal
because the fire
method is public
. It would be desirable for certain systems to expose a readonly
Signal to better enforce when a Signal
may be fired.
Two ideas on how to accomplish this:
Option 1: Create a new ReadOnlySignalBox
which hides the fire
able Signal internally.
class ReadOnlySignalBox<T> {
public typealias SignalCallback = (T) -> Void
// MARK: - Private Properties
private let boxedSignal: Signals.Signal<T>
init(boxedSignal: Signals.Signal<T>) {
self.boxedSignal = boxedSignal
}
// MARK: - Public API
func subscribe(on observer: AnyObject, callback: @escaping Signals.Signal<T>.SignalCallback) -> Signals.SignalSubscription<T> {
return boxedSignal.subscribe(on: observer, callback: callback)
}
/// Other subscribe + cancel methods
}
Option 2: Create a new protocol SignalObservingProtocol
(feel free to bike shed on naming) Which Signal
conforms to by default.
public protocol SignalObservingProtocol {
associatedtype T
typealias ObservableCallback = (T) -> Void
func subscribe(on observer: AnyObject, callback: @escaping ObservableCallback) -> Signals.SignalSubscription<T>
/// Other subscribe + cancel methods
}
extension Signals.Signal: SignalObservingProtocol {}
/// And provide a type erased `AnySignalObservingProtocol` with a type erased AnySignalObservingProtocol for convenience.
class AnySignalObservingProtocol<T>: SignalObservingProtocol {
func subscribe(on observer: AnyObject, callback: @escaping (T) -> Void) -> Signals.SignalSubscription<T> {
return _subscribe(observer, callback)
}
init<S: ReadOnlyObservableProtocol>(readOnlyObservable: S) where S.T == T {
_subscribe = { observer, callback in
return readOnlyObservable.subscribe(on: observer, callback: callback)
}
}
private var _subscribe: (AnyObject, @escaping (T) -> Void) -> Signals.SignalSubscription<T>
}
Thoughts?
With Signals 2.1.0 and Xcode 7.0.1, carthage update
fails with this error:
Tests.swift:11:18: error: module 'Signals' was not compiled for testing
A shell task failed with exit code 65:
This can be fixed by setting ENABLE_TESTABILITY to YES in the project file for release builds.
If it helps, I can send a PR with this change. Thanks!
The latest version generates several warnings when built in XCode 7 (Swift 2).
Last one for now, I promise. Have you measured the binary size impact of this library?
Please add the Podspec to the repo (useful to fetch a different branch directly from the Podfile without using a local repo, e.g. the "swift-2" branch).
Thank you.
If I have a Signal<Int>
and the value is currently 1
, then it fires with another 1
, I want certain observers not to respond to it (this would of course require the use of retainLastData
). The closest thing I see to satisfying this use case would be the use of filter
when setting up the observation, but it doesn't really work because the only argument is the new value, not the old value to compare and filter against. Is there something I'm missing? If this currently isn't possible, I have a few ideas:
Add this functionality into a separate fire
method, such as fireIfNew
. This would enforce the constraint on the publisher side if you want to make sure subscribers don't get repeated events for the same value. This is not the most flexible approach so can't be the main change if it happens at all.
This seems like a natural candidate for something you can add to filter
. One way would be to add another parameter to the filter block for the previous value, something like previousData
. This unfortunately does add a parameter to the filter
API that not everyone would use.
Another solution would be to add this as a chainable modifier method to SignalSubscription
alongside filter, which then sets an internal flag that can be checked at the same time filter is run. So the method would look something like ignoreDuplicates()
networkLoader.onProgress.subscribe(on: self) { (progress) in }.filter { $0 == 1.0 }.ignoreDuplicates()
distinctOnly = false
which would make this a backwards compatible change as the method signature wouldn't need to change to external users of the framework. This flag would then be saved and checked alongside the filter as well.Do you think that this is something that belongs in the framework? It seems like a pretty common use case and at the moment to do it correctly, you'd need to wrap your subscribers in another subscriber + signal that retains the second to last fired value. If you're interested, I can draft up a pull request (probably with solution 4) and we can see how it looks.
Attach-and-forget sounds interesting, but how do you deal with the problem of retain cycles and lifetimes that Disposables were created for?
Current version is 2.1.1. But in the podspec it is 2.1.0.
Firstly, thanks for this library, very useful. Secondly, I'm putting together a SignalsService that can be dependency injected, and privately create/fire/delete Signals, and would be very handy in that context for each Signal to have a numListeners:Int property. No drama if not deemed appropriate, I'll just create a Dictionary of Ints in my own Service if not. JBM.
The Signal's fireCount and lastDataFired-properties should only be readable publicly.
When I updated to the new version, all removeListener methods became undefined. Is it was renamed or removed?
Hi artman,
Thanks for this awesome library. The documentation says this library requires iOS 7.0 but the podspec targets iOS 8.0. Is iOS 8.0 required and if not, can the target be lowered to 7.0?
It looks interesting, and definitely smaller than RxSwift. Were there conversations to have uber move to this? Why haven't they?
Testing some more
Sorry if this is obvious but I'm new to Swift.
I'd like fire a Signal without passing any argument.
I've resorted to using Signal<Int?>()
and .fire(nil)
but is there more elegant way of handling this?
@artman can you push a new version to cocoa pods? I have some repos that use this (awesome) library as a dependency - would love to get all of them updated to 4.2 but need this to go first!
Thanks!
I'm still quite new to CocoaPods so I'm trying to figure out if it's me doing something wrong, but for some reason, CocoaPods doesn't think that Signals 6.0.0 support osx
:
- ERROR | [OSX] unknown: Encountered an unknown error (The platform of the target `App` (macOS 10.13) is not compatible with `Signals (6.0.0)`, which does not support `osx`.) during validation.
But looking at your pod-spec I cannot find anything that could cause this 🤔
This is my pod-spec btw.
Pod::Spec.new do |s|
s.name = "Marionette"
s.version = %x(git describe --tags --abbrev=0).chomp
s.summary = "Swift library which provides a high-level API to control a WKWebView"
s.description = "Marionette is a Swift library which provides a high-level API to control a WKWebView. The goal is to have the API closely mirror that of Puppeteer."
s.homepage = "https://github.com/LinusU/Marionette"
s.license = "MIT"
s.author = { "Linus Unnebäck" => "[email protected]" }
s.swift_version = "4.0"
s.ios.deployment_target = "11.0"
s.osx.deployment_target = "10.13"
s.source = { :git => "https://github.com/LinusU/Marionette.git", :tag => "#{s.version}" }
s.source_files = "Sources"
s.dependency "LinusU_JSBridge", "1.0.0-alpha.14"
s.dependency "PromiseKit", "~> 6.0"
s.dependency "Signals", "~> 6.0"
end
Maybe this should be reported to the CocoaPods repo? 🤔
I understand the dispatchOnQueue
method allows a subscriber to specify the thread on which to run its callback code.
However, I need to fire events from code which is running on a background thread. As it happens, all subscribers to these events are in the main thread. It feels like using dispatchOnQueue
in this case would require the subscribers to know about the origin of the event, leading to tightly-coupled code.
So I assume the obvious solution is to fire the events on the main thread in the first place:
// Send a signal on the main thread.
DispatchQueue.main.async {
self.onRawStderrorReceived.fire(stringData)
}
Does this approach sound correct? The reason I am asking is that I keep getting Thread 1: EXC_BAD_ACCESS (code=1, address=0xfffffffffffffff0)
errors thrown at that point (Xcode actually highlights the comment, oddly).
Method listenPast doesn't work with signals that don't retain last data but it doesn't prevent from using it which is causing hard to track issues, especially when you're migrating from old version of this library. There should also be an explanation that you should use listen instead.
Thanks for sharing this with the world. I'm only making light use of it at present but it seems to work very nicely.
Could you create a changelog file that documents the changes across releases, that would be very helpful.
Thanks.
Signals will not build under Xcode 14.3 due to an invalid IPHONEOS_DEPLOYMENT_TARGET. See the attached xcodebuild log.
Would it make sense to pass the observer as a parameter in the callback closure? Something like:
public func subscribe(with observer: ObserverType, callback: @escaping (ObserverType, T) -> T) -> Signals.SignalSubscription<ObserverType, T>
This will allow to convert this:
signal.subscribe(with: self) { [weak self] (newValue) in
guard let weakSelf = self else { return } // Boilerplate + easy to forget
weakSelf.property = newValue
}
Or this:
signal.subscribe(with: self) { (newValue) in
self.property = newValue // Retain cycle!!!!
}
Into this:
signal.subscribe(with: self) { (observer, newValue) in
observer.property = newValue
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.