ReactiveCocoa 问题
ReactiveCocoa Issue
我正在尝试在我的项目中使用 ReactiveCocoa 来处理 UITableView 的填充。
如果 none 可用,当我加载数据时,我想将 tableView.backgroundView
的 hidden
属性 设置为 false。这是我目前所拥有的:
func loadData() {
let dataSource = tableView.dataSource as! BlockedTableViewDataSource
let load = dataSource.load(currentUser) # RACSignal
load.map {
return ([=10=] as! [AnyObject]).count > 0
}.startWith(true).distinctUntilChanged().setKeyPath("hidden", onObject: tableView.backgroundView!)
load.subscribeError({ error in
println(error)
}, completed: {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
})
}
然而,这会出错,提示我需要等待网络请求完成。我正在使用 Parse 获取数据,但我认为我的 ReactiveCocoa 代码设置不正确并导致此错误。如果我注释掉 load.map...
部分,table 会按预期填充。
如何在 "Reactive Way" 中实现这一点?
更新 #1
这里是dataSource
的load
函数
func load(user: User) -> RACSignal {
return self.getBlocks(user).doNext {
self.blocks = [=11=] as! [Block]
}
}
private func getBlocks(fromUser: User) -> RACSignal {
let query = Block.query()!
query.whereKey("fromUser", equalTo: fromUser)
query.includeKey("toUser")
return query.rac_findObjects()
}
更新#2
2015-04-28 08:20:02.612 ohio[90547:2154845] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This query has an outstanding network connection. You have to wait until it's done.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010b840c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010bc5dbb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010b840b9d +[NSException raise:format:] + 205
3 ohio 0x0000000107facb1b -[PFQuery checkIfCommandIsRunning] + 77
4 ohio 0x0000000107facb71 -[PFQuery markAsRunning:] + 46
5 ohio 0x0000000107fad105 -[PFQuery _findObjectsAsync:after:] + 234
6 ohio 0x0000000107faf0a0 -[PFQuery findObjectsInBackgroundWithBlock:] + 288
7 ohio 0x0000000107d9532d _TFFE4ohioCSo7PFQuery15rac_findObjectsFS0_FT_CSo9RACSignalU_FGSQPSo13RACSubscriber__GSQCSo13RACDisposable_ + 205
8 ohio 0x0000000107d6639e _TTRXFo_oGSQPSo13RACSubscriber___oGSQCSo13RACDisposable__XFo_iGSQPS____iGSQS0___ + 30
9 ohio 0x0000000107d944c1 _TPA__TTRXFo_oGSQPSo13RACSubscriber___oGSQCSo13RACDisposable__XFo_iGSQPS____iGSQS0___ + 81
10 ohio 0x0000000107d663d4 _TTRXFo_iGSQPSo13RACSubscriber___iGSQCSo13RACDisposable__XFo_oGSQPS____oGSQS0___ + 36
11 ohio 0x0000000107d66418 _TTRXFo_oGSQPSo13RACSubscriber___oGSQCSo13RACDisposable__XFdCb_dGSQPS____aGSQS0___ + 56
12 ohio 0x0000000107eeacca __30-[RACDynamicSignal subscribe:]_block_invoke + 74
13 ohio 0x0000000107f35b8e -[RACSubscriptionScheduler schedule:] + 478
14 ohio 0x0000000107eeab9d -[RACDynamicSignal subscribe:] + 765
15 ohio 0x0000000107f28f1d -[RACSignal(Subscription) subscribeNext:error:completed:] + 1133
16 ohio 0x0000000107f004cc __32-[RACSignal(Operations) doNext:]_block_invoke + 396
17 ohio 0x0000000107eeacca __30-[RACDynamicSignal subscribe:]_block_invoke + 74
18 ohio 0x0000000107f35b8e -[RACSubscriptionScheduler schedule:] + 478
19 ohio 0x0000000107eeab9d -[RACDynamicSignal subscribe:] + 765
20 ohio 0x0000000107f2999e -[RACSignal(Subscription) subscribeError:completed:] + 766
21 ohio 0x0000000107dc5fdb _TFC4ohio26BlockedTableViewController8loadDatafS0_FCS_4UserT_ + 3083
22 ohio 0x0000000107dc6775 _TFC4ohio26BlockedTableViewController11viewDidLoadfS0_FT_T_ + 501
23 ohio 0x0000000107dc7702 _TToFC4ohio26BlockedTableViewController11viewDidLoadfS0_FT_T_ + 34
24 UIKit 0x000000010a142210 -[UIViewController loadViewIfRequired] + 738
25 UIKit 0x000000010a14240e -[UIViewController view] + 27
26 UIKit 0x000000010a167297 -[UINavigationController _startCustomTransition:] + 633
27 UIKit 0x000000010a1733bf -[UINavigationController _startDeferredTransitionIfNeeded:] + 386
28 UIKit 0x000000010a173f0e -[UINavigationController __viewWillLayoutSubviews] + 43
29 UIKit 0x000000010a2be715 -[UILayoutContainerView layoutSubviews] + 202
30 UIKit 0x000000011915093e -[UILayoutContainerViewAccessibility layoutSubviews] + 43
31 UIKit 0x000000010a091a2b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 536
32 QuartzCore 0x0000000109d12ec2 -[CALayer layoutSublayers] + 146
33 QuartzCore 0x0000000109d076d6 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
34 QuartzCore 0x0000000109d07546 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
35 QuartzCore 0x0000000109c73886 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242
36 QuartzCore 0x0000000109c74a3a _ZN2CA11Transaction6commitEv + 462
37 QuartzCore 0x0000000109c750eb _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 89
38 CoreFoundation 0x000000010b773ca7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
39 CoreFoundation 0x000000010b773c00 __CFRunLoopDoObservers + 368
40 CoreFoundation 0x000000010b769a33 __CFRunLoopRun + 1123
41 CoreFoundation 0x000000010b769366 CFRunLoopRunSpecific + 470
42 GraphicsServices 0x000000010cfc8a3e GSEventRunModal + 161
43 UIKit 0x000000010a011900 UIApplicationMain + 1282
44 ohio 0x0000000107d86df7 main + 135
45 libdyld.dylib 0x000000010c3c1145 start + 1
46 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
方法 rac_findObjects()
returns a cold signal. It means that each time someone subscribes to this signal, its side effects (that is, executing the underlying network request) will be repeated. And it seems that PFQuery
doesn't allow to send more than one simultaneous request,因此出现错误消息。
在您的情况下,您正在为 load
信号制作 两个 订阅,因为调用 setKeyPath
也会创建一个。所以网络请求被执行了两次,这导致了你发布的错误。
如链接 GitHub 问题中所建议,您可以使用 RACMulticastConnection
来确保副作用(网络请求)只执行一次,无论有多少订阅者。例如:
let load = dataSource.load(currentUser).publish().autoconnect()
我正在尝试在我的项目中使用 ReactiveCocoa 来处理 UITableView 的填充。
如果 none 可用,当我加载数据时,我想将 tableView.backgroundView
的 hidden
属性 设置为 false。这是我目前所拥有的:
func loadData() {
let dataSource = tableView.dataSource as! BlockedTableViewDataSource
let load = dataSource.load(currentUser) # RACSignal
load.map {
return ([=10=] as! [AnyObject]).count > 0
}.startWith(true).distinctUntilChanged().setKeyPath("hidden", onObject: tableView.backgroundView!)
load.subscribeError({ error in
println(error)
}, completed: {
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
})
}
然而,这会出错,提示我需要等待网络请求完成。我正在使用 Parse 获取数据,但我认为我的 ReactiveCocoa 代码设置不正确并导致此错误。如果我注释掉 load.map...
部分,table 会按预期填充。
如何在 "Reactive Way" 中实现这一点?
更新 #1
这里是dataSource
的load
函数
func load(user: User) -> RACSignal {
return self.getBlocks(user).doNext {
self.blocks = [=11=] as! [Block]
}
}
private func getBlocks(fromUser: User) -> RACSignal {
let query = Block.query()!
query.whereKey("fromUser", equalTo: fromUser)
query.includeKey("toUser")
return query.rac_findObjects()
}
更新#2
2015-04-28 08:20:02.612 ohio[90547:2154845] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This query has an outstanding network connection. You have to wait until it's done.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010b840c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010bc5dbb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010b840b9d +[NSException raise:format:] + 205
3 ohio 0x0000000107facb1b -[PFQuery checkIfCommandIsRunning] + 77
4 ohio 0x0000000107facb71 -[PFQuery markAsRunning:] + 46
5 ohio 0x0000000107fad105 -[PFQuery _findObjectsAsync:after:] + 234
6 ohio 0x0000000107faf0a0 -[PFQuery findObjectsInBackgroundWithBlock:] + 288
7 ohio 0x0000000107d9532d _TFFE4ohioCSo7PFQuery15rac_findObjectsFS0_FT_CSo9RACSignalU_FGSQPSo13RACSubscriber__GSQCSo13RACDisposable_ + 205
8 ohio 0x0000000107d6639e _TTRXFo_oGSQPSo13RACSubscriber___oGSQCSo13RACDisposable__XFo_iGSQPS____iGSQS0___ + 30
9 ohio 0x0000000107d944c1 _TPA__TTRXFo_oGSQPSo13RACSubscriber___oGSQCSo13RACDisposable__XFo_iGSQPS____iGSQS0___ + 81
10 ohio 0x0000000107d663d4 _TTRXFo_iGSQPSo13RACSubscriber___iGSQCSo13RACDisposable__XFo_oGSQPS____oGSQS0___ + 36
11 ohio 0x0000000107d66418 _TTRXFo_oGSQPSo13RACSubscriber___oGSQCSo13RACDisposable__XFdCb_dGSQPS____aGSQS0___ + 56
12 ohio 0x0000000107eeacca __30-[RACDynamicSignal subscribe:]_block_invoke + 74
13 ohio 0x0000000107f35b8e -[RACSubscriptionScheduler schedule:] + 478
14 ohio 0x0000000107eeab9d -[RACDynamicSignal subscribe:] + 765
15 ohio 0x0000000107f28f1d -[RACSignal(Subscription) subscribeNext:error:completed:] + 1133
16 ohio 0x0000000107f004cc __32-[RACSignal(Operations) doNext:]_block_invoke + 396
17 ohio 0x0000000107eeacca __30-[RACDynamicSignal subscribe:]_block_invoke + 74
18 ohio 0x0000000107f35b8e -[RACSubscriptionScheduler schedule:] + 478
19 ohio 0x0000000107eeab9d -[RACDynamicSignal subscribe:] + 765
20 ohio 0x0000000107f2999e -[RACSignal(Subscription) subscribeError:completed:] + 766
21 ohio 0x0000000107dc5fdb _TFC4ohio26BlockedTableViewController8loadDatafS0_FCS_4UserT_ + 3083
22 ohio 0x0000000107dc6775 _TFC4ohio26BlockedTableViewController11viewDidLoadfS0_FT_T_ + 501
23 ohio 0x0000000107dc7702 _TToFC4ohio26BlockedTableViewController11viewDidLoadfS0_FT_T_ + 34
24 UIKit 0x000000010a142210 -[UIViewController loadViewIfRequired] + 738
25 UIKit 0x000000010a14240e -[UIViewController view] + 27
26 UIKit 0x000000010a167297 -[UINavigationController _startCustomTransition:] + 633
27 UIKit 0x000000010a1733bf -[UINavigationController _startDeferredTransitionIfNeeded:] + 386
28 UIKit 0x000000010a173f0e -[UINavigationController __viewWillLayoutSubviews] + 43
29 UIKit 0x000000010a2be715 -[UILayoutContainerView layoutSubviews] + 202
30 UIKit 0x000000011915093e -[UILayoutContainerViewAccessibility layoutSubviews] + 43
31 UIKit 0x000000010a091a2b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 536
32 QuartzCore 0x0000000109d12ec2 -[CALayer layoutSublayers] + 146
33 QuartzCore 0x0000000109d076d6 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
34 QuartzCore 0x0000000109d07546 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
35 QuartzCore 0x0000000109c73886 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242
36 QuartzCore 0x0000000109c74a3a _ZN2CA11Transaction6commitEv + 462
37 QuartzCore 0x0000000109c750eb _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 89
38 CoreFoundation 0x000000010b773ca7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
39 CoreFoundation 0x000000010b773c00 __CFRunLoopDoObservers + 368
40 CoreFoundation 0x000000010b769a33 __CFRunLoopRun + 1123
41 CoreFoundation 0x000000010b769366 CFRunLoopRunSpecific + 470
42 GraphicsServices 0x000000010cfc8a3e GSEventRunModal + 161
43 UIKit 0x000000010a011900 UIApplicationMain + 1282
44 ohio 0x0000000107d86df7 main + 135
45 libdyld.dylib 0x000000010c3c1145 start + 1
46 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
方法 rac_findObjects()
returns a cold signal. It means that each time someone subscribes to this signal, its side effects (that is, executing the underlying network request) will be repeated. And it seems that PFQuery
doesn't allow to send more than one simultaneous request,因此出现错误消息。
在您的情况下,您正在为 load
信号制作 两个 订阅,因为调用 setKeyPath
也会创建一个。所以网络请求被执行了两次,这导致了你发布的错误。
如链接 GitHub 问题中所建议,您可以使用 RACMulticastConnection
来确保副作用(网络请求)只执行一次,无论有多少订阅者。例如:
let load = dataSource.load(currentUser).publish().autoconnect()