Swift 单选按钮逻辑,具有反应性,避免死锁

Swift 单选按钮逻辑,具有反应性,避免死锁,swift,frp,reactive-cocoa-4,Swift,Frp,Reactive Cocoa 4,我的目标是使用ReactiveCocoa实现单选按钮。这意味着我有一个子viewModels数组,一次只能有一个处于选定状态。我还希望能够在需要时快速切换到多选,但我的问题是单选。当我试图清除以前选择的项时,会出现死锁。下面的代码将给出以下错误: -[NSLock lock]: deadlock (<NSLock: 0x7fc64233e180> 'org.reactivecocoa.ReactiveCocoa.Signal') 2016-06-09 04:05:08.731 ios

我的目标是使用ReactiveCocoa实现单选按钮。这意味着我有一个子viewModels数组,一次只能有一个处于选定状态。我还希望能够在需要时快速切换到
多选
,但我的问题是
单选
。当我试图清除以前选择的项时,会出现死锁。下面的代码将给出以下错误:

-[NSLock lock]: deadlock (<NSLock: 0x7fc64233e180> 'org.reactivecocoa.ReactiveCocoa.Signal')
2016-06-09 04:05:08.731 ios_samples[92288:26027579] *** Break on _NSLockError() to debug.
-[NSLock lock]:死锁('org.reactivecocoa.reactivecoa.Signal')
2016-06-09 04:05:08.731 ios_示例[92288:26027579]***中断_NSLockError()以进行调试。
我不确定我是不是把这一切都搞错了。请帮忙

代码示例:

// MAIN METHOD
let model = Model(selectionType: .Single)

model.children[0].toggleState()
model.children[1].toggleState() // deadlocks here

print("selected:\(model.selectedChildren.value.filter { $0.isSelected }.map { $0.name }), count: \(model.totalSelected.value)")


// TYPES
enum SelectionType { case Single, Multi }

class Model {
    let children = [ChildModel(name: "child1"), ChildModel(name: "child2")]
    let totalSelected = MutableProperty<Int>(0)
    let selectedChildren = MutableProperty<[ChildModel]>([])

    init(selectionType: SelectionType) {

        let aggregateProducer = SignalProducer(values: children.map { $0.selectedSignal.producer })
        .flatten(.Merge)

        func singleSelectChildrenProducer() -> SignalProducer<[ChildModel], NoError> {
            return SignalProducer { emitter, disposable in
                aggregateProducer.startWithNext { state in
                    self.children
                        .filter { $0.isSelected && $0.name != state.childModel.name }
                        .forEach { $0.clearState() /* SOURCE OF DEADLOCK */ }

                    emitter.sendNext(state.childModel.isSelected ? [state.childModel] : [])
                }
            }
        }

        func multiSelectChildrenProducer() -> SignalProducer<[ChildModel], NoError>{
            return SignalProducer { emitter, disposable in
                aggregateProducer.startWithNext { _ in
                    let allSelectedChildren = self.children.filter { $0.isSelected }
                    emitter.sendNext(allSelectedChildren)
                }
            }
        }

        let selectionProducer = selectionType == .Multi
            ? multiSelectChildrenProducer()
            : singleSelectChildrenProducer()

        selectionProducer.startWithSignal { signal, disposable in
            totalSelected <~ signal.map { $0.count }
            selectedChildren <~ signal
        }
    }
}

class ChildModel {
    let name: String
    var selectedSignal: MutableProperty<ChildModelState>!

    init(name: String) {
        self.name = name
        selectedSignal = MutableProperty<ChildModelState>(ChildModelState(childModel: self, state: false))
    }

    var isSelected: Bool { return selectedSignal.value.state }

    func toggleState() {
        selectedSignal.value = ChildModelState(childModel: self, state: !selectedSignal.value.state)
    }

    func clearState() {
        selectedSignal.value = ChildModelState(childModel: self, state: false)
    }
}

struct ChildModelState {
    let childModel: ChildModel
    let state: Bool
}
//MAIN方法
让模型=模型(selectionType:.Single)
model.children[0]。toggleState()
model.children[1].toggleState()//此处存在死锁
打印(“选定:\(model.selectedChildren.value.filter{$0.isSelected}.map{$0.name}),计数:\(model.totalSelected.value)”
//类型
枚举选择类型{大小写单一,多}
类模型{
let children=[ChildModel(名称:“child1”)、ChildModel(名称:“child2”)]
让totalSelected=MutableProperty(0)
让selectedChildren=MutableProperty([])
初始化(selectionType:selectionType){
让aggregateProducer=SignalProducer(值:children.map{$0.selectedSignal.producer})
.flant(.Merge)
func singleSelectChildrenProducer()->SignalProducer{
返回信号发生器{发射器,可在
aggregateProducer.startWithNext{状态在中
自我保护儿童
.filter{$0.isSelected&&$0.name!=state.childModel.name}
.forEach{$0.clearState()/*死锁源*/}
emitter.sendNext(state.childModel.isSelected?[state.childModel]:[])
}
}
}
func multiSelectChildrenProducer()->SignalProducer{
返回信号发生器{发射器,可在
aggregateProducer.startWithNext{uu}in
让allSelectedChildren=self.children.filter{$0.isSelected}
发射器.sendNext(所有选定的子项)
}
}
}
让selectionProducer=selectionType==.Multi
?多选儿童生产者()
:singleSelectChildrenProducer()
selectionProducer.startWithSignal{signal,可随意使用
全选
// MAIN METHOD
let model = Model(selectionType: .Multi)
model.children[0].tapEvent.bind(SignalProducer(value: Void()))
model.children[1].tapEvent.bind(SignalProducer(value: Void()))

print("selected:\(model.selectedChildren.value.filter { $0.isSelected }.map { $0.name }), count: \(model.totalSelected.value)")

// TYPES
enum SelectionType { case Single, Multi }

class Model {
    let children = [ChildModel(name: "child1"), ChildModel(name: "child2")]
    let totalSelected = MutableProperty<Int>(0)
    let selectedChildren = MutableProperty<[ChildModel]>([])

    init(selectionType: SelectionType) {
        // watch events and update state properties
        let allTapProducer = SignalProducer(values: children.map { $0.tapEvent.producer }).flatten(.Merge)
        allTapProducer.startWithNext { child in
            if selectionType == .Single {
                self.children
                    .filter { $0.isSelected && $0.name != child.name }
                    .forEach { $0.clearState() }
            }
            child.toggleState()
        }

        //watch state properties and bind to other state properties
        SignalProducer(values: children.map { $0.selectedSignal.producer })
            .flatten(.Merge)
            .map { _ in self.children.filter { $0.isSelected } }
            .startWithSignal { signal, disposable in
                totalSelected <~ signal.map { $0.count }
                selectedChildren <~ signal
        }
    }
}

class ChildModel {
    let name: String
    var selectedSignal = MutableProperty<Bool>(false)
    var tapEvent: UIEventSignal<ChildModel>!

    init(name: String) {
        self.name = name
        tapEvent = UIEventSignal<ChildModel>(sender: self)
    }

    var isSelected: Bool { return selectedSignal.value }

    func toggleState() {
        selectedSignal.value = !self.selectedSignal.value
    }

    func clearState() {
        selectedSignal.value = false
    }
}

class UIEventSignal<T> {
    private let property = MutableProperty<T?>(nil)
    let sender: T

    init(sender: T) {
        self.sender = sender
    }

    func bind(uiSignalProducer: SignalProducer<Void, NoError>) {
        property <~ uiSignalProducer.map { [weak self] _ in self?.sender }
    }

    var producer: SignalProducer<T, NoError> {
        return property.producer.filter { $0 != nil }.map { $0! }
    }
}