aleclarson / emitter-kit Goto Github PK
View Code? Open in Web Editor NEWType-safe event handling for Swift
License: MIT License
Type-safe event handling for Swift
License: MIT License
Xcode 6.3 (6D570)
OS X 10.10.3
Building for iPhone 6 (8.1, 8.3)
Added emitter-kit
as a submodule to the project. I am not using CocoaPods due to various problems experienced earlier.
When compiling, receive the error Unknown type name 'FOUNDATION_EXPORT'
.
The project builds successfully if each occurrence of FOUNDATION_EXPORT
is changed to extern
.
Hi there,
I'm trying to emit an event every time I update my array so I can reload a specific row in my table view. So far in other areas of my app I've been using 'once' without any problems but now I need to use 'on' instead of 'once' and for some reason it's not working...
I'm probably just missing something small here but I just can figure it out.
Hope you can help,
Thanks
signInEvent = Event<MasterViewController>()
//button touchup inside event
btnSignIn.onTap { [weak self] in
if self == nil {
return
}
self?.signInEvent?.emit(SigninController()) //Emit data Here
print(self?.signInEvent?.listenerCount) //Always return 0
}
//Listner
let listner = signInEvent?.on({ (data) in
print(data)
})
please upload the demo
works:
NSNotificationCenter.defaultCenter().addObserverForName(NSPopoverWillCloseNotification, object: self.popover, queue: nil, usingBlock: { _ in
self.statusItemView.highlighted = false
})
don't work:
Notification(NSPopoverWillCloseNotification).on(self.popover, { data in
self.statusItemView.highlighted = false
})
am I doing something wrong?
I think it's a good idea to make Notifier
subclass of NSObject
.
this way, developers can retain Notifier
object with protocol extensions too. (using objc_setAssociatedObject
) .
I've described it here: http://stackoverflow.com/questions/38190702/how-to-use-objc-protocol-with-optional-and-extensions-at-the-same-time/42212943#42212943
Any plan to support watchOs?
https://medium.com/@JTEhlert/using-cocoapods-with-watchos-2-723b92eae04f#.ab2fpi6b3
The listenerCount
property of the Event
class is currently computed with _listeners.count
. That's not right, since the _listeners
dictionary uses target identifiers for its keys; not listener identifiers.
This will get fixed at the same time as #43.
I've been playing around with the library, and after reading up on the README it looks like anytime you use .on vs .once for anything (in my case KVO), you have to push the listener into an array.
I was trying out .on without pushing on an array and everything looked fine. Can you explain a little more how this works out, and why I shouldn't be using .on without pushing into an array? Also, is there any cleanup I have to do for .on instead of .once?
Thanks
Working with the Event class I often have to make sure that I'm not creating a retain cycle.
To make it a bit easier, I've created the following helper:
func on<Owner: AnyObject>(_ owner: Owner, _ method: @escaping (Owner) -> (T) -> Void) -> EventListener<T> {
return self.on { [weak owner] data in
if let ownerRef = owner {
method(ownerRef)(data)
}
}
}
You can use it like this:
var listener = myEvent.on(self, MyClass.onMyEvent)
private func onMyEvent(data: Data) {
print(data)
}
Would you consider adding this to the codebase?
Perhaps the method should have a different name than on
to prevent confusion with the overloads that have the targetting arguments.
This method would prevent listeners added after the current listener from receiving the event.
Not certain on how this would be implemented or what the method name would be.
It's also possible something like this calls for an abstraction layer on top of EmitterKit instead of being baked in.
Currently, targeted listeners must be manually retained by their target if you want the listeners to get released when/if their target gets released. If you don't do that, your code may be retaining listeners whose target has long been released. This means wasted memory, because those listeners will never be triggered.
The AssociatedListeners
class would use objc_setAssociatedObject
to attach an array (of strong pointers to all associated listeners) to the appropriate target. You would no longer have to manually retain indefinite listeners, since they would be released when the target is released.
Additionally, a helper method would be added to the Event
class called getListeners(target)
for retrieving the array of associated listeners. You could use this method to remove associated listeners any time before the target is released.
I'm interested in finding out if anyone thinks this is a problem worth solving. Thanks.
Please find the crash in the screenshot above.
As mentioned in #57, force unwrapping _listeners[_targetID]
is causing the crash because there's no value in _listeners
.
Just an extra reason to store the listeners in an array in your object is because when that object is deallocated, the listeners are deallocated as well. Which leaves no listeners hanging in "thin air".
For example:
class SomeTemporaryClass {
var listeners = [Listener]()
init(someEvent: Event<String>) {
listeners += someEvent.on { (str) -> Void in
print("someEvent was triggered")
}
}
deinit {
print("instance of SomeTemporaryClass was deallocated")
}
}
class ViewController: UIViewController {
var temp: SomeTemporaryClass?
override func viewDidLoad() {
super.viewDidLoad()
let someEvent = Event<String>()
temp = SomeTemporaryClass(someEvent: someEvent)
temp = nil // deallocate temp and it's listeners will be deallocated too :-)
someEvent.emit("hello")
}
}
I installed the Library with Carthage 0.26.2
X-Code 9.0.1
Swift 3.2
Simulator: no errors
Device: This application’s bundle identifier does not match its code signing identifier.
If I remove the library all is working fine.
I can install other libraries with Carthage with no problems.
Any help would be greatly appreciated!
Can you please push the 5.0 release to cocoapods? Thanks!
There is specific case when calling event.emit(*) causes critical error. It happens when event is expecting type protocol.
init (_ event: Event<T>, _ target: AnyObject!, _ once: Bool, _ handler: @escaping (T) -> Void) {
self.event = event
super.init(target, once, {
handler($0 as! T) <- Error while casting
})
}
(Issue appeared after migration of the own project to swift 4.2)
Hi,
I want to ask you if you have any reason to have deployment target iOS 8.0 and higher, why not iOS 7.0 since Swift is fully supported on iOS 7?
I wanted to be able to work with emitter-kit, in the same paradigm as Backbone (http://backbonejs.org/#Events)
only instead of using String for event names, I wanted to use enums.
enum EventType {
case Start
case Open
}
let events = ListenerStorage()
let myEvent = Event<Int>()
events += myEvent.on {
NSLog("myEvent.on listener was called with: \($0)")
}
myEvent.emit(EventType.Start, 33) // fails at compilation
var type : AnyObject! = EventType.Start // fails at compilation
the reason being
you can't assign sturct/enum to AnyObject because they are not object type (you can use Any to hold them)
my current (somewhat hacky) solution is to do:
enum EventType : String {
case Start = "start-event-id"
case Open = "open-event-id"
}
and then do
myEvent.emit(EventType.Start.toRaw(), 33)
I suspect the issue with enums is the hashify
func:
https://github.com/aleclarson/emitter-kit/blob/master/src/Emitter.swift#L228-L230
@aleclarson any ideas?
Do you need to push the new podspec?
https://guides.cocoapods.org/making/getting-setup-with-trunk
Swift 2 has changed in this beta, and emitter-kit no longer compiles.
Thanks!
I used to use this library a lot. Opening my new Xcode after more than a year, it reports that the library is not compatible with Swift 4. Do they already have some native event emitter I can use or should I try to port emitter-kit to make it work with Swift 4?
There are currently several issues with the build after the latest Xcode update (6D520o). We are looking at these locally and probably have a patch during today.
How are you handling backwards incompatible changes at the moment? After the updates the code will only compile with Swift 1.2 as there is no proper support for conditional compiling in the language.
Just curious what changes went into this release.
All add info on how to install in README.md
@aleclarson WDYT?
Listeners should be called in the order they were added. Currently they are stored in a Dictionary
(with no defined order).
Example:
let didSave = Event<Void>()
let listener1 = didSave.on {
print("1")
}
let listener2 = didSave.on {
print("2")
}
didSave.emit()
The output may be:
1
2
or
2
1
This may be a pretty big problem when actions need to be done in the certain order. E.g. we may listen to an event in the same class where it's also located. The listener would be set in the constructor and I'd expect that this is the first listener that would get called. After that would be call other listeners (that were set let's say out of this class).
I'm considering making isListening
readonly. Right now, you can set it to false
to temporarily remove the listener from its associated event, and set it to true
to receive events again. Currently, doing that will make the listener lose its place in the call order (assuming #43 gets fixed).
Instead, there could be a disable
method for disabling the listener without losing its place, and an enable
method for allowing events to be handled again. Also, a destroy
method would be added for removing the listener from its event forever; which would be used for cancelling one-time listeners and automatically clearing out dereferenced listeners.
I'm curious what anyone else thinks of this change. Would the breaking change be worth it? I'm also open to suggestions on the naming of the proposed methods.
In case Signal can't send data.(Why BTW?) But I need to send some so I've to extend Event (am I right?)
But xcode give me and error if I try to
class Foo: Event <EventData: Any> {
}
Expected '>' to complete generic argument list
Thanks
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.