Mobile Development 13 min read

Applying Flux Architecture to iOS Video Editing: Plugin‑Based Design and Event Management

The article explains how an iOS video‑editing app adopts a Flux‑style, single‑direction data flow by extracting a shared playback controller and encapsulating features as weak‑referenced plugins that register with a central dispatcher, enabling predictable state management and extensible, decoupled UI interactions.

Baidu Geek Talk
Baidu Geek Talk
Baidu Geek Talk
Applying Flux Architecture to iOS Video Editing: Plugin‑Based Design and Event Management

This article describes how the video‑editing application on iOS adopts the Flux architecture pattern to handle complex interactions and improve extensibility.

1. Architecture background – Video‑editing tools involve many UI regions (preview, timeline, undo/redo, control panels) that must respond to gestures and keep state synchronized. To achieve a predictable, single‑direction data flow, the team borrowed Flux concepts and the topological idea of a directed acyclic graph, centralising event management.

2. Playback preview reuse – A common preview/playback controller (baseVC) is extracted so that multiple features (general editing, quick cut, theme templates) can share the same logic. The baseVC structure is illustrated in the original diagram.

3. Functional module reuse via plugins – Each sub‑feature (sticker, text, filter, etc.) is encapsulated as a BDTZEditPlugin protocol implementation. Plugins receive references to the controller, main view, timeline, streaming context, and live window via weak properties, eliminating singletons and deep callbacks.

protocol BDTZEditPlugin: NSObjectProtocol {
    var editViewController: BDTZEditViewController? { get set }
    var mainView: BDTZEditLevelView? { get set }
    var timeline: Timeline? { get set }
    var streamingContext: StreamingContext? { get set }
    var liveWindow: LiveWindow? { get set }
    func pluginDidLoad()
    func pluginDidUnload()
}

Plugins are added to the baseVC with addPlugin(_:) , which injects the required references and registers the plugin with the dispatcher.

func addPlugin(_ plugin: BDTZEditPlugin) {
    plugin.editViewController = self
    plugin.mainView = self.view
    plugin.liveWindow = liveWindow
    plugin.streamingContext = streamingContext
    plugin.timeline = timeline
    if plugin.conforms(to: BDTZEditViewControllerDelegate.self) {
        pluginDispatcher.add(subscriber: plugin as! BDTZEditViewControllerDelegate)
    }
    plugin.pluginDidLoad()
}

4. Event and state management – The article reviews four iOS state‑notification mechanisms (Delegate, KVO, NotificationCenter, Block) and explains why a centralized Flux‑style flow is preferable. The Flux components are defined as:

Dispatcher – distributes actions to stores/subscribers.

Store – holds data and business logic.

Action – triggers the dispatcher.

View – renders UI based on store data.

Implementation details include a generic weak‑proxy dispatcher and a concrete BDTZActionDispatcher class.

class WeakProxy: Equatable {
    weak var value: AnyObject?
    init(value: AnyObject) { self.value = value }
    static func == (lhs: WeakProxy, rhs: WeakProxy) -> Bool { lhs.value === rhs.value }
}

open class BDTZActionDispatcher
: NSObject {
    fileprivate var subscribers = [WeakProxy]()
    public func add(subscriber: T) { ... }
    public func remove(subscriber: T) { ... }
    public func dispatch(_ invocation: @escaping (T) -> ()) { ... }
}

Plugins communicate via the BDTZEditActionSubscriber protocol, allowing any plugin to react to actions such as selection, addition, or deletion of media assets.

@objc protocol BDTZEditActionSubscriber {
    @objc optional func update(action: BDTZEditAction)
}

Example: a sticker plugin sends a BDTZClipSeleteAction , and other plugins receive it through the dispatcher, updating their own state accordingly.

// APlugin sends action
func sendAction(model: Any?) {
    let action = BDTZClipSeleteAction(event: .selected, type: .sticker, actionTarget: model)
    editViewController?.pluginDispatcher.dispatch { $0.update?(action: action) }
}

// BPlugin receives action
extension BDTZTrackPlugin: BDTZEditActionSubscriber {
    func update(action: BDTZEditAction) {
        if let action = action as? BDTZClipSeleteAction { handleSelectActionDoSomething() }
    }
}

5. Summary – While pure Flux introduces extra boilerplate and migration effort, the team found the single‑direction flow valuable for managing the relationship between view controllers and plugins. The approach keeps the UI layer simple, allows each plugin to adopt any internal architecture (MVC, MVVM, etc.), and centralises event propagation.

Future considerations include UI layering issues, multithreading in the dispatcher, plugin dependency ordering, and action explosion mitigation.

architectureiOSpluginVideo EditingFluxEvent Management
Baidu Geek Talk
Written by

Baidu Geek Talk

Follow us to discover more Baidu tech insights.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.