简体   繁体   中英

Weird intermittent crash on synchronous start of an NSOperation on main thread

I have a system here that renders itself in bits that get stitched together. Sometimes those bits are rendered in an background threads, but sometimes when latency of feedback is really important those bits are rendered synchronously on the main thread.

This code is called on the main thread, in a method named createPatchView , and patchView.createRenderingOperation() returns a subclass of NSOperation that does the rendering. The async version works fine, the operation queue picks up the job and handles it in the background. But the other branch where we want to render it right now is giving me intermittent crashes.

// Figure out when to render it
if async {
    // Add the patch rendering job to the tile rendering queue.
    tiledView.renderingQueue.addOperation(patchView.createRenderingOperation())
} else {
    // Render and install the patch right now on the main thread for maximum responsiveness.
    patchView.createRenderingOperation().start() // <-- CRASHES HERE
}

Here's the crash detail:

Signal: SIGSEGV: SEGV_ACCERR at 0x10
Reason: objc_msgSend() selector name: observationInfo

崩溃堆栈

And I've yet to replicate this with the debugger attached, which is frustrating, but the crash logs are clearly coming in.

So, all on the main thread, the render operation is created. Then we call start() on that operation to do it right now. So now before it gets to any of my code in the operations main() method, some internal key value observation handler kicks off and calls observationInfo on some internal object that's somehow invalid? At this point it feels like I'm trying to understand the inner workings of a black box that doesn't work anymore.

Have I missed some pitfall of running an NSOperation outside of an NSOperationQueue ?

UPDATE: Is it bad form to call patchView.createRenderingOperation().main() instead? I suppose in this case, I don't need to keep track of the status of the operation in a thread safe way. I just need it to do it's work and continue execution from there. In theory, this should avoid whatever is crashing nested inside the logic of the start() method.

Refactor the code out of main and put it somewhere else. Call that code from your operation's main and whenever you want it to happen.

Have you tried adding the operation to the main queue. Will that also crash?

if async { 
    ....
} else {
    OperationQueue.main.addOperation(patchView.createRenderingOperation())
}

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