Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

The most powerful Event-Driven Observer Pattern solution the Swift language has ever seen!

License

NotificationsYou must be signed in to change notification settings

Flowduino/EventDrivenSwift

Repository files navigation

Decoupling of discrete units of code contributes massively to the long-term maintainability of your project(s). WhileObserver Pattern is a great way of providing some degree of decoupling by only requiring thatObservers conform to a mutually-agreedInterface (Protocol, in Swift), we can go significantly further using an Event-Driven Pattern.

With Event-Driven systems, there is absolutelyno direct reference between discrete units of code. Instead, each discrete unit of code emits and listens forEvents (as applicable). AnEvent is simply a structured object containing immutable information. Each unit of code can then operate based on the Event(s) it receives, and perform whatever operation(s) are necessary in the context of that particular unit of code.

Event Driven Swift is an extremely powerful library designed specifically to power your Event-Driven Applications in the Swift language.

Decoupled Topology

Where traditional software design principles would require communicating objects to reference each-other directly, Event-Driven design patterns eliminate the need for this.

Topological Diagram showing Event-Driven ViewModel being updated via Events from the Data Model Repository

Terminology

Understanding the Terminology used in this Library and its supporting examples/documentation will aid you considerably in immediately leveraging these tools to produce extremely powerful, high-performance, entirely-decoupled and easily maintained Event-Driven solutions.

Event

AnEvent is simply an immutable payload of information that can be used to drive logic and behaviour.

Think of anEvent as being akin to anOperation Trigger. In response to receiving anEvent of a known Type, a distinct unit of code would perform an appropriate operation based on the information received in thatEvent'spayload.

InEventDrivenSwift, we would typically define anEvent as astruct conforming to theEventable protocol.

Here is a simple example:

structTemperatureEvent:Eventable{vartemperatureInCelsius:Float}

Note that the above example,TemperatureEvent, is the most basic example of anEvent possible, in that it only contains one piece of information.In reality, yourEvents can encapsulate as much information as is logical for a single cohesive operation trigger.

Important Note: AnEvent shouldnever include any Reference-Type values (such asclass instances).Events need to beimmutable, meaning that none of their values can possibly change after they have beenDispatched.

Event Queue

AnEvent Queue is a sequencial collection (Array) ofEventable objects that will automatically be processed whenever theQueue is not empty.Queues are always processed in the order First-in-First-out (orFiFo).

Note thatEvents dispatched to aQueue will always be processed afterEvents dispatched to aStack.

Event Stack

AnEvent Stack is virtually the same as anEvent Queue, except that it is processed in the opposite order: Last-in-First-out (orLiFo)

Note thatEvents dispatched to aStack will always be processed beforeEvents dispatched to aQueue.

Event Priority

Events can be dispatched to aQueue orStack with one of the followingPriorities:.highest will be processed first.high will be processed second.normal will be processed third.low will be processed fourth.lowest will be processed last

This means that we can enforce some degree ofexecution order overEvents at the point of dispatch.

Dispatch

Dispatch is a term comparable toBroadcast.When weDispatch anEvent, it means that we are sending that information to everyEventThread (see next section) that is listening for thatEvent type.

Once anEvent has beenDispatched, it cannot be cancelled or modified. This is by design. Think of it as saying that "you cannot unsay something once you have said it."

Events can beDispatched from anywhere in your code, regardless of whatThread is invoking it. In this sense,Events are very much afire and forget process.

EventThread

AnEventThread is aclass inheriting the base type provided by this library calledEventThread.

Beneath the surface,EventThread descends fromThread, and is literally what is known as aPersistent Thread.This means that theThread would typically exist either for a long as your particular application would require it, or even for the entire lifetime of your application.

Unlike most Threads,EventThread has been built specifically to operate with the lowest possible system resource footprint. When there are noEvents waiting to be processed by yourEventThread, the Thread will consume absolutely no CPU time, and effectively no power at all.

Once yourEventThread receives anEvent of anEventable type to which it hassubscribed, it willwake up automatically and process any waitingEvents in its respectiveQueue andStack.

Note: any number ofEventThreads can receive the sameEvents. This means that you can process the sameEvent for any number of purposes, in any number of ways, with any number of outcomes.

Event Handler (or Callback)

When you define yourEventThread descendant, you will implement a function calledregisterEventListeners. Within this function (which is invoked automatically every time an Instance of yourEventThread descendant type is initialised) you will register theEventable Types to which yourEventThread is interested; and for each of those, define a suitableHandler (orCallback) method to process thoseEvents whenever they occur.

You will see detailed examples of this in theUsage section of this document later, but the key to understand here is that, for eachEventable type that yourEventThread is interested in processing, you will be able to register yourEvent Handler for thatEvent type in a single line of code.

This makes it extremely easy to manage and maintain theEvent Subscriptions that eachEventThread has been implemented to process.

Performance-Centric

EventDrivenSwift is designed specifically to provide the best possible performance balance both at the point ofDispatching anEvent, as well as at the point ofProcessing anEvent.

With this in mind,EventDrivenSwift provides aCentral Event Dispatch Handler by default. Whenever youDispatch anEvent through either aQueue orStack, it will be immediately enqueued within theCentral Event Dispatch Handler, where it will subsequently beDispatched to all registeredEventThreads through its ownThread.

This means that there is a near-zero wait time between instructing anEvent toDispatch, and continuing on in the invoking Thread's execution.

Despite using an intermediary Handler in this manner, the time betweenDispatch of anEvent and theProcessing of thatEvent by eachEventThread isimpressively short! This makesEventDrivenSwift more than useful for performance-critical applications, including videogames!

Built onObservable

EventDrivenSwift is built on top of ourObservable library, andEventThread descends fromObservableThread, meaning that it supports fullObserver Pattern behaviour as well asEvent-Driven behaviour.

Put simply: you can ObserveEventThreads anywhere in your code that it is necessary, including from SwiftUI Views.

This means that your application can dynamically update your Views in response toEvents being received and processed, making your application truly and fully multi-threaded, without you having to produce code to handle the intra-Thread communication yourself.

Built onThreadSafeSwift

EventDrivenSwift is also built on top of ourThreadSafeSwift library, and every public method and member of every type inEventDrivenSwift is designed specifically to beThread-Safe.

It is strongly recommended that your own implementations usingEventDrivenSwift adhere strictly to the best Thread-Safe standards. With that said, unless you are defining avar orfunc that is accessible publicly specifically for the purpose of displaying information on the UI, most back-end implemenations built with a pure Event-Driven methodology will not need to concern themselves too much with Thread-Safety.

Installation

Xcode Projects

SelectFile ->Swift Packages ->Add Package Dependency and enterhttps://github.com/Flowduino/EventDrivenSwift.git

Swift Package Manager Projects

You can useEventDrivenSwift as a Package Dependency in your own Packages'Package.swift file:

letpackage=Package(    //...    dependencies:[.package(            url:"https://github.com/Flowduino/EventDrivenSwift.git",.upToNextMajor(from:"5.0.0")),],    //...)

From there, refer toEventDrivenSwift as a "target dependency" in any ofyour package's targets that need it.

targets:[.target(        name:"YourLibrary",        dependencies:["EventDrivenSwift",],        //...),    //...]

You can then doimport EventDrivenSwift in any code that requires it.

Usage

So, now that we've taken a look at whatEventDrivenSwift is, what it does, and we've covered a lot of the importantTerminology, let's take a look at how we can actually use it.

Defining anEvent type

You can make virtuallyanystruct type into anEvent type simply by inheriting fromEventable:

structTemperatureEvent:Eventable{vartemperatureInCelsius:Float}

It really is as simple as that!

Dispatching anEvent

Now that we have a definedEvent type, let's look at how we wouldDispatch anEvent of this type:

lettemperatureEvent=TemperatureEvent(temperatureInCelsius:23.25)

The above creates an instance of ourTemperatureEventEvent type.If we want to dispatch it via aQueue with the.normalPriority, we can do so as easily as this:

temperatureEvent.queue()

We can also customise thePriority:

temperatureEvent.queue(priority:.highest)

The above would dispatch the Event via aStack with the.highestPriority.

The same works when dispatching via aStack:

temperatureEvent.stack()

Above would again be with.normalPriority...

temperatureEvent.stack(priority:.highest)

Above would be with.highestPriority.

ScheduledDispatching of anEvent

Version 4.2.0 introducedScheduled Dispatch into the library:

temperatureEvent.scheduleQueue(at:DispatchTime.now()+ TimeInterval().advanced(by:4), priority:.highest)

The above wouldDispatch thetemperatureEvent after 4 seconds, via theQueue, with thehighest Priority

temperatureEvent.scheduleStack(at:DispatchTime.now()+ TimeInterval().advanced(by:4), priority:.highest)

The above wouldDispatch thetemperatureEvent after 4 seconds, via theStack, with thehighest Priority

Scheduled Event Dispatch is a massive advantage when your use-case requires a fixed or calculated time delay between the composition of anEvent, and itsDispatch for processing.

(Receiving & Processing Events - Method 1) Defining anEventThread

So, we have anEvent type, and we are able toDispatch it through aQueue or aStack, with whateverPriority we desire. Now we need a way to Receive our*TemperatureEvents so that we can do something with them. One way of doing this is to define anEventThreadto listen for and process ourTemperatureEvent`s.

classTemperatureProcessor:EventThread{    /// Register our Event Listeners for this EventThreadoverridefunc registerEventListeners(){addEventCallback(onTemperatureEvent, forEventType:TemperatureEvent.self)}        /// Define our Callback Function to process received TemperatureEvent Eventsfunc onTemperatureEvent(_ event:TemperatureEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){}}

Before we dig into the implementation ofonTemperatureEvent, which can basically do whatever we would want to do with the data provided in theTemperatureEvent, let's take a moment to understand what is happening in the above code.

Firstly,TemperatureProcessor inherits fromEventThread, which is where all of the magic happens to receiveEvents and register ourListeners (orCallbacks orHandlers).

The functionregisterEventListeners will be called automatically when an instance ofTemperatureProcessor is created. Within this method, we calladdEventCallback to registeronTemperatureEvent so that it will be invoked every time anEvent of typeTemperatureEvent isDispatched.

OurCallback (orHandler orListener Event) is calledonTemperatureEvent, which is where we will implement whateverOperation is to be performed against aTemperatureEvent.

Version 5.0.0 introduces the new parameter,dispatchTime, which will always provide theDispatchTime reference at which theEvent wasDispatched. You can use this to determineDelta (how much time has passed since theEvent wasDispatched), which is particularly useful if you are performing interpolation and/or extrapolation.

Now, let's actually do something with ourTemperatureEvent in theonTemperatureEvent method.

    /// An Enum to map a Temperature value onto a RatingenumTemperatureRating:String{case belowFreezing="Below Freezing"case freezing="Freezing"case reallyCold="Really Cold"case cold="Cold"case chilly="Chilly"case warm="Warm"case hot="Hot"case reallyHot="Really Hot"case boiling="Boiling"case aboveBoiling="Steam"staticfunc fromTemperature(temperatureInCelsius:Float)->TemperatureRating{if temperatureInCelsius<0{return.belowFreezing}elseif temperatureInCelsius==0{return.freezing}elseif temperatureInCelsius<5{return.reallyCold}elseif temperatureInCelsius<10{return.cold}elseif temperatureInCelsius<16{return.chilly}elseif temperatureInCelsius<22{return.warm}elseif temperatureInCelsius<25{return.hot}elseif temperatureInCelsius<100{return.reallyHot}elseif temperatureInCelsius==100{return.boiling}else{return.aboveBoiling}}}@ThreadSafeSemaphorepublicvartemperatureInCelsius:Float=Float.zero@ThreadSafeSemaphorepublicvartemperatureRating:TemperatureRating=.freezingfunc onTemperatureEvent(_ event:TemperatureEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){        temperatureInCelsius= event.temperatureInCelsius        temperatureRating=TemperatureRating.fromTemperature(event.temperatureInCelsius)}}

The above code is intended to be illustrative, rather thanuseful. OuronTemperatureEvent passesEvent's encapsulatedtemperatureInCelsius to a public variable (which could then be read by other code as necessary) as part of ourEventThread, and also pre-calculates aTemperatureRating based on the Temperature value received in theEvent.

Ultimately, your code can do whatever you wish with theEvent'sPayload data!

Playground Code to test everything so far

The only thing you're missing so far is how to create an instance of yourEventListner type.This is in fact remarkably simple. The following can be run in a Playground:

lettemperatureProcessor=TemperatureProcessor()

That's all you need to do to create an instance of yourTemperatureProcessor.

Let's add a line to print the inital values oftemperatureProcessor:

print("Temp in C:\(temperatureProcessor.temperatureInCelsius)")print("Temp Rating:\(temperatureProcessor.temperatureRating)")

We can now dispatch aTemperatureEvent to be processed bytemperatureProcessor:

TemperatureEvent(temperatureInCelsius:25.5).queue()

BecauseEvents are processedAsynchronously, and because this is just a Playground test, let's add a 1-second sleep to giveTemperatureProcessor time to receive and process theEvent.Note: In reality, this would need less than 1ms to process!

sleep(1)

Now let's print the same values again to see that they have changed:

print("Temp in C:\(temperatureProcessor.temperatureInCelsius)")print("Temp Rating:\(temperatureProcessor.temperatureRating)")

Now you have a little Playground code to visually confirm that yourEvents are being processed. You can modify this to see what happens.

Observing anEventThread

Remember,EventThreads are alsoObservable, so we can not only receive and operate onEvents, we can also notifyObservers in response toEvents.

Let's take a look at a simple example based on the examples above.We shall begin by defining anObserver Protocol:

protocolTemperatureProcessorObserver:AnyObject{func onTemperatureEvent(temperatureInCelsius:Float)}

Now let's modify theonTemperatureEvent method we implemented in the previous example:

func onTemperatureEvent(_ event:TemperatureEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){        temperatureInCelsius= event.temperatureInCelsius        temperatureRating=TemperatureRating.fromTemperature(event.temperatureInCelsius)                /// Notify any Observers...withObservers{(observer:TemperatureProcessorObserver)in            observer.onTemperatureEvent(temperatureInCelsius: event.temperatureInCelsius)}}

Now, every time aTemperatureEvent is processed by theEventThread, it will also notify any directObservers as well.

It should be noted that this functionality serves as acomplement toEvent-Driven behaviour, as there is no "one size fits all" solution to every requirement in software. It is often neccessary to combine methodologies to achieve the best results.

Reciprocal Events

Typically, systems not onlyconsume information, but alsoreturn information (results). This is not only true when it comes to Event-Driven systems, but also trivial to achieve.

Let's expand upon the previous example once more, this time emitting a reciprocalEvent to encapsulate the Temperature, as well as theTemperatureRating we calculated in response to theTemperatureEvent.

We'll begin by defining the ReciprocalEvent type:

enumTemperatureRatingEvent:Eventable{vartemperatureInCelsius:FloatvartemperatureRating:TemperatureRating}

With theEvent type defined, we can now once more expand ouronTemperatureEvent toDispatch our reciprocalTemperatureRatingEvent:

func onTemperatureEvent(_ event:TemperatureEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){        temperatureInCelsius= event.temperatureInCelsius        temperatureRating=TemperatureRating.fromTemperature(event.temperatureInCelsius)                /// Notify any Observers...withObservers{(observer:TemperatureProcessorObserver)in            observer.onTemperatureEvent(temperatureInCelsius: event.temperatureInCelsius)}                /// Dispatch our Reciprocal Event...TemperatureRatingEvent(            temperatureInCelsius= temperatureInCelsius,            temperatureRating= temperatureRating).queue()}

As you can see, we can create andDispatch anEvent in a single operation. This is becauseEvents should be considered to be "fire and forget". You need only retain a copy of theEvent within theDispatching Method if you wish to use its values later in the same operation. Otherwise, just create it andDispatch it together, as shown above.

Now that we've walked through these basic Usage Examples, see if you can produce your ownEventThread to processTemperatureRatingEvents. Everything you need to achieve this has already been demonstrated in this document.

UIEventThread

Version 2.0.0 introduced theUIEventThread base class, which operates exactly the same way asEventThread, with the notable difference being that your registeredEvent Callbacks willalways be invoked on theMainActor (or "UI Thread"). You can simply inherit fromUIEventThread instead ofEventThread whenever it is imperative for one or moreEvent Callbacks to execute on theMainActor.

(Receiving & Processing Events - Method 2)EventListener

Version 3.0.0 introduced theEventListener concept to the Library. These are a universally-available means (available in anyclass you define) ofReceiving Events dispatched from anywhere in your code, and requireconsiderably less code to use.

AnEventListener is a universal way of subscribing toEvents, anywhere in your code, without having to define and operate within the constraints of anEventThread.

By design,EventDrivenSwift provides aCentral Event Listener, which is automatically initialized should any of your code register aListener for anEvent by reference to theEventable type.

Important Note:EventListener will (by default) invoke the associatedCallbacks on the same Thread (orDispatchQueue) from whence theListener registered! This is an extremely useful behaviour, because it means thatListeners registered from theMainActor (or "UI Thread") will always execute on that Thread, with no additional overhead or code required by you.

Let's register a simpleListener in some arbitraryclass. For this example, let's produce a hypotheticalView Model that willListen forTemperatureRatingEvent, and would invalidate an owningView to show the newly-received values.

For the sake of this example, let's define this the pure SwiftUI way,without taking advantage of ourObservable library:

classTemperatureRatingViewModel:ObservableObject{@PublishedvartemperatureInCelsius:Float@PublishedvartemperatureRating:TemperatureRatingvarlistenerHandle:EventListenerHandling?internalfunc onTemperatureRatingEvent(_ event:TemperatureRatingEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){        temperatureInCelsius= event.temperatureInCelsius        temperatureRating= event.temperatureRating}init(){        // Let's register our Event Listener Callback!        listenerHandle=TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent)}}

It really isthat simple!

We can use a direct reference to anEventable type, and invoke theaddListener method, automatically bound to allEventable types, to register ourListener.

In the above example, whenever theReciprocal Event namedTemperatureRatingEvent is dispatched, theonTemperatureRatingEvent method of anyTemperatureRatingViewModel instance(s) will be invoked, in the context of thatEvent!

Don't worry about managing the lifetime of yourListener! If the object which owns theListener is destroyed, theListener will be automatically unregistered for you!

If you need yourEvent Callback to execute on theListener's Thread, as of Version 3.1.0... you can!

listenerHandle=TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, executeOn:.listenerThread)

Remember: When executing anEvent Callback on.listenerThread, you will need to ensure that yourCallback and all resources that it uses are 100% Thread-Safe!Important: Executing theEvent Callback on.listnerThread can potentially delay the invocation of otherEvent Callbacks. Only use this option when it is necessary.

You can also execute yourEvent Callback on an ad-hocTask:

listenerHandle=TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, executeOn:.taskThread)

Remember: When executing anEvent Callback on.taskThread, you will need to ensure that yourCallback and all resources that it uses are 100% Thread-Safe!

Another thing to note about the above example is thelistenerHandle. Whenever you register aListener, it will return anEventListenerHandling object. You can use this value toUnregister yourListener at any time:

    listenerHandle.remove()

This will remove yourListener Callback, meaning it will no longer be invoked any time aTemperatureRatingEvent isDispatched.

Note: This is an improvement for Version 4.1.0, as opposed to the use of an untypedUUID from previous versions.

EventListeners are an extremely versatile and very powerful addition toEventDrivenSwift.

EventListener withLatest-Only Interest

Version 4.3.0 of this library introduces the concept ofLatest-Only Listeners. ALatest-Only Listener is aListener that will only be invoked for the very latestEvent of its requestedEvent Type. If there are a number of olderEvents of this type pending in a Queue/Stack, they will simply be skipped over... and only the veryLatest will invoke yourListener.

We have made it incredibly simple for you to configure yourListener to be aLatest-Only Listener. Taking the previous code example, we can simply modify it as follows:

classTemperatureRatingViewModel:ObservableObject{@PublishedvartemperatureInCelsius:Float@PublishedvartemperatureRating:TemperatureRatingvarlistenerHandle:EventListenerHandling?internalfunc onTemperatureRatingEvent(_ event:TemperatureRatingEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){        temperatureInCelsius= event.temperatureInCelsius        temperatureRating= event.temperatureRating}init(){        // Let's register our Event Listener Callback!        listenerHandle=TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, interestedIn:.latestOnly)}}

By including theinterestedIn optional parameter when invokingaddListener against anyEventable type, and passing for this parameter a value of.latestOnly, we define that thisListener is only interested in theLatestTemperatureRatingEvent to beDispatched. Should a number ofTemperatureRatingEvents build up in the Queue/Stack, the above-definedListener will simply discard any older Events, and only invoke for the newest.

EventListener withMaximum Age Interest

Version 5.1.0 of this library introduces the concent ofMaximum Age Listeners. AMaximum Age Listener is aListener that will only be invoked forEvents of its registeredEvent Type that are younger than a definedMaximum Age. AnyEvent older than the definedMaximum Age will be skipped over, while anyEvent younger will invoke yourListener.

We have made it simple for you to configure yourListener to define aMaximum Age interest. Taking the previous code example, we can simply modify it as follows:

classTemperatureRatingViewModel:ObservableObject{@PublishedvartemperatureInCelsius:Float@PublishedvartemperatureRating:TemperatureRatingvarlistenerHandle:EventListenerHandling?internalfunc onTemperatureRatingEvent(_ event:TemperatureRatingEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){        temperatureInCelsius= event.temperatureInCelsius        temperatureRating= event.temperatureRating}init(){        // Let's register our Event Listener Callback!        listenerHandle=TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, interestedIn:.youngerThan, maximumAge:1*1_000_000_000)}}

In the above code example,maximumAge is a value defined innanoseconds. With that in mind,1 * 1_000_000_000 would be 1 second. This means that, anyTemperatureRatingEvent older than 1 second would be ignored by theListener, while anyTemperatureRatingEventyounger than 1 second would invoke theonTemperatureRatingEvent method.

This functionality is very useful when the context of anEvent's usage would have a known, fixed expiry.

EventListener withCustom Event Filtering Interest

Version 5.2.0 of this library introduces the concept ofCustom Event Filtering forListeners.

Now, when registering aListener for anEventable type, you can specify acustomFilterCallback which, ultimately, returns aBool wheretrue means that theListener is interested in theEvent, andfalse means that theListener isnot interested in theEvent.

We have made it simple for you to configure aCustom Filter for yourListener. Taking the previous code example, we can simply modify it as follows:

classTemperatureRatingViewModel:ObservableObject{@PublishedvartemperatureInCelsius:Float@PublishedvartemperatureRating:TemperatureRatingvarlistenerHandle:EventListenerHandling?internalfunc onTemperatureRatingEvent(_ event:TemperatureRatingEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime){        temperatureInCelsius= event.temperatureInCelsius        temperatureRating= event.temperatureRating}internalfunc onTemperatureRatingEventFilter(_ event:TemperatureRatingEvent, _ priority:EventPriority, _ dispatchTime:DispatchTime)->Bool{if event.temperatureInCelsius>50{returnfalse} // If the Temperature is above 50 Degrees, this Listener is not interested in it!returntrue // If the Temperature is NOT above 50 Degrees, the Listener IS interested in it!}init(){        // Let's register our Event Listener Callback!        listenerHandle=TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, interestedIn:.custom, customFilter: onTemperatureRatingEventFilter)}}

The above code will ensure that theonTemperatureRatingEvent method is only invoked for aTemperatureRatingEvent where itstemperatureInCelsius is less than or equal to 50 Degrees Celsius. AnyTemperatureRatingEvent with atemperatureInCelsius greater than 50 will simply be ignored by thisListener.

EventPool

Version 4.0.0 introduces the extremely powerfulEventPool solution, making it possible to create managed groups ofEventThreads, where inboundEvents will be directed to the bestEventThread in theEventPool at any given moment.

EventDrivenSwift makes it trivial to produce anEventPool for any givenEventThread type.

To create anEventPool of ourTemperatureProcessor example from earlier, we can use a single line of code:

vartemperatureProcessorPool=EventPool<TemperatureProcessor>(capacity:5)

The above example will create anEventPool ofTemperatureProcessors, with an initialCapacity of5 instances. This means that your program can concurrently process5TemperatureEvents.Obviously, for a process so simple and quick to complete as our earlier example, it would not be neccessary to produce anEventPool, but you can adapt this example for your own, more complex and time-consuming,EventThread implementations to immediately parallelise them.

EventPools enable you to specify the most context-appropriateBalancer on initialization:

vartemperatureProcessorPool=EventPool<TemperatureProcessor>(capacity:5, balancer:EventPoolRoundRobinBalancer())

The above example would use theEventPoolRoundRobinBalancer implementation, which simply directs each inboundEventable to the nextEventThread in the pool, rolling back around to the first after using the finalEventThread in the pool.

There is also anotherBalancer available in version 4.0.0:

vartemperatureProcessorPool=EventPool<TemperatureProcessor>(capacity:5, balancer:EventPoolLowestLoadBalancer())

The above example would use theEventPoolLowestLoadBalancer implementation, which simply directs each inboundEventable to theEventThread in the pool with the lowest number of pendingEventables in its ownQueue andStack.

NOTE: When nobalancer is declared,EventPool will useEventPoolRoundRobinBalancer by default.

Features Coming Soon

EventDrivenSwift is an evolving and ever-improving Library, so here are lists of the features you can expect in future releases.

Version 5.1.0 (or 6.0.0 if interface-breaking changes are required):

  • Event Pool Scalers - Dynamic Scaling forEventPool instances will be fully-implemented (for the moment, no automatic Scaling will occur, and you cannot change the scale of anEvent Pool once it has been initialised)

License

EventDrivenSwift is available under the MIT license. See theLICENSE file for more info.

Join us on Discord

If you require additional support, or would like to discussEventDrivenSwift, Swift, or any other topics related to Flowduino, you canjoin us on Discord.


[8]ページ先頭

©2009-2025 Movatter.jp