I have a similar use case, but with SwiftUI. One of key principle I've tried to follow is to avoid storing reference types in TCA app state. This implies storing value types which can be accessed by the view store and passed as an identifier to something on the SwiftUI / UIKIt end to request the corresponding reference types (images videos, etc) that can be displayed in the UI.
For example, an AssetClient could be created that operated asynchronously, in an Effect context, to create / edit / download images locally, then return value type identifiers that refer to them when the operations are completed. A new list state can be generated with a new row view which now includes the new value identifier, which could be resolved when the row is redisplayed, etc. This could either be a URL or, in the case of PhotoKit, an asset identifier, etc. If you're using SwiftUI, you could pass this resolver in the environment. With UIKIt, you could use some other dependency injection framework to provision the UI. Both the TCA client and UI client would call into PhotoKit in the live content via async methods to perform the required work.
Test-wise, you could create a mock that just checks if the correct identifier was received. Hypothetically, you might be able to use the same client that implements two separate protocols in both the live and mock cases.
I've just started on this strategy with images. An attachment client uses Kingfisher to asynchronously download and display images related to CoreData entities that have related images.This is bridged using KFCache. When an image is local, I use an async client endpoint to write that to the KF cache, then return its identifier. If it's remote, this same async endpoint to download the asset and write it into the same cache. In both cases the cache identifier is a sendable value type that can be passed into the UI and loaded via KF asynchronously.
This is performed as an effect to prevent the front end from performing the conditional local remote logic, knowing details about Core Data (when image data is stored locally in as legacy binary property) or has a URL that refers to a remote image on a server. Those details are abstracted away by simply accessing the cache. Actions are used to kick off requesting a cache load via an identifier, which calls into the TCA client, preloads the cache, returns the identifier, etc.
However, if everything is local in PhotoKit, there might not be any work to abstract into an Effect. The front end could just use the Asset ID value type from the view store to asynchronously request the photo to be loaded, etc.