Search code examples
iosswiftgrand-central-dispatchsynchronousdispatch-queue

Closure argument passed as @noescape to Objective-C has escaped


I'm trying to use a resource wrapper for a thread safe access. In my implementation, awaitedValue field performs a synchronous read of resource through a serial queue. For some reason, whenever I try to read this property, my app crashes with an error, which doesn't really make sense with synchronous code.

class ThreadsafeResource<T> {
    private let accessorsQueue: DispatchQueue
    private var resource: T
    
    //MARK: Initializers
    init(_ resource: T) {
        self.resource = resource
        self.accessorsQueue = DispatchQueue(label: "X")
    }

    //MARK: Synchronous access
    var awaitedValue: T {
        accessorsQueue.sync(flags: .inheritQoS) { // Point where my app crashes.
            self.resource
        }
    }
}

I've tried reading it from both main and global(.utility) queues – same result. And Asynchronous calls to resource work fine.

Error screen and code example


Solution

  • The problem manifests itself when you supply the flags. If you remove that, the problem goes away.

    Looking at the stack trace, it’s failing in _syncHelper, which declares the closure as escaping when it’s not really, AFAICT. This rendition of _syncHelper is called when you supply flags and it’s not empty.

    I'll file a bug report, as it would seem to be incorrect for _syncHelper to make that parameter as @escaping.

    For now, I'd suggest you simply remove the flags parameter or consider a different synchronization mechanism.