Reswift: Data is not saved

Created on 28 May 2017  路  18Comments  路  Source: ReSwift/ReSwift

When I rerun my app in Xcode all the values that were in the store are not saved.
How do I reload it ?

Most helpful comment

That sounds like session settings. The built-in UserDefaults can do that, too.

Whatever persistence mechanism you pick: you will create a substate object that contains all you need, read the defaults in on launch, then set the state according to the UserDefaults's values.

A naive sketch:

import ReSwift

struct AppState: StateType {
    var session: Session?
    var isSessionValid: Bool { return session != nil }
}

struct Session {
    var tokens: [String]
    var idForWhatever: String
}

struct ChangingSession: Action {
    let newSession: Session
}

func reduceChangingSession(_ action: ChangingSession, state: AppState) -> AppState {
    var state = state
    state.session = action.newSession
    return state
}
struct LoggingOut: Action {}

func reduceLoggingOut(_ action: LoggingOut, state: AppState) -> AppState {
    var state = state
    state.session = nil
    return state
}

For everything else we simply know too little. Any goes beyond the scope of an issue here, I'd say, because it concerns your app design. (If you need more code assistance, posting the approaches on StackOverflow might be more beneficial for everyone.)

It boils down to "save the stuff however you like, then store.dispatch(ChangingSession(newSession: ...)) at launch with the stuff you read from disk".

All 18 comments

@MaxToyberman you might want to take a look at https://github.com/realm/realm-cocoa

@mzgnr thanks

@mzgnr is it bad practice to define my state as class instead of struct ? to use realm I need to extend the Object class from Realm .
currently this is my declaration:

struct EndUserState: StateType {
}

need to change it to :

class EndUserState: StateType {
}

@MaxToyberman i'm not sure if its a bad practice or not. But i use struct even if i use realm in project.

@mzgnr actually i can use structs ... but the problem is that my code will be duplicated...

It does not matter if you use value types (struct) or reference types (class) from ReSwift's point of view. But with reference types, you get all the dangers of mutable state, for example: a store subscriber can change a value in its subscription method that affects all other subscribers in the chain. (Of course you can always keep a solid convention, like "never mutate state in subscribers", but that promise to yourself can be broken under stress.)

I would not make the Realm objects part of the state, though. Realm is nice, but still invasive. As mentioned recently on Fatal Error by @khanlou and @cdzombak (https://fatalerror.fm/episodes/2017/4/24/27-core-data). So you should separate persistence from temporary app state: load date from Realm, create state objects the way that suits you best, then persist changes when necessary.

You might also want to look at https://github.com/ReSwift/ReSwift-Recorder in case you don't need a full-blown database and just want to let users continue where they left off.

@DivineDominion Good advice, totally agree with the danger of having reference type in state.
I have Realm in my project for persisting data. I recently found out about ReSwift and trying to use it in my project but it just felt wrong. I feel like it's a lot of duplication between realm data and the state data structure, and I have to make sure they are in sync. Because I persist state in Realm data too, in case the app crashes or user kill the app at any time, i don't end up with a corrupted state. I am thinking about using realm only, just make it unidirectional and follow the flux/redux pattern. Any thoughts on that?

The reasoning makes sense, so why not! :) There are smaller unidirectional flow dispatch libraries in case you want to ensure your UI actions are routed through a single trusted point (reducer) and then the changes are persisted to Realm in the process.

@DivineDominion so what alternative you can offer to realm ? ,I am new to swift ,I don't have a lot of information to persist. I just want to reload my app and reload my data.

@MaxToyberman maybe you should check RxSwift ?

@mzgnr I don't see how RxSwift helps with saving the app state :man_shrugging:

@MaxToyberman I _do_ get it right, don't I? You want to save the app state so the user can continue later. Plist files can work, too. Or local SQLite. Depends on your data.

I personally would use Realm. If you don't want to have your code duplicated (even though if you want real decoupling, this kind of duplication is usually unavoidable), treat your Realm instance as you'd do with a web service. Create a way to serialise and deserialise your state and use a simple ReSwift middleware to serialise and store the state when needed. Upon store creation, read the saved data and deserialise it, if any, and pass this initial state to the store.

Ok folks, but you have to have a _reason_ to add the complexity of a web-based store / database abstraction like Realm. Especially for a (Swift) beginner, when for all that we know the state could be a simple array of strings that can be dumped to a file. The OP did not say a word about sync. (Even then you could make a point for dumping to a file _inside an iCloud container._)

Sorry, I agree that maybe there are simpler options to persist the data, depending on the complexity of the project, and where you want to put the focus. I do think that using a middleware for this is the way to go with ReSwift, independently of the persisting layer, and I also wouldn't recommend a library like ReSwift to a beginner.

@danielmartinprieto I have worked With Redux in React-Native so I found a boilerplate that is using ReSwift and just started working with it.
I am using this : https://github.com/NghiaTranUIT/iOS-Awesome-Starter-Kit

@DivineDominion I need to save data like "_id" and some "tokens" so that I can use them in my http requests later. for example : receive an fcm with an action to get the location of the device.
when I want to send the location to the server I need to specify this id.

I don't need to save entire objects

That sounds like session settings. The built-in UserDefaults can do that, too.

Whatever persistence mechanism you pick: you will create a substate object that contains all you need, read the defaults in on launch, then set the state according to the UserDefaults's values.

A naive sketch:

import ReSwift

struct AppState: StateType {
    var session: Session?
    var isSessionValid: Bool { return session != nil }
}

struct Session {
    var tokens: [String]
    var idForWhatever: String
}

struct ChangingSession: Action {
    let newSession: Session
}

func reduceChangingSession(_ action: ChangingSession, state: AppState) -> AppState {
    var state = state
    state.session = action.newSession
    return state
}
struct LoggingOut: Action {}

func reduceLoggingOut(_ action: LoggingOut, state: AppState) -> AppState {
    var state = state
    state.session = nil
    return state
}

For everything else we simply know too little. Any goes beyond the scope of an issue here, I'd say, because it concerns your app design. (If you need more code assistance, posting the approaches on StackOverflow might be more beneficial for everyone.)

It boils down to "save the stuff however you like, then store.dispatch(ChangingSession(newSession: ...)) at launch with the stuff you read from disk".

@MaxToyberman you need anything else? Or can we close the issue?

Thank you very much !

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dolanmiu picture dolanmiu  路  7Comments

ColinEberhardt picture ColinEberhardt  路  3Comments

adamhongmy picture adamhongmy  路  3Comments

dolanmiu picture dolanmiu  路  3Comments

nferruzzi picture nferruzzi  路  10Comments