导读:为了应对视频编辑类工具应用复杂的交互,度咔iOS借鉴了Flux架构模式的设计思想,参考有向无环图的拓扑概念,将事件进行集中化管理,从开发体验上实现了舒适清爽、容易驾驭的“单向流”模式;在这种调度模式下,事件的变化和追踪变得清晰可预测,并且显著的增加了业务的可扩展性。
全文6882字,预计阅读时间18分钟。
protocol BDTZEditPlugin: NSObjectProtocol {
// 组织控制器
var editViewController: BDTZEditViewController? { get set }
// 所有添加到控制器View上的控件 加到这个View上,解决层级问题
var mainView: BDTZEditLevelView? { get set }
// 编辑场景的时间轴实体,由轨道组成,可以有多个视频轨道和音频轨道,由视频轨道决定长度
var timeline: Timeline? { get set }
// 流媒体上下文 包含时间线、预览窗口、采集、资源包管理等相关信息集合的对象
var streamingContext: StreamingContext? { get set }
// 视频预览窗口控件
var liveWindow: LiveWindow? { get set }
/// 插件初始化
func pluginDidLoad()
/// 插件卸载
func pluginDidUnload()
}
func addPlugin(_ plugin: BDTZEditPlugin) {
plugin.pluginWillLoad()
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()
}
func removePugin(_ plugin: BDTZEditPlugin) {
plugin.pluginWillUnload()
plugin.editViewController = nil
plugin.mainView = nil
plugin.liveWindow = nil
plugin.streamingContext = nil
plugin.timeline = nil
if plugin.conforms(to: BDTZEditViewControllerDelegate.self) {
pluginDispatcher.remove(subscriber: plugin as! BDTZEditViewControllerDelegate)
}
plugin.pluginDidUnload()
}
基本的MVC数据流
class WeakProxy: Equatable {
weak var value: AnyObject?
init(value: AnyObject) {
self.value = value
}
static func == (lhs: WeakProxy, rhs: WeakProxy) -> Bool {
return lhs.value === rhs.value
}
}
open class BDTZActionDispatcher<T>: NSObject {
fileprivate var subscribers = [WeakProxy]()
public func add(subscriber: T) {
guard !subscribers.contains(WeakProxy(value: subscriber as AnyObject)) else {
return
}
subscribers.append(WeakProxy(value: subscriber as AnyObject))
}
public func remove(subscriber: T) {
let weak = WeakProxy(value: subscriber as AnyObject)
if let index = subscribers.firstIndex(of: weak) {
subscribers.remove(at: index)
}
}
public func contains(subscriber: T) -> Bool {
var res: Bool = false
res = subscribers.contains(WeakProxy(value: subscriber as AnyObject))
return res
}
public func dispatch(_ invocation: @escaping(T) -> ()) {
clearNil()
subscribers.forEach {
if let subscriber = $0.value as? T {
invocation(subscriber)
}
}
}
private func clearNil() {
subscribers = subscribers.filter({ $0.value != nil})
}
}
@objc protocol BDTZEditViewControllerDelegate: BDTZEditViewLifeCycleDelegate, StreamingContextDelegate, BDTZEditActionSubscriber {
// BDTZEditViewLifeCycleDelegate 控制器声明周期
// StreamingContextDelegate 预览编辑能力回调
// BDTZEditActionSubscriber plugin之间的通讯协议
}
public class BDTZEditViewController: UIViewController {
// 实例化的 BDTZEditViewControllerDelegate
var pluginDispatcher = BDTZEditViewControllerDelegateImp()
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
pluginDispatcher.dispatch { subscriber in
subscriber.editViewControllerViewDidAppear?()
}
}
public override func viewDidLoad() {
super.viewDidLoad()
/***省略部分代码**/
setupPlugins()
//放最后调用
pluginDispatcher.dispatch { subscriber in
subscriber.editViewControllerViewDidLoad?()
}
}
/***...**/
/// seek进度回调
func didSeekingTimelinePosition(_ timeline: Timeline!, position: Int64) {
pluginDispatcher.dispatch { subscriber in
subscriber.didSeekingTimelinePosition?(timeline, position: position)
}
}
/***...**/
}
@objc protocol BDTZEditAction {
}
@objc protocol BDTZEditActionSubscriber {
@objc optional func update(action: BDTZEditAction)
}
//APlugin
func sendAction(model: Any?) {
let action = BDTZClipSeleteAction.init(event: .selected, type: .sticker, actionTarget: model)
editViewController?.pluginDispatcher.dispatch({ subscriber in
subscriber.update?(action: action)
})
}
//BPlugin
extension BDTZTrackPlugin: BDTZEditActionSubscriber {
func update(action: BDTZEditAction) {
if let action = action as? BDTZClipSeleteAction {
handleSelectActionDoSomething()
}
}
}
参考链接