Here's a very simple class (subclass of NSObject
) that keeps a list of CGPath
objects and appends one CGPath
to the array on init
:
import Foundation
class MyClass: NSObject {
var list = [CGPath]();
init() {
list.append(CGPathCreateMutable());
}
}
When trying to use this class:
var instance = MyClass();
println(instance.list.count); // runtime error after adding this line
Yields an ugly crash:
Playground execution failed: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
* thread #1: tid = 0x1251d1, 0x00000001064ce069 libswiftFoundation.dylib`partial apply forwarder for Swift._ContiguousArrayBuffer.(_asCocoaArray <A>(Swift._ContiguousArrayBuffer<A>) -> () -> Swift._CocoaArray).(closure #1) with unmangled suffix "392" + 121, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
* frame #0: 0x00000001064ce069 libswiftFoundation.dylib`partial apply forwarder for Swift._ContiguousArrayBuffer.(_asCocoaArray <A>(Swift._ContiguousArrayBuffer<A>) -> () -> Swift._CocoaArray).(closure #1) with unmangled suffix "392" + 121
frame #1: 0x00000001064ce0d8 libswiftFoundation.dylib`partial apply forwarder for reabstraction thunk helper <T_0_0> from @callee_owned (@in T_0_0) -> (@owned Swift.AnyObject) to @callee_owned (@in T_0_0) -> (@out Swift.AnyObject) with unmangled suffix "395" + 56
frame #2: 0x00000001057bf29a libswift_stdlib_core.dylib`Swift.MapSequenceGenerator.next <A : Swift.Generator, B>(@inout Swift.MapSequenceGenerator<A, B>)() -> Swift.Optional<B> + 554
frame #3: 0x00000001057bf49a libswift_stdlib_core.dylib`protocol witness for Swift.Generator.next <A : Swift.Generator>(@inout Swift.Generator.Self)() -> Swift.Optional<Swift.Generator.Self.Element> in conformance Swift.MapSequenceGenerator : Swift.Generator + 58
frame #4: 0x00000001064d8e97 libswiftFoundation.dylib`Swift._copyCollectionToNativeArrayBuffer <A : protocol<Swift._Collection, Swift._Sequence_>>(A) -> Swift._ContiguousArrayBuffer<A.GeneratorType.Element> + 1511
frame #5: 0x00000001064f1951 libswiftFoundation.dylib`protocol witness for Swift.Sequence.~> @infix <A : Swift.Sequence>(Swift.Sequence.Self.Type)(Swift.Sequence.Self, (Swift._CopyToNativeArrayBuffer, ())) -> Swift._ContiguousArrayBuffer<Swift.Sequence.Self.GeneratorType.Element> in conformance Swift.LazyRandomAccessCollection : Swift.Sequence + 449
frame #6: 0x00000001064daf7b libswiftFoundation.dylib`Swift.ContiguousArray.map <A>(Swift.ContiguousArray<A>)<B>((A) -> B) -> Swift.ContiguousArray<B> + 1339
frame #7: 0x00000001064da9cb libswiftFoundation.dylib`Swift._ContiguousArrayBuffer._asCocoaArray <A>(Swift._ContiguousArrayBuffer<A>)() -> Swift._CocoaArray + 475
frame #8: 0x00000001064ced3e libswiftFoundation.dylib`Swift._ArrayBuffer._asCocoaArray <A>(Swift._ArrayBuffer<A>)() -> Swift._CocoaArray + 78
frame #9: 0x000000010649f583 libswiftFoundation.dylib`Foundation._convertArrayToNSArray <A>(Swift.Array<A>) -> ObjectiveC.NSArray + 35
frame #10: 0x000000011163b40e
Frame #9 caught my eye: libswiftFoundation.dylib\`Foundation._convertArrayToNSArray
. Why would swift be trying to convert my nice, happy, Swift array into an NSArray
?
This issue only occurs when using CFType
objects in an array. I can use NSObject
subclasses in the array just fine (Ex. [UIBezierPath]
)
The issue can easily be fixed by not subclassing NSObject
, however I want to know what exactly swift is doing to my innocent array. Also, how I can still use NSObject
as the base class and have arrays of CFType
objects such as CGPath
.
It was also pointed out (Thanks, @user102008!) that it doesn't have to be a subclass of NSObject
, but the property just has to be declared @objc
.
There is some documentation on purpose of using @objc
and subclassing an Objective-C class in Swift:
When you define a Swift class that inherits from NSObject or any other Objective-C class, the class is automatically compatible with Objective-C.
However, I am trying the use my Swift class from within Swift. There is no mention of side effects in the documentation of different behavior when subclassing an Objective-C class and using it within Swift. But the documentation also mentions bridging Swift arrays to NSArray
:
When you bridge from a Swift array to an
NSArray
object, the elements in the Swift array must beAnyObject
compatible.
And goes on to say:
If an element in a Swift array is not
AnyObject
compatible, a runtime error occurs when you bridge to anNSArray
object.
Hmmmm, CGPath
isn't AnyObject
compatible, but Swift shouldn't be trying to convert my Swift array into an NSArray
.