UITableView with different cell state

Hello,

Right now when we want to deal with cell state we are using the cellForRowAt function for UITableViews.My question is how we can pass a store as datastore in UITableViewCell instead of array of objects?

There's a very simple example of a table view in the UIKit case studies app, which scopes a store for each cell: swift-composable-architecture/ListsOfState.swift at 6a5b8f276fdc5549172fc41ef3b33be883453079 · pointfreeco/swift-composable-architecture · GitHub

Thanks for the reply Stephen I saw this example but in my case I have one cell which contains a UIButton and from this UIButton I want to trigger an event for example:

viewStore?.send(.cellButtonTapped)

my main issue is that I want to pass the viewstore in cell and this must be done in cellForRowAt in order to manage the data cell

The demo cells have buttons that increment and decrement a counter for each specific row by sending actions through the view store. As long as you provide a store to the cell you should be able to scope it to send whatever action you need it to!

@stephencelis

I see that the cells' states, counters is declared in advance...

How would you do it if the table or collection's data source is a fetch results controller or a bottomless data source (using batching)?

While counters is declared in advance, it is completely mutable. This means you could fire off effects or feed actions into the store to load data (like a didScrollCloseToBottom action for loading the next page).

In the case of the fetch results controller it is a bit trickier :frowning:

the fetch results controller delegate will continually insert, update or move around cells when the managed object context is updated in the background.

Maybe I can send a command when the cell is created to initialise a new state and add it to a NSMapTable (it works like a dictionary with weak references) and keyed by the cell id... not sure this is the right approach.

@stephencelis I have the same problem as @mycroftcanner and svger!

Should I put my NSFetchResultsController in my environment?

What about my fetchRequest? Is it part of my state or my environment?

How do I create my cell's state in tableView(_:cellForRowAt:)?

Can I access the environment from my ViewControllers? In your case studies you keep the mainQueue in the environment.... in our viewControllers, should we access the mainQueue via the environment and how?

@stephencelis @Ariana

What about sending an action in tableView(_:cellForRowAt:) or tableView(_:didSelectRowAt:) with a closure parameter that will configure the cell once the state is created?

The action would use an effect to access the object for that row using environment.fetchResultsController.object(at:).

The reducer's forEach can derive it's state from a dictionary so I guess we can delete and recreate the cell's state in cellForRowAt after calling dequeueReusableCell(withIdentifier:for:).

I am actually using Texture's ASCollectionNode so I would want to create the state when my CellNode enters preload range or is already in Display or Visible range and get rid of the state when it leaves preload range.

I could also let the NSFetchResultsControllerDelegate update the table view by inserting, updating, moving and deleting view and when the delegate method controllerDidChangeContent(_:) is called, update the state using the fetch results controller's property fetchedObjects.

@stephencelis @mbrandonw I thought that other people using similar framework (ReSwift, rxFeedback, etc.) would have encountered the same problem.... However no-one seems to be using a FRC... and when they interface with Core Data they do it manually using naive fetch requests that will force the whole table or collection view to be reloaded every time there is an update. (NO FRC, no diffable data source, etc.)

If I use the FRC fetchedObjects and convert my entities to structs I will lose the benefits of faults (large objects can be represented by a fault instead, until they really are needed.) unless I just map fetchedObjects to their objectIDs and only keep the objectIDs in the state and create a state for a cell lazily when it is needed.

I am going to create some case studies for the different approaches and see how it goes.