Isn't there toll free bridging between a Swift Array and an NSArray? It would make a lot of sense for the performance characteristics of the two being the same if that were the case.
Yeah and swapping to a C array isn't that simple in Swift. It seems easier to just have objective c code and call that from Swift when needed.
Actually, a Swift array is pretty much identical to a C array. You get an unsafe pointer to that array and treat it exactly as it was one. NSArray on the other hand is toll-free bridged to a CFArray.
The current "solution" is to keep the array a Swift array, then in any performance critical code simply cast that into an unsafe pointer and work with that directly as if it was C array.
There's bridging, but it's not toll-free. You have to convert between them, which is pretty slow. Toll-free bridging means that no conversion is necessary, e.g. you can take a CFArray and just treat it like an NSArray and everything still works with no conversion.
Conversion may or may not be slow, depending on the elements involved. Specifically, if you're converting from Array<T> to NSArray where T is a class of @objc protocol type, it's guaranteed to be O(1). Converting from other types (such as Array<Int>) will do an O(n) copy, as it has to bridge each element (e.g. Int would bridge to NSNumber).
Conversely, treating any NSArray as an Array is always just a call to -copyWithZone (which is O(n) for mutable arrays and O(1) for immutable arrays), although the docs say that upon the first element access it type-checks the elements of the array (though presumably converting to [AnyObject] is always free).
The conversion is only supposed to happen once, but there was a bug (don't know if it is fixed yet, it was discovered quite a while ago), which made the Swift <-> ObjC NSDictionary conversion to be performed each time an access was made.
Can you give some more information? This is the first I've heard of that. The only thing that comes to mind that would explain this sort of behavior is if you actually make a copy of the Dictionary first and then access that copy; since it's a copy, the conversion would presumably invoke the normal copy-on-write behavior and make a copy of the backing storage, while leaving the original Dictionary un-converted. In that case, any subsequent copy + access would have to re-convert. And if that's what's going on, then that sounds like expected behavior, not a bug.
An example of what I'm talking about would be something like
let dict = self.someDictionary // dict is a copy, not a reference
let x = dict["foo"] // this would then convert
let y = dict["bar"] // but this wouldn't
If you mean that the `let y = dict["bar"]` would convert as well, then I'm a bit skeptical, because it seems implausible that the conversion code in Dictionary would even be capable of "converting" a native storage to a native storage (i.e. it's reasonable to expect that the conversion code explicitly converts an NSDictionary to a native storage).
I am not sure of the exact behaviour. I only read something Lattner wrote as a comment on very slow behaviour when passing things back and forth into CoreGraphics that relied on bridging Swift arrays/dictionaries into their CF counterparts.
In the debug trace, it appeared that the Swift hash map got bridged over and over again every time it was to be read. Since this was a set of attributes for CoreGraphics graphics rendering, the dict/array conversion ended up costing magnitudes more than what the rendering itself did.
From what I remember, Lattner (might have been someone else on the compiler team) said that such conversion should only have needed to happen once, and not at every access to an element. Something like that.
This issue started to occur when it was no longer possible to directly create NSDictionary/NSArray from Swift.
I may also misremember things. Best would be to ask on the Apple developer forums.
> This issue started to occur when it was no longer possible to directly create NSDictionary/NSArray from Swift.
Huh? You can still create NSDictionary / NSArray in Swift using the exact same API you would in Obj-C. That's always been possible. And in fact Swift even extends NSArray / NSDictionary to support the Swift literal syntax.
Yeah and swapping to a C array isn't that simple in Swift. It seems easier to just have objective c code and call that from Swift when needed.