Giter Site home page Giter Site logo

alexdrone / store Goto Github PK

View Code? Open in Web Editor NEW
500.0 9.0 36.0 31.88 MB

Unidirectional, transactional, operation-based Store implementation.

Swift 99.93% Shell 0.07%
redux swift store swiftui combine unidirectional-data-flow flux-application dispatcher binding stateobject

store's Introduction

store's People

Contributors

adriankoren avatar alexdrone avatar bragegs avatar danpalmer avatar mgcrea avatar regexident avatar sebastianv1 avatar steffenmllr avatar stuartro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

store's Issues

Combine separate reducers

I'm looking to reproduce a common redux pattern, combineReducers when you split your slices (types/actions/reducers) in separate files and combine them in your root store.

I have a Counter.swift:

import Store

struct CounterStore: SerializableModelProtocol {
    var count = 0
}

enum CounterAction: ActionProtocol {

    case increase(amount: Int)
    case decrease(amount: Int)

    var id: String {
        switch self {
        case .increase(_): return "INCREASE"
        case .decrease(_): return "DECREASE"
        }
    }

    func reduce(context: TransactionContext<Store<Counter>, Self>) {
        defer {
            context.fulfill()
        }
        switch self {
        case .increase(let amount):
            context.reduceModel { $0.count += amount }
        case .decrease(let amount):
            context.reduceModel { $0.count -= amount }
        }
    }
}

And a root Store.swift

import Store

struct RootStore: SerializableModelProtocol {
    var counter = CounterStore();
}

let store = SerializableStore<RootStore>(model: RootStore())

However this does not work as the the action reduce function does not receive the proper context (.counter key from RootStore).

Do you think such pattern is possible? Do you have any examples of a working setup?

Thanks for the lib!

iOS 14 compatibility issues

Hi!
I was trying to get the getting-started code snippets working in a freshly created swiftUI project that targets iOS 14.
But I am running into issues.

First, perhaps unrelated, I had to bump the iOS version in Package.swift from v12 to v13 in a fork, to able to resolve it inside XCode as a SwiftPackage, because of features like Future requiring at least iOS v13.

After getting the package installed I tried out the snippet in my ContentView, but got stuck at following errors:
Screenshot 2021-02-03 at 12 19 40

Potential race condition in Store.run (?)

In the code snippet below, Store's run method invokes transactionObj.run and then shortly (probably fast enough for it to work) invokes transactionObj.throttle. Would it not be better to reverse the order of run and throttle?

@discardableResult @inlinable @inline(__always)
public func run<A: ActionProtocol, M>(
    action: A,
    mode: Dispatcher.Strategy = .async(nil),
    throttle: TimeInterval = 0,
    handler: Dispatcher.TransactionCompletionHandler = nil
) -> Transaction<A> where A.AssociatedStoreType: Store<M> {
  let transactionObj = transaction(action: action, mode: mode)
  transactionObj.run(handler: handler) // RUN STARTED HERE
  if throttle > TimeInterval.ulpOfOne {
    transactionObj.throttle(throttle) // THROTTLING APPLIED HERE
  }
  return transactionObj
}

That is, instead of:

  let transactionObj = transaction(action: action, mode: mode)
  transactionObj.run(handler: handler) // RUN STARTED HERE
  if throttle > TimeInterval.ulpOfOne {
    transactionObj.throttle(throttle) // THROTTLING APPLIED HERE
  }

use:

  let transactionObj = transaction(action: action, mode: mode)

  if throttle > TimeInterval.ulpOfOne {
    transactionObj.throttle(throttle) // THROTTLING APPLIED HERE
  }
  transactionObj.run(handler: handler) // RUN STARTED HERE

?

Type 'CounterAction' does not conform to protocol 'ActionProtocol'

Just copy pasted the TLDR in the README and I'm encountering this error:

Type 'CounterAction' does not conform to protocol 'ActionProtocol'

Looks similar to #13 but there is no answer there.

I'm a Swift noob so it's probably obvious, looks like it requires a typealias AssociatedStoreType property but not sure what I should put there.

Thanks!


EDIT, looks like the README is not up to date with the protocol.

Build failure around RecorderMiddleware+.swift

When I build master(26ed0d6) with carthage, I gotta this error,

Carthage/Checkouts/Dispatch/src/RecorderMiddleware+.swift:214:58: error: use of undeclared type 'UIKeyModifierFlags'
                                          modifierFlags: UIKeyModifierFlags,
                                                         ^~~~~~~~~~~~~~~~~~
Carthage/Checkouts/Dispatch/src/RecorderMiddleware+.swift:216:75: error: use of undeclared type 'UIKeyModifierFlags'
    public static func unregisterKeyCommand(input: String, modifierFlags: UIKeyModifierFlags) {}
                                                                          ^~~~~~~~~~~~~~~~~~
Carthage/Checkouts/Dispatch/src/RecorderMiddleware+.swift:35:5: error: type 'KeyCommands' has no member 'register'
    KeyCommands.register(input: "n", modifierFlags: .command) { [weak self] in
    ^~~~~~~~~~~ ~~~~~~~~
Carthage/Checkouts/Dispatch/src/RecorderMiddleware+.swift:38:5: error: type 'KeyCommands' has no member 'register'
    KeyCommands.register(input: "p", modifierFlags: .command) { [weak self] in
    ^~~~~~~~~~~ ~~~~~~~~

** BUILD FAILED **

Missing import UIKit and KeyCommands.register, KeyCommands.unregister implementation?

Installation Section

Hey, your library is really interesting.

The only problem I found was the README.md, which lacks an Installation Section
I created this iOS Open source Readme Template so you can take a look on how to easily create an Installation Section
If you want, I can help you to organize the lib.

What are your thoughts? ๐Ÿ˜„

Carthage update error (has no shared schemes)

$ carthage update               
*** Fetching Dispatch
*** Checking out Dispatch at "e239f52f9400db79af78331f899df94e8fe5870c"
*** xcodebuild output can be found in /var/folders/s9/558z8thj5_d25__q84s895zm0000gq/T/carthage-xcodebuild.bMdbHS.log
*** Skipped building Dispatch due to the error:
Dependency "Dispatch" has no shared framework schemes

If you believe this to be an error, please file an issue with the maintainers at Optional("https://github.com/alexdrone/Dispatch/issues/new")

[Question] Async action with combine

Thank you for writing this library, I'm new to this architecture and trying to make it works.
However I'm struggling to implement an async task for reducer.

For example:
in Counter actions, make a GET call to remote server and then increase count with the response.

Can you please show the proper way to do async / side effect operation?

Build failed with Carthage

$ carthage update --platform iOS                 
*** Fetching Dispatch
*** Checking out Dispatch at "e239f52f9400db79af78331f899df94e8fe5870c"
*** xcodebuild output can be found in /var/folders/s9/558z8thj5_d25__q84s895zm0000gq/T/carthage-xcodebuild.IodW8V.log
*** Building scheme "DispatchStore_iOS" in DispatchStore.xcodeproj
** BUILD FAILED **


The following build commands failed:
	CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
	CompileSwift normal arm64
(2 failures)
/Carthage/Checkouts/Dispatch/src/RecorderMiddleware.swift:33:56: error: type 'KeyModifierFlags' (aka 'Int') has no member 'command'
/Carthage/Checkouts/Dispatch/src/RecorderMiddleware.swift:36:56: error: type 'KeyModifierFlags' (aka 'Int') has no member 'command'
A shell task (/usr/bin/xcrun xcodebuild -project /Carthage/Checkouts/Dispatch/DispatchStore.xcodeproj -scheme DispatchStore_iOS -configuration Release -sdk iphoneos ONLY_ACTIVE_ARCH=NO BITCODE_GENERATION_MODE=bitcode CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES clean build) failed with exit code 65:
** BUILD FAILED **


The following build commands failed:
	CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
	CompileSwift normal arm64
(2 failures)

But build success via Xcode.

Handling child stores for lists of data

I am thinking about using stores for new app I will be working on, but I cannot imagine how would the stores handle showing detail of a movie from the list of movies.

Imagine if I have app that loads list of items and I select on of the items to see its detail information. I am on the screen, but meanwhile the app updates the list in the background and the corresponding index does not match the same movie now, what will happen, how is this handled/should be handled

Iโ€™ve seen some other examples where there was selectedItem in the store/model, but that seems sort of too simple or am I missing something?

Is it okay to use a class instead of a struct for a store?

I am really struggling with this:

struct RequestLocation: ActionType {
  let location: CLLocation

  func reduce(context: TransactionContext<Store<LocationStore>, Self>) {
    defer {
      // Remember to always call `fulfill` to signal the completion of this operation.
      context.fulfill()
    }
    context.reduceModel { store -> (Void) in
      CoreLocationProxy().locationPublisher().map { location in
        store.location = location
      }
    }
  }
}

Compile error: Escaping closure captures 'inout' parameter 'store'

    context.reduceModel { store -> (Void) in
      store.requestLocationCancellable = store.proxy.locationPublisher().assign(to: \LocationStore.location, on: store)
    }

Compile error: Cannot convert value of type 'WritableKeyPath<LocationStore, CLLocation>' to expected argument type 'ReferenceWritableKeyPath<_, CLLocation>'

I don't see how to make this work without turning my store into a class. It works then. Would that code any issue?

Some more examples using publishers, etc would be quite useful btw.

Tag problem

Could you please add another number to your next release (like so 1.1.0). SPM is not working otherwise(

Sent with GitHawk

Add CI Integration?

Hi Alex,

is there any chance to have CI running for Store? That would greatly increase the trust level of this package. ๐Ÿ™‚

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.