ReSwift - 如何在视图

时间:2017-08-05 17:01:39

标签: ios swift redux reswift

我正在尝试在我的ios项目中使用ReSwift,并且有一个关于如何处理视图中的更改的问题。我发现在我应用新状态提出的更改之前我需要知道旧状态是什么。在我的反应项目中使用redux时,我从来不需要知道我的旧状态是什么。

我的特殊用例是,我正在使用Overlay屏幕构建CameraView。从应用程序的任何地方说一个ViewController我可以创建一个CameraView并触发它通过触发一个动作从其中打开一个UIImagePickerController。这是一些代码:

//ViewController:

class MainViewController: UIViewController {
    var cameraView: CameraView?
    @IBOutlet weak var launchCameraButton: UIButton!

    init() {
        cameraView = CameraView(self)
    }

    @IBAction func launchCameraButtonClicked(_ sender: Any) {
       store.dispatch(OpenCameraAction())
    }

}

//CameraActions
struct OpenCameraAction: Action {}
struct CloseCameraAction: Action {}

//CameraState
struct CameraState {
    var cameraIsVisible: Bool
}

func cameraReducer(state: CameraState?, action: Action) -> CameraState {
    let initialState = state ?? CameraState()

    switch action {
        case _ as OpenCameraAction:
            return CameraState(cameraIsVisible: true)
        default:
            return initialState
    }    
}

//CameraView

class CameraView: StoreSubscriber {
    private var imagePicker: UIImagePickerController?
    weak private var viewController: UIViewController?

    init(viewController: UIViewController) {
        self.viewController = viewController
        super.init()
        imagePicker = UIImagePickerController()
        imagePicker?.allowsEditing = true
        imagePicker?.sourceType = .camera
        imagePicker?.cameraCaptureMode = .photo
        imagePicker?.cameraDevice = .rear
        imagePicker?.modalPresentationStyle = .fullScreen
        imagePicker?.delegate = self
        imagePicker?.showsCameraControls = false

        store.subscribe(self) { subscription in
           subscription.select { state in
                state.camera
           }
        }
    }

    func newState(state: CameraState?) {
        guard let state = state else {
            return
        }
        if state.cameraIsVisible {
            self.open()
        } else if !state.cameraIsVisible {
            self.close()
        }
    }

    func open() {
        if let imagePicker = self.imagePicker {
            self.viewController?.present(
                imagePicker,
                animated: true
            )
        }
    }

    func close(){
         self.imagePicker?.dismiss(animated: true)
    }

}

以上是打开和关闭相机的所有代码。当我们添加更多操作(例如禁用或启用闪存)时,我的困惑开始了。我需要在视图中处理其他状态转换。

我的行动现在增长到:

struct OpenCameraAction: Action {}
struct CloseCameraAction: Action {}
struct FlashToggleAction: Action {}

我的州现在看起来像这样:

struct CameraState {
    var cameraIsVisible: Bool
    var flashOn: Bool
}
// not showing reducer changes as it self explanatory 
// what the state changes will be for my actions.

我的观点是并发症开始的地方。如果用户启用了闪存并且我正在响应FlashToggleAction状态更改,那么如何在视图中处理状态更改?

func newState(state: CameraState?) {
        guard let state = state else {
            return
        }

        // this will get triggered regardless of whether
        // a change in the flash happened or not.
        self.toggleFlash(state.flashOn)

        // now the below lines will be executed even though 
        // the only change was a flash on action. 
        //I don't want my camera to opened again or closed.
        if state.cameraIsVisible {
            self.open()
        } else if !state.cameraIsVisible {
            self.close()
        }
    }

我现在如何回应变化?我能想到处理这个问题的唯一方法是存储对旧状态的引用并自己比较差异。

1 个答案:

答案 0 :(得分:2)

在这种情况下,我的第一个问题是:您是否需要在应用状态中处理此问题?是否有人需要通知相机状态变化?如果没有,请将其作为UI层中的实现细节。让biew控制器自己打开相机,拍摄结果图像,然后发送DoStuffWithImage(imageFromCam)

这只是一个一般建议:不要在ReSwift中为UIKit特定的交互建模。建模有趣的数据流。然后让UI组件朝着这个目标努力。

您真正的问题提示:如何对商店订阅者进行分区?

目前,您使用单个订户处理与相机相关的问题。但你也可以为每个可独立修改的组件写1个用户。像闪光切换一样。然后你只需要检查闪光灯切换的状态变化,忽略其他设置;虽然在这种情况下闪光切换的东西可以利用知道他的相机是否真的开启 - 你重置闪光灯状态,当相机关闭以照顾",有效地移动"闪光灯和相机激活"逻辑到减速器。

我可以提出更多方法和想法,但最终归结为:应用程序中的组件是什么?相机状态控制是应用程序状态的核心部分,还是只是一分钟的细节?在设计过程的早期权衡这一点有助于找到合适的解决方案。