ReactiveCocoa:创建一个将地图应用于观察者的信号
ReactiveCocoa: creating a signal that applies a map over an observer
据我了解,RACSubject
相当于 ReactiveCocoa 4 是 Observer
class。
我想将一个信号和一个观察者链接在一起,以便信号发送事件,将映射操作应用于发送给观察者的事件。
在 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]
}
这看起来是个糟糕的解决方案,因为
internalSignal
应该是私有的,但需要声明 public 以便将其与 Signal 的管道相匹配
someSignal
每次需要时都会计算,因此,即使可以重复使用相同的信号。也不能声明为 let
常量。
您可以像 ObjC 一样初始化 init
中的成员...
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 允许您使用改变它的值(没有 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])"
}
}
}
据我了解,RACSubject
相当于 ReactiveCocoa 4 是 Observer
class。
我想将一个信号和一个观察者链接在一起,以便信号发送事件,将映射操作应用于发送给观察者的事件。
在 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]
}
这看起来是个糟糕的解决方案,因为
internalSignal
应该是私有的,但需要声明 public 以便将其与 Signal 的管道相匹配someSignal
每次需要时都会计算,因此,即使可以重复使用相同的信号。也不能声明为let
常量。
您可以像 ObjC 一样初始化 init
中的成员...
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 允许您使用改变它的值(没有 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])"
}
}
}