Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Christian Tietze
    @DivineDominion
    This message was deleted
    #123    0x00000001012624c8 in closure #1 in closure #1 in closure #1 in variable initialization expression of updateWorkspaceTitlesMiddleware at /Users/ctm/Coding/minNV/State/State/Middlewares/UpdateWorkspaceTitlesMiddleware.swift:9
    #124    0x000000010126400a in partial apply for closure #1 in closure #1 in closure #1 in variable initialization expression of updateWorkspaceTitlesMiddleware ()
    #125    0x000000010132172c in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #126    0x0000000101321791 in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #127    0x0000000101603981 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) [inlined] ()
    #128    0x000000010160397e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) ()
    #129    0x0000000101603cb9 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ())partial apply ()
    #130    0x0000000101603911 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () [inlined] ()
    #131    0x000000010160390e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #132    0x0000000101603be9 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> ()partial apply ()
    #133    0x0000000101603981 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) [inlined] ()
    #134    0x000000010160397e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) ()
    #135    0x0000000101603ca9 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ())partial apply ()
    #136    0x0000000101603911 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () [inlined] ()
    #137    0x000000010160390e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #138    0x0000000101603c09 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> ()partial apply ()
    #139    0x000000010132150c in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) ()
    #140    0x0000000101321711 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ())partial apply ()
    #141    0x00000001012b1729 in closure #1 in closure #1 in closure #1 in variable initialization expression of renameHistoryItemsMiddleware at /Users/ctm/Coding/minNV/State/State/Middlewares/RenameHistoryItemsMiddleware.swift:10
    #142    0x00000001012b301a in partial apply for closure #1 in closure #1 in closure #1 in variable initialization expression of renameHistoryItemsMiddleware ()
    #143    0x000000010132172c in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #144    0x0000000101321791 in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #145    0x0000000101603981 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) [inlined] ()
    #146    0x000000010160397e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) ()
    #147    0x0000000101603cb9 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ())partial apply ()
    #148    0x0000000101603911 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () [inlined] ()
    #149    0x000000010160390e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #150    0x0000000101603be9 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> ()partial apply ()
    #151    0x0000000101603981 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) [inlined] ()
    #152    0x000000010160397e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) ()
    #153    0x0000000101603ca9 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ())partial apply ()
    #154    0x0000000101603911 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () [inlined] ()
    #155    0x000000010160390e in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> () ()
    #156    0x0000000101603c09 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> ()partial apply ()
    #157    0x000000010132150c in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ()) ()
    #158    0x0000000101321711 in thunk for @escaping @callee_guaranteed (@in_guaranteed Action) -> (@out ())partial apply ()
    so this repeats over and over
    if a middleware dispatches an action, the whole stack is executed again, branching off there. Add some RxSwift code to the mix, and I am looking at 1530 entries in the stack trace for a very innocent action dispatched
    only one user reported a crash yesterday, with the main stack overflowing at 8MB. I don't know why it's just one user, and if this is related at all, but I worry that this approach doesn't scale indefinitely
    Christian Tietze
    @DivineDominion
    so I wonder if it would help to have 1 middleware registry object that requires its elements to provide a single, flat callback taking in all parameters of the 3 Middleware closures at once. It would at least reduce the noise in the stack trace. But would this ultimately address any potential stack-related problem? Like, filling 8MB at 16 bits per struct required 500.000 instances to be active at once; I don't know the footprint of closures in that regard. This kind of analysis is very new to me
    I'm aware that it's weird just 1 user is reporting this kind of crash, and if the design of my state would be flawed, it should crash for more people -- like the folks on Git reporting crashes on real devices but not the simulator
    This message was deleted
    Christian Tietze
    @DivineDominion
    So this is the experiment right now to flatten the nested callback calls. The stack depth is down from 1533 to 310 now.
    public protocol RegularMiddleware {
        /// Return `true` to invoke the `next` callback and continue processing. Return `false` to swallow the action.
        func runBeforeAndContinue(action: ReSwift.Action, dispatch: @escaping DispatchFunction, getState: @escaping () -> AppState?) -> Bool
        func runAfter(action: ReSwift.Action, dispatch: @escaping DispatchFunction, getState: @escaping () -> AppState?)
    }
    
    public class RegularMiddlewareRegistry {
        internal var middlewares: [RegularMiddleware]
    
        public init(middlewares: [RegularMiddleware]) {
            self.middlewares = middlewares
        }
    
        public func middlewareCallback(dispatch: @escaping DispatchFunction, getState: @escaping () -> AppState?)
            -> (_ next: @escaping DispatchFunction)
            -> (DispatchFunction)
        {
            return { next in
                return { action in
                    for middleware in self.middlewares {
                        guard middleware.runBeforeAndContinue(action: action, dispatch: dispatch, getState: getState) else {
                            // Simulate `next(action)` by continuing processing the stack, and not invoking `next` by aborting here completely
                            return
                        }
                    }
    
                    // If no middleware aborted the chain in pre-processing, continue with reducers
                    next(action)
    
                    for middleware in self.middlewares {
                        middleware.runAfter(action: action, dispatch: dispatch, getState: getState)
                    }
                }
            }
        }
    }
    Christian Tietze
    @DivineDominion
    I think this is a step in the direction of trampolining. Problem is that a Middleware can call next anytime. So I cannot optimize like I would for tail recursion
    Christian Tietze
    @DivineDominion
    Hm, I just experimented with chaining 10mio middleware-like function calls, and so far I have no problem at all with the stack
    Christian Tietze
    @DivineDominion
    aha, it works in a Playground, but not a Cocoa app
    Christian Tietze
    @DivineDominion
    Okay, so all my experiments that actually result in flattening the stack trace boil down to something like this: typealias Middleware = (beforeHandler: () -> Void, predicate: (Action) -> Bool, afterHandler: () -> Void)
    (all three closures would also get access to getState and dispatch, of course)
    predicate can be changed so you can exchange the action, e.g. (Action) -> Action
    but in this case, you have no equivalent of calling next multiple times. It's just 0 or 1 time.
    Question is: would this be acceptable?
    (I guess no)
    Christian Tietze
    @DivineDominion
    Folks, I have good news today. Last weeks Middleware experiments led me to a working inversion of subscriptions:
    Feedback would be very welcome!
    This implements an idea by @mjarvis from back in 2017, borrowing the "inverted" memory management model from RxSwift
    Håkon Bogen
    @haaakon
    Anyone know of a bigger scale project that uses ReSwift? I think the examples on the GitHub is a bit simple
    Open source project that is
    Christian Tietze
    @DivineDominion
    Maybe this, if the Todo/Counter examples don't suffice :) https://github.com/roosmaa/Octowire-iOS
    @haaakon
    Håkon Bogen
    @haaakon
    Not updated for 3 years, anyone know of any newer stuff?
    Christian Tietze
    @DivineDominion
    Don't dismiss it for its age: The ReSwift core didn't change much in the meantime
    Stefan van den Oord
    @svdo
    And that’s a very good thing in my book! :)
    Christian Tietze
    @DivineDominion
    @haaakon https://github.com/danbee/persephone uses ReSwift, too
    Xiaoyu Guo
    @MichaelGuoXY
    Hi guys, I'm new to ReSwift. I've seen this article about how to do App Routing https://www.raywenderlich.com/516-reswift-tutorial-memory-game-app#toc-anchor-012 and I know there is https://github.com/ReSwift/ReSwift-Router But I'm wondering if I can create a NavigationMiddleware which handles app routing based on the actions?
    From here https://redux.js.org/advanced/middleware I saw that "People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more."
    So I'm thinking that I can create some NavigationActions that will be handled by the NavigationMiddleware (which has the navigation controller / presenting view controller / tab bar controller)
    Malcolm Jarvis
    @mjarvis
    @MichaelGuoXY Yes, thats a common setup for routing as well.
    Michael Langford
    @langford
    You certainly can do routing in ReSwift...however sometimes maintaining sync with UIKit as far as "currently presented controller" is a lot harder than expected @MichaelGuoXY
    Anthony Maina
    @mainaaw
    Hey everyone, I've been using Reswift for some time now and I had a question regarding how to overload the default dispatch to return Any instead of Void. The question is posted here. Essentially, I need to pass in a middleware that returns Any and not only Void when creating my main appStore. If anyone could point me in the right direction, that would be much appreciated.
    Anthony Maina
    @mainaaw
    @DivineDominion I noticed that this change was made based off of this conversation and was wondering if you could provide more insight: ReSwift/ReSwift#175
    Malcolm Jarvis
    @mjarvis
    @mainaaw How are you intending to use that return value elsewhere? There is likely another way to achieve what you need in a more type-safe manner, without requiring a return value as described.
    Anthony Maina
    @mainaaw

    @mjarvis So the way my project is set up, I'm using promises. For example, here's the setup I would like to retrieve a sample user profile:

    public static func getUserProfile(id: Int) -> Thunk<Any> {
            return Thunk(
                body: { (dispatch, getState) in
                    _ = dispatch(ActionUserProfileGet(id: id))
    
                    let result: Promise<[String : Any]> = Promise { promise in
                        ReduxConfig.userSessionManager
                            .request(Router.getUserProfile(id: id))
                            .validate()
                            .responseJSON(completionHandler: { (dataResponse) in
                                switch dataResponse.result {
                                case .success(let value):
                                    guard let json = value as? [String : Any] else {
                                        promise.reject(UserError.malformedJson)
                                        return
                                    }
                                    promise.fulfill(json)
                                case .failure(let error):
                                    promise.reject(convertNetworkResponseError(error: error))
                                }
                            })
                    }
    
                    _ = result.done({ (json) in
                        _ = dispatch(ActionUserProfileGetSuccess(id: id, json: json))
                    }).catch { error in
                        let userProfileGetError = error as? UserError ?? .unknown
                        _ = dispatch(ActionUserProfileGetFailure(id: id, error: userProfileGetError))
                    }
                    return result
            }
            )
        }

    What I need is the result of the promise returned when I call this function, for example in the case of a similar setup for a login method:

     let result = reduxWorker.getStore().dispatch(action)
    
            //Created helper methods to allow for navigation testing
            if let promise = result as? Promise<[String : Any]> {
                promise.done { json -> Void in
                    self.loginSuccessful()
                }.catch { error in
                    self.loginFailure()
                }
            }

    Just for more context, I upgraded the project to ReSwift 5.0.0 and ReSwiftThunk 1.2.0 recently. Before that, we were on ReSwift 3.0.0 and this ReSwiftThunkVersion. Is it possible to achieve this in a type-safe manner as you mentioned?

    Malcolm Jarvis
    @mjarvis
    You can create the promise alongside the thunk, and return it as well:
    func foo() -> (Thunk, Promise) {
       let promise = Promise()
       let thunk = Thunk { ... promise.fulfill() ... }
       return (thunk, promise)
    }
    let (thunk, promise) = foo()
    dispatch(thunk)
    promise.done { ... }
    Anthony Maina
    @mainaaw
    Thanks for the response @mjarvis! Let me give it a shot
    Anthony Maina
    @mainaaw

    @mjarvis This was very helpful, thank you! So I tried this and I believe it should fix my problem. Only issue now is that for some reason the default createThunkMiddleware() doesn't seem to be executing the body of my thunk.

    I have my thunk defined as :

    let loginThunk = Thunk<Any> { dispatch, getState in
       ....promise.fulfill()....
            }

    And my middleware is the default createThunkMiddleware() which is:

    public func createThunkMiddleware<State>() -> Middleware<State> {
        return { dispatch, getState in
            return { next in
                return { action in
                    switch action {
                    case let thunk as Thunk<State>:
                        thunk.body(dispatch, getState)
                    default:
                        next(action)
                    }
                }
            }
        }
    }
    When I step through with the debugger, it executes until the case statement but doesn't execute the thunk.body(dispatch, getState) and skips to next(action) then moving on to the next middleware. Could it be because I initialized my Thunk with type <Any>?
    Malcolm Jarvis
    @mjarvis
    @mainaaw Yes, it could be the Any type -- perhaps try copying over the middleware and adding a case for Any? I thought there had been a test for that in the library though... If that is the issue, it would be worth creating a github issue for it.
    Anthony Maina
    @mainaaw
    Alright let me give it a shot, i'll report back here
    Anthony Maina
    @mainaaw
    Ah yes, creating a case for case let thunk as Thunk<Any>: got it to execute the body.
    I'll open a ticket for it
    Christian Tietze
    @DivineDominion
    Thanks!
    Stephen Kirkland
    @kylelol
    Hi everyone, are there any good open source resources for demonstrating a production ready iOS app using ReSwift?