简体   繁体   中英

ReactiveCocoa Issue

I'm attempting to use ReactiveCocoa in my project to handle the population of a UITableView.

When I load the data if none is available, I want to set the hidden property of tableView.backgroundView to false. Here's what I have so far:

func loadData() {
    let dataSource = tableView.dataSource as! BlockedTableViewDataSource
    let load = dataSource.load(currentUser) # RACSignal

    load.map {
        return ($0 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()
    })
}

This however errors out saying that I need to wait for the network request to finish. I'm using Parse to fetch the data but I'm thinking that my ReactiveCocoa code just isn't set up correctly and is causing this error. If I comment out the load.map... portion the table populates as expected.

How would one going about implementing this in the "Reactive Way"?

Update #1

Here is the load function of the dataSource

func load(user: User) -> RACSignal {
    return self.getBlocks(user).doNext {
        self.blocks = $0 as! [Block]
    }
}

private func getBlocks(fromUser: User) -> RACSignal {
    let query = Block.query()!
    query.whereKey("fromUser", equalTo: fromUser)
    query.includeKey("toUser")

    return query.rac_findObjects()
}

Update #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

The method 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 , hence the error message.

In your case you are making two subscriptions for the load signal, because calling setKeyPath also creates one. So the networks request gets executed twice, which results in the error you posted.

As suggested in the linked GitHub issue, you can use RACMulticastConnection to ensure that the side effects (the network request) are executed only once, no matter how many subscribers there are. For example:

let load = dataSource.load(currentUser).publish().autoconnect()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM