Search code examples
swiftthread-confinement

Is there a elegant way to confine a class to a thread?


I have a class which I want to confine to a thread. To be precise I want it's void returning methods to be accessed on a certain thread or serial queue created by the class privately. To acheive this I looked at the NSManagedObjectContext API as a reference. There is a perform(block:() -> Void) method which can do this.

This comes with a code pattern that I am a bit uncomfortable. The user of this API needs to make calls to the object in the block of the perform(block:() -> Void) method. Is there a more elegant solution wherein I can declare that all methods and properties are confined to this particular thread. So essentially the user can access the methods but the internal operation happen on the intended thread.

I know the option where I can go to each method and dispatch work of that method into the intended thread. But this is an additional overhead to write the dispatch code.


Solution

  • Approach:

    Use a property wrapper

    Code:

    @propertyWrapper
    struct QueueVariable<T> {
    
        private var _value  : T
        private let queue   : DispatchQueue
    
        var wrappedValue : T {
    
            get {
                queue.sync { _value }
            }
    
            set {
                queue.sync { _value = newValue }
            }
        }
    
        init(value: T,
             queue: DispatchQueue = DispatchQueue(label: "sync queue")) {
            _value      = value
            self.queue  = queue
        }
    }
    
    class Test {
    
        @QueueVariable(value: 100, queue: DispatchQueue(label: "aaa"))
        var a1
    
        @QueueVariable(value: "aaa")
        var a2
    }
    

    Invoking

    Either pass the dispatch queue, or a new one would be generated.

    let t1 = Test()
    
    t1.a1 += 5
    
    print(t1.a1)
    print(t1.a2)