I have an associated object on a view extension that contains an array (a mutable array in this case).
var queue: NSMutableArray {
get {
if let queue = objc_getAssociatedObject(self, &Key.queue) as? NSMutableArray {
return queue
} else {
let queue = NSMutableArray()
objc_setAssociatedObject(self, &Key.queue, queue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return queue
}
}
}
I would like to transform NSMutableArray into a Swift array but I cannot figure out how to do. This will prevent me to perform quite ugly casting. Any suggestion?
The
NSMutableArrayhere is a reference type. The consequence of this is that the moment you hand somebody a reference to your view object'squeue, your view object loses all control of it. The recipient of the reference can rearrange items, delete all items, etc., and your view wouldn't know about it until next time it tried reading it.Generally speaking, this sort of implicit data sharing has been found to be a bad idea, because it breaks encapsulation, and complicates systems, because you can no longer reason locally about code, because there's always the threat that another thread has a reference to your aliased object, and is changing it under your feet.
This model isn't compatible with Swift's value-types, such as
Array. Ifqueuewere anArray<T>, every person who accessed it would get back their own value. Semantically, these copies are all completely isolated from each other, and there's no way in which a mutation done through one reference can cause an effect that's observable via the other reference.If you wanted to faithfully preserve the reference semantics of your current code, you would need a mechanism to listen for changes to the
NSMutableArray, and update every individualArray<T>that was derived from it. This isn't really practical, nor is it a good idea.Here's what I would do:
Make the interface more explicitly transactional. More than likely, you can hide the
queueentirely. Make it private, and have your view expose public methods likepushandpop.I would use a type-safe Swift wrapper to tuck away associated object sets/gets, which can do type checking and casting automatically behind the scenes. The new property wrapper feature is perfect for this.
Extract out a separate
Queue<T>data structure.Array<T>by itself doesn't make for a good queue, because removing at the start hasO(n)time complexity. There are lots of data structure libraries out there, I would use one of their queues instead.