iosswiftrunloopweak

Can I use RunLoop for realtime object observing in Swift?


I have a Process object (is kind of Model). Inside a process, I have an array of tuples

var listeners: [(WeakContainer<AnyObject>, (S) -> ())]

WeakContainer handles a weak ref inside. I need to remove an element from the listeners array when Conainer's value becomes nil. My code looks like this:

class Process<S> {
    
    typealias Handler = (S) -> ()
    typealias Listener = (container: Weak<AnyObject>, handler: StateHandler)
    
    var listeners: [Listener] = []
    private let runLoop = RunLoop()
    
    init() {
        runLoop.run(mode: .default, before: .now)
        runLoop.perform { [weak self] in
            self?.state.listeners.removeAll {
                $0.container.value == nil
            }
        }
    }
    
}

Is it correct usage of RunLoop for my targets or not? Why? I will be grateful if you propose a more suitable alternative for my case (tracking for the object becomes nil).


Solution

  • There is a NSMapTable collection which is flexible for configuring with various memory retaining policy.

    Here is an example how to store Handler object with a weak key object. Handler will be retained until key exist, and the pair will be removed from the collection on key delete.

    class Handler<Action> {
        let action: Action
        init(_ action: Action) {
            self.action = action
        }
    }
    
    var listeners = NSMapTable<AnyObject, Handler<(S)->Void>> (keyOptions: [.weakMemory, .objectPointerPersonality],
                                                               valueOptions: .strongMemory)