Local shared environment

Duplicate of this GitHub issue

I'm using UIKit, AVFoundation & ReactiveSwiftComposableArchitecture but the question is related to the architecture itself. I'd like to share the environment with a viewController and store. My VC has a SZAVPlayer (UIView), which is responsible for all the AV-stuff and I'd like to have a client for this object to put it in the environment, but the player object is created later than the viewController, which is initialized by the store.

As far as I understand – I don't have to keep SZAVPlayer object in a view hierarchy, but I have to handle CGImage output, which is not Equatable so it's not convenient to put it in State. I'm gonna try implementing the conformance myself. But maybe someone can give me advice on how to do it in a better way. :slightly_smiling_face:

@stephencelis

As a potential answer, though, you may wanna wrap the image data in your own type that you can conform, and then you may be able to use memcmp for a quick implementation.

@maximkrouk

Container type is a nice idea, but is it ok to compare each frame of video output? Maybe it worth losing some state change data and making container type instances always equal?

I came up to this implementation for Not-Equatable types

public struct EquatableContainer<Content>: Equatable {
    public var content: Content
    private var compare: (Content, Content) -> Bool
  
    public init(_ content: Content, compare: @escaping (Content, Content) -> Bool) {
        self.content = content
        self.compare = compare
    }
  
    public static func ==(lhs: Self, rhs: Self) -> Bool {
        lhs.compare(lhs.content, rhs.content) && rhs.compare(rhs.content, lhs.content)
    }
}

_ = EquatableContainer<CGImage?> = .init(.none, compare: ==)

And then I understood that CGImage is Equatable xD


Anyway I think that sharing objects with ViewControllers may be a generic topic, so I'll leave it here. If anyone has best-practices or questions, now there is a place to share some :slightly_smiling_face:

I've got an issue with integrating VideoPlayer. At first, I setup CGImage output to leave it in State type, but somehow it is leaked (by store, I guess and it is probably a swift bug, but I'm not sure how to reproduce and don't have time now to investigate), so I removed that output and I'd like to expose an AVPlayer from VideoPlayerClient to viewController's AVPlayerLayer. For now, I have to pass and map my environments twice: in reducers and in viewControllers, it seems kinda okay from the architecture perspective, like ViewEnvironment. But sometimes environments can be created with local objects (I mean protocol replacement, where the client is just a functional interface for a single object), usually in forEach reducers for example. Such local dependencies can't be shared without generalization client with id keys (client which manages many objects, providing access with AnyHashable ids).

So the question is: maybe it's worth storing environments in stores, not just in the reducer function?
As an idea, we may introduce some kind of the ComposableEnvironment protocol to separate the general environment, from the stuff we'd like to expose.

protocol ComposableEnvironment {
    associatedtype ExposedContainer
    var exposedContainer: ExposedContainer { get }
}
extension ComposableEnvironment { var exposedContainer: Void { () } }

which in my case is only AVPlayer for video output.

I came to ComposableVideoPlayer with a resettable store and player state is persistent in parent states, setting of store is based on ViewController lifecycle

Store management relies on ComposableCore

AVPlayer design notes and basic docs can be found here AVPlayer

Terms of Service

Privacy Policy

Cookie Policy