ReactiveCocoa:创建一个通过观察者应用地图的信号

时间:2016-05-19 12:45:46

标签: objective-c swift reactive-cocoa reactive-cocoa-4

据我所知,ReactiveCocoa 4的RACSubject等价物是Observer类。 我希望将一个信号和一个观察者链接在一起,以便信号将发送映射操作的事件发送给发送给观察者的事件。 在Obj-C中它看起来像这样:

// ViewModel.h

@interface ViewModel

@property (readonly) RACSubject *someAction; //expects e.g. int values
@property (readonly) RACSignal *someSignal; //sends e.g. string values

@end

// ViewModel.m

//redeclaring the signal and action as readwrite

@implementation

- (id)init {
  _someAction = [RACSubject subject];
  _someSignal = [_someAction map:^id(NSNumber *index) {
     return "Some string based on index passed in";
  }];
}

@end

现在有人将值推送到someAction时,someSignal将触发包含派生值的事件。 如何在Swift中实现相同的效果?

到目前为止,我能够做到的是:

public class ViewModel: NSObject {
    public let (internalSignal, someAction) = Signal<Int, NoError>.pipe()
    public var someSignal: Signal<String, NoError> {
        get {
            return self.internalSignal.map({ [unowned self](index: Int) -> String in
                return "Some string value based on \(self.someArray[index])"
            })
        }
    }
    public let someArray = [1, 2, 3, 4, 5]
}

这看起来像是一个糟糕的解决方案,因为

  1. internalSignal应该是私有的,但需要声明为公开才能将其与信号管道相匹配
  2. 因此,每次需要时计算
  3. someSignal,即使相同的信号可以反复使用。也不能声明为let常量。

1 个答案:

答案 0 :(得分:1)

您可以在init中初始化成员,就像ObjC ...

一样
public class ViewModel: NSObject {
    private let internalSignal: Signal<Int, NoError>
    public let someAction: Observer<Int, NoError>
    public let someSignal: Signal<String, NoError>

    override init() {
        (internalSignal, someAction) = Signal<Int, NoError>.pipe()
        someSignal = internalSignal.map { index in
            "Some string value based on \(index)"
        }
        super.init()
    }
}

对于someSignal,您还可以使用lazy initialization,这允许该成员引用self

public class ViewModel: NSObject {
    private let internalSignal: Signal<Int, NoError>
    public let someAction: Observer<Int, NoError>
    public private(set) lazy var someSignal: Signal<String, NoError> =
        self.internalSignal.map { [unowned self] index in
            "Some string value based on \(self.someArray[index])"
        }

    override init() {
        (internalSignal, someAction) = Signal<Int, NoError>.pipe()
        super.init()
    }
}

与第一段代码不同,lazy-var仅在使用someSignal之前初始化,而不是在ViewModel初始化时初始化。

此外,由于它是var,Swift允许你使用mutate它的值(没有lazy let这样的东西)。我们可以使用private(set)来限制权限,但这不会阻止您在某处意外写入self.someSignal = ...

或者,你可以让someSignal隐式解包,并手动初始化:

public class ViewModel: NSObject {
    private let internalSignal: Signal<Int, NoError>
    public let someAction: Observer<Int, NoError>
    public private(set) var someSignal: Signal<String, NoError>!

    override init() {
        (internalSignal, someAction) = Signal<Int, NoError>.pipe()
        super.init()
        someSignal = internalSignal.map { [unowned self] index in
            "Some string value based on \(self.someArray[index])"
        }
    }
}