所以现在有了swift,ReactiveCocoa人员已经在3.0版本中为swift重写了它
此外,还有另一个名为RxSwift的项目.
我想知道人们是否可以添加关于两个框架的设计/ api /哲学的差异的信息(请在SO的精神中,坚持真实的事情,而不是关于哪个是"最佳"的意见)
[注意StackOverflow mods:这个问题有确切的答案,答案是两个框架之间的差异.我认为这也是SO的主题
首先,我阅读ReadMe的最初印象是:
从RxSwift4开始,Variable移动到Deprecated.swift标记Variable未来可能的弃用.建议的替代方案Variable是BehaviorRelay.在发布这个问题时,由于我在网上找不到太多的教程,BehaviorRelay我在SO中发布了这样一个基本问题.
假设我正在进行webService调用,并且我收到一块JSONArray数据,在逐个解析JSON对象时我更新了我的Variable的value属性
这是我的变量声明
var myFilter = Variable<[MyFilterModel]>([MyFilterModel(data: "{:}")])
Run Code Online (Sandbox Code Playgroud)
每次我将变量更新为获取新元素时
myFilter.value.append(newModel)
Run Code Online (Sandbox Code Playgroud)
当Variable绑定到CollectionView时,collectionVie将立即使用新添加的对象更新其UI.
使用BehaviorRelay的问题
现在我的声明看起来像
var myFilter = BehaviorRelay<[MyFilterModel]>(value: [MyFilterModel(data: "{:}")])
Run Code Online (Sandbox Code Playgroud)
但最大的问题myFilter.value是readOnly.很明显
myFilter.value.append(newModel)
Run Code Online (Sandbox Code Playgroud)
不是解决方案.我发现我可以使用accept.
但是现在当我尝试解析响应中的每个元素并更新myFilter的值时
self?.expertsFilter.accept(newModel)
Run Code Online (Sandbox Code Playgroud)
上面的陈述给出了错误引用
无法将NewModel的值转换为预期的争论类型[NewModel]
显然,它期待一个数组而不是一个单独的元素.
解决方法:
解决方案1:
因此,一个解决方案是在临时数组中累积所有响应并且一旦完成触发 self?.expertsFilter.accept(temporary_array)
解决方案2:
如果我必须onNext在解析每个元素时向订阅者发送事件,我需要将self?.expertsFilter的值复制到new Array,将新解析的元素添加到它并返回新数组.
解决方案3:
摆脱BehaviorRelay并使用BehaviorSubject/PublishSubject
前两个声音令人沮丧,因为可能需要在解析每个元素时触发UI我不能等到解析整个响应.因此,解决方案1显然没有多大用处.
第二种解决方案更加可怕,因为它每次发送onNext事件时都会创建一个新数组(我知道它是临时的并且将被释放).
题:
因为BehaviorRelay被提议作为Variable进入两难的替代方案,我accept正确使用?有没有更好的方法来解决它?
请帮忙
目前我正在努力让RxSwift工作.我想创建一个自定义的Observable.但我认为我做错了什么.
我已经将我做的事情提炼到这个最小的样本:
import Foundation
import RxSwift
class Example
{
let exampleObservable : Observable<String> = Observable.create { (observer) in
observer.on(.Next("hello"))
observer.on(.Completed)
return AnonymousDisposable { }
}
let exampleObserver : AnyObserver<String>?
func run()
{
self.exampleObserver = exampleObservable.subscribeNext({ (text) -> Void in
print(text)
})
}
}
let ex = Example()
ex.run()
Run Code Online (Sandbox Code Playgroud)
它是否正确?在run方法中,subscribeNext方法由XCode自动完成.
但是当我运行它时,我得到以下编译错误:
Cannot Invoke 'substribeNext' with an argument list of type ((String) -> Void)
Run Code Online (Sandbox Code Playgroud) 我是否需要[weak self]在RXSwift subscribeNext闭包内使用?
我有代码:
searchController.searchBar.rx_text.throttle(0.2, scheduler: MainScheduler.instance).subscribeNext { searchText in
self.viewModel.searchForLocation(searchText)
}.addDisposableTo(DisposelBag.sharedDisposelBag.disposeBag)
Run Code Online (Sandbox Code Playgroud)
我是否需要修改它以便[weak self]在闭包开始时有一个捕获列表?像这样:
searchController.searchBar.rx_text.throttle(0.2, scheduler: MainScheduler.instance).subscribeNext { [weak self] searchText in
self?.viewModel.searchForLocation(searchText)
}.addDisposableTo(DisposelBag.sharedDisposelBag.disposeBag)
Run Code Online (Sandbox Code Playgroud) 我们试图尽可能地使用Swift结构.我们也在使用RxSwift,它具有关闭的方法.当我们有一个结构创建一个引用self的闭包时,它会创建一个强大的引用循环.
import Foundation
import RxSwift
struct DoesItLeak {
var someState: String = "initial value"
var someVariable: Variable<String> = Variable("some stuff")
let bag = DisposeBag()
mutating func someFoo() {
someVariable.subscribeNext { person in
self.someState = "something"
}
.addDisposableTo(bag)
}
}
Run Code Online (Sandbox Code Playgroud)
我怎么知道这个?如果我创建100,000个DoesItLeak对象并在每个对象上调用someFoo(),我相信我有100,000个具有强引用周期的对象.换句话说,当我摆脱包含这些对象的DoesItLeak数组时,对象会留在内存中.如果我不调用someFoo(),则没有问题.
变量是一个类.所以,我可以通过使用xcode的Instruments的Allocations和Variable <String>中的过滤来看到这个内存问题
如果我尝试使用[弱自我],如下所示,我得到一个编译器错误:
someVariable.subscribeNext { [weak self] person in
Run Code Online (Sandbox Code Playgroud)
编译错误是"弱不能应用于非类型"
在实际/非示例代码中,我们通过self访问方法和变量,这是一个内存问题.
如何在保持DoesItLeak结构的同时解决此内存问题?
谢谢你的帮助.
我有一个Thing对象数组,我想ConvertedThing使用返回的异步函数转换为对象Observable<ConvertedThing>.
我想创建一个Observable<[ConvertedThing]>在所有转换完成后发出一个值.
如何实现这一目标?任何帮助非常感谢!
我对你可以调用observables的方法subscribeOn和observeOn方法有点困惑.我读了几篇帖子,其中一个人说这没关系,只是在他的例子中使用了东西而其他人说它确实很重要.所以这是我的问题:
例如:
self.remoteService.rxGetAllLanguages()
.observeOn(MainScheduler.instance)
.subscribeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Background))
.subscribe({ e in
switch e {
case .Next(let element):
case .Error(let e):
DDLogError("Error in \(e)")
case .Completed:
DDLogDebug("Completed")
}
}
).addDisposableTo(self.disposeBag)
Run Code Online (Sandbox Code Playgroud)
这是一样的:
self.remoteService.rxGetAllLanguages()
.subscribeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Background))
.observeOn(MainScheduler.instance)
.subscribe({ e in
switch e {
case .Next(let element):
case .Error(let e):
DDLogError("Error in \(e)")
case .Completed:
DDLogDebug("Completed")
}
}
).addDisposableTo(self.disposeBag)
Run Code Online (Sandbox Code Playgroud)
如果我正确理解它们的机制是不同的.第一个在主线程上完成所有工作,第二个在另一个线程上完成所有工作,然后调度回主线程.但我很坚定,所以有人可以帮我清楚一下吗?
假设我有一个即时消息应用程序,每次消息到达时都会发出哔声.我想要debounce发出哔哔声,但我想播放第一条消息的嘟嘟声而不是下面的消息(在2秒的时间内).
另一个例子可能是:我的应用程序发送了输入通知(因此我正在聊天的用户可以看到我正在键入消息).我想在开始输入时发送打字通知,但只在X秒间隔发送新的通知,所以我不会为我输入的每个字符发送输入通知.
这有意义吗?那有运营商吗?可以用现有的运营商来实现吗?
这是我的第一个例子的代码.我现在正在解决它debounce,但它并不理想.如果我以1秒的间隔收到1000条消息,则在最后一条消息到达之前它不会播放声音(我想在第一条消息上播放声音).
self.messagesHandler.messages
.asObservable()
.skip(1)
.debounce(2, scheduler: MainScheduler.instance)
.subscribeNext { [weak self] message in
self?.playMessageArrivedSound()
}.addDisposableTo(self.disposeBag)
Run Code Online (Sandbox Code Playgroud)
谢谢!
我正试图绕过黄金法则(如果有的话):
何时使用BehaviorSubject?
和
何时使用PublishSubject?
他们之间的区别非常明显
有很多种科目.对于这个特定的要求,PublishSubject运行良好,因为我们希望从它停止的位置继续序列.所以假设事件1,2,3在(B)中发出,在(A)连接之后我们只想看到4,5,6.如果我们使用ReplaySubject,我们会看到[1,2,3],4, 5,6; 或者如果我们使用了BehaviorSubject,我们会看到3,4,5,6等等(来源:如何考虑RxJava中的主题(第1部分))
我已经看到它Subject用于两个上下文(至少),UI上下文和监听器上下文.
例如这里一个BehaviorSubject被使用,并且他们为什么使用它显然Subject并没有Observable,但我已经改变了BehaviorSubject到PublishSubject,但应用程序的行为仍然是相同的.
他们为什么要创建项目领域BehaviorSubject而不是PublishSubject?
见下面的代码.
class ViewController4: UIViewController {
var disposeBag = DisposeBag()
let v = Variable(0)
override func viewDidLoad() {
super.viewDidLoad()
v.asObservable()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
v.value = 1
}
}
Run Code Online (Sandbox Code Playgroud)
当它运行时,它将打印出来
0
1
Run Code Online (Sandbox Code Playgroud)
但是,我不希望它继续运行0,或者说0只是用于启动的值v.我能这样做吗?或者我必须在我使用它的时间点推迟代码?