Closed
Description
With RAC4 rc1 .observeOn(UIScheduler())
doesn't work as expected for me (I didn't test older versions though):
let currentRoute = MutableProperty<MKRoute?>(nil)
func observe() {
self.currentRoute.producer.observeOn(UIScheduler()).startWithNext { route in
// Works:
// dispatch_async(dispatch_get_main_queue(), {
// if let route = route {
// self.mapView.addOverlay(route.polyline, level: .AboveRoads)
// }
// })
// Crashes in -[VKRasterOverlayTileSource init] with EXC_BAD_ACCESS:
if let route = route {
self.mapView.addOverlay(route.polyline, level: .AboveRoads)
}
}
}
currentRoute
is set from the callback in MKDirections calculateDirectionsWithCompletionHandler
. When I wrap the addOverlay
call into a dispatch_async(dispatch_get_main_queue()
, as shown in the commented version, it works as expected and doesn't crash.
Any hints on what I'm doing wrong?
Activity
kommen commentedon Dec 28, 2015
I've created a minimal sample project demonstrating my issue: http://www.komendera.com/bugs/rac/UISchedulerTest.zip
kommen commentedon Dec 28, 2015
The problem seems to be that
MKMapView
wants to have itsaddOverlay
called on the main queue, not only the main thread, so theUIScheduler
'sNSThread.isMainThread()
check to see if it can skip scheduling is not sufficient here.I found this tweet, which might be related?:
https://twitter.com/jspahrsummers/status/669198976835592192
NachoSoto commentedon Dec 28, 2015
Main queue and main thread are the same thing. The optimization that you linked to regarding scheduling is an implementation detail, but regardless, both will be invoked on the same thread.
What's the crash exactly? The bad access seems to indicate that something else is at play here. I'm AFK right now but I can test the sample project when I get home :)
kommen commentedon Dec 28, 2015
I thought so too.
Here's a simple Playground demonstrating the issue without ReactiveCocoa:
https://gist.github.com/kommen/524ca1ce72df1f5d0b96
The crash log from the Playground looks like this (the framework stack trace is the same for the crashes with RAC):
laptobbe commentedon Dec 30, 2015
I ran into the same problem, I was trying to scroll a collection view programmatically and the scroll was not happening. I tried dispatching async to main and that fixed the problem for me. I created another version of ate UISchedular that always dispatches async to main. This probably has other implications that I am unaware of but it solved the problem for me right now.
ikesyo commentedon Dec 30, 2015
That is
QueueScheduler.mainQueueScheduler
.kommen commentedon Dec 30, 2015
Yes,
QueueScheduler.mainQueueScheduler
is what I'm using now instead of UIScheduler, which works.I suppose there's no way of knowing beforehand weither
UIScheduler
is safe or if one should useQueueScheduler.mainQueueScheduler
?laptobbe commentedon Dec 30, 2015
@ikesyo Thanks for the tip, will use that instead 👍🏼
kommen commentedon Jan 9, 2016
@NachoSoto I contacted Apple DTS, they confirmed it is a bug in MapKit. But they also cautioned that the pattern of
dispatch_sync
and theisMainThread
will likely run into more issues like this and the one reported by @laptobbe above.They also explicitly stated that main queue and the main thread are not the same thing, but are have subtle differences, as shown in my demo app.
kommen commentedon Jan 9, 2016
For what its worth, I dug into what's the issue in my example:
[VKRasterOverlayTileSource init]
calls+[VKDispatch defaultDispatch]
on the current dispatch queue, which in my example is theorg.reactivecocoa.ReactiveCocoa.SignalProducer.buffer
serial queue.There
dispatch_get_specific("com.apple.vectorkit.dispatch.homequeue");
is called, which returns null, because the key wasn't set on that queue, but only on the main queue. This eventually leads to a call todispatch_retain
passing null in-[VKRasterOverlayTileSource init]
which crashes.adriantofan commentedon Apr 22, 2016
Hello, I've run in to the same issue. Can I help fixing it ?
For me it means that UIScheduler is not safe and I have to use QueueScheduler.mainQueueScheduler for UI stuff in order to not dig up unknown bugs.
Why just not make UIScheduler work on the main queue?
Thank you
mdiep commentedon May 19, 2016
We want to avoid a scheduler hop. That adds a delay that can have unfortunate side effects, and it makes debugging much more difficult.
I'm not sure there's anything we can do about this. You may just need to use the main queue scheduler in some instances.
NSThread.isMainThread()
#2912ikesyo commentedon May 19, 2016
I've just submitted a PR for this: #2912. Could you try that branch and confirm whether the fix works as expected? @kommen @laptobbe @adriantofan