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

Minimal Flux architecture written in Swift.

License

NotificationsYou must be signed in to change notification settings

hyperdevs-team/mini-swift

Repository files navigation

The minimal expression of a Flux architecture in Swift.

Mini is built with be a first class citizen in Swift applications:macOS, iOS and tvOS applications.With Mini, you can create a thread-safe application with a predictable unidirectional data flow, focusing on what really matters: build awesome applications.

Release VersionRelease DatePodPlatformGitHub

Build Statuscodecov

Requirements

  • Xcode 10 or later
  • Swift 5.0 or later
  • iOS 11 or later
  • macOS 10.13 or later
  • tvOS 11 or later

Installation

  • Add this to youCartfile:
github "masmovil/masmini-swift"
  • Add this to youPodfile:
pod "MasMini-Swift"
  • We also offer two subpecs for logging and testing:
pod "MasMini-Swift/Log"pod "MasMini-Swift/Test"

Usage

  • MasMiniSwift is a library which aims the ease of the usage of a Flux oriented architecture for Swift applications. Due its Flux-based nature, it heavily relies on some of its concepts likeStore,State,Dispatcher,Action,Task andReducer.

Architecture

State

  • The minimal unit of the architecture is based on the idea of theState.State is, as its name says, the representation of a part of the application in a moment of time.

  • TheState is a simplestruct which is conformed of differentTasks and different pieces of data that are potentially fulfilled by the execution of those tasks.

  • For example:

structMyCoolState:State{letcool:Bool?letcoolTask:Taskinit(cool:Bool=nil,         coolTask:Task=Task()){self.cool= coolself.coolTask= coolTask}    // Conform to State protocolfunc isEqual(to other:State)->Bool{guardlet state= otheras?MyCoolStateelse{returnfalse}returnself.cool== state.cool &&self.coolTask== state.coolState}}
  • The core idea of aState is itsimmutability, so once created, no third-party objects are able to mutate it out of the control of the architecture flow.

  • As can be seen in the example, aState has a pair ofTask +Resultusually (that can be any object, if any), which is related with the execution of theTask. In the example above,CoolTask is responsible, through itsReducer to fulfill theAction with theTask result and furthermore, the newState.

Action

  • AnAction is the piece of information that is being dispatched through the architecture. Anyclass can conform to theAction protocol, with the only requirement of being unique its name per application.
classRequestContactsAccess:Action{  // As simple as this is.}
  • Actions are free of have some pieces of information attached to them, that's whyMini provides the user with two main utility protocols:CompletableAction,EmptyAction andKeyedPayloadAction.

    • ACompletableAction is a specialization of theAction protocol, which allows the user attach both aTask and some kind of object that gets fulfilled when theTask succeeds.
    classRequestContactsAccessResult:CompletableAction{letrequestContactsAccessTask:TaskletgrantedAccess:Bool?typealiasPayload=Boolrequiredinit(task:Task, payload:Payload?){self.requestContactsAccessTask= taskself.grantedAccess= payload}}
    • AnEmptyAction is a specialization ofCompletableAction where thePayload is aSwift.Never, this means it only has associated aTask.
    classActivateVoucherLoaded:EmptyAction{letactivateVoucherTask:Taskrequiredinit(task:Task){self.activateVoucherTask= task}}
    • AKeyedPayloadAction, adds aKey (which isHashable) to theCompletableAction. This is a special case where the sameAction produces results that can be grouped together, tipically, under aDictionary (i.e., anAction to search contacts, and grouped by their main phone number).
    classRequestContactLoadedAction:KeyedCompletableAction{typealiasPayload=CNContacttypealiasKey=StringletrequestContactTask:Taskletcontact:CNContact?letphoneNumber:Stringrequiredinit(task:Task, payload:CNContact?, key:String){self.requestContactTask= taskself.contact= payloadself.phoneNumber= key}}

Store

  • AStore is the hub where decissions and side-efects are made through the ingoing and outgoingActions. AStore is a generic class to inherit from and associate aState for it.

  • AStore may produceState changes that can be observed like any otherRxSwift'sObservable. In this way aView, or any other object of your choice, can receive newStates produced by a certainStore.

  • AStore reduces the flow of a certain amount ofActions through thevar reducerGroup: ReducerGroup property.

  • TheStore is implemented in a way that has two generic requirements, aState: StateType and aStoreController: Disposable. TheStoreController is usually a class that contains the logic to perform theActions that might be intercepted by the store, i.e, a group of URL requests, perform a database query, etc.

  • Through generic specialization, thereducerGroup variable can be rewritten for each case of pairState andStoreController without the need of subclassing theStore.

extensionStorewhere State==TestState, StoreController==TestStoreController{varreducerGroup:ReducerGroup{returnReducerGroup{[Reducer(of:OneTestAction.self, on:self.dispatcher){ actioninself.state=self.state.copy(testTask:*.requestSuccess(), counter:*action.counter)}]}}}
  • In the snippet above, we have a complete example of how aStore would work. We use theReducerGroup to indicate how theStore will interceptActions of typeOneTestAction and that everytime it gets intercepted, theStore'sState gets copied (is not black magic 🧙‍, is through a set ofSourcery scripts that are distributed with this package).

If you are using SPM or Carthage, they doesn't really allow to distribute assets with the library, in that regard we recommend to just installSourcery in your project and use the templates that can be downloaded directly from the repository under theTemplates directory.

  • When working withStore instances, you may retain a strong reference of itsreducerGroup, this is done using thesubscribe() method, which is aDisposable that can be used like below:
varbag=DisposeBag()letstore=Store<TestState,TestStoreController>(TestState(), dispatcher: dispatcher, storeController:TestStoreController())store.subscribe().disposed(by: bag)

Dispatcher

  • The last piece of the architecture is theDispatcher. In an application scope, there should be only oneDispatcher alive from which every action is being dispatched.
letaction=TestAction()dispatcher.dispatch(action, mode:.sync)
  • With one line, we can notify everyStore which has defined a reducer for that type ofAction.

Authors & Collaborators

License

Mini-Swift is available under the Apache 2.0. See the LICENSE file for more info.

Packages

No packages published

Contributors5

Languages


[8]ページ先頭

©2009-2025 Movatter.jp