在Swift NSObject子类中使用CoreFoundation对象时发生运行时错误

下面是一个非常简单的类( NSObject子类),该类保存CGPath对象列表,并在init CGPath一个CGPath追加到数组:

 import Foundation class MyClass: NSObject { var list = [CGPath](); init() { list.append(CGPathCreateMutable()); } } 

当试图使用这个类时:

 var instance = MyClass(); println(instance.list.count); // runtime error after adding this line 

产生一个难看的崩溃:

 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 

第9帧引起了我的注意: libswiftFoundation.dylib\`Foundation._convertArrayToNSArray 。 为什么会迅速尝试将我的好,快乐,Swift数组转换成NSArray

只有在数组中使用CFType对象时,才会出现此问题。 我可以在数组中使用NSObject子类(例如[UIBezierPath]

这个问题可以很容易地通过不NSObject子类来解决,但是我想知道什么是swift正在做我的无辜的数组另外,我如何仍然可以使用NSObject作为基类,并具有诸如CGPath类的CFType对象的数组

也有人指出(谢谢,@ user102008!) ,它不一定是NSObject的子类,但属性只需要声明@objc

有一些关于在Swift中使用@objc和子类化Objective-C类的文档 :

当你定义一个从NSObject或任何其他Objective-C类inheritance而来的Swift类时,该类将自动与Objective-C兼容。

不过,我想从Swift中使用我的Swift类。 在子类化Objective-C类并在Swift中使用它时,没有提到不同行为的副作用。 但是文档中也提到将Swift数组桥接到NSArray

当你从一个Swift数组桥接到一个NSArray对象时,Swift数组中的元素必须是AnyObject兼容的。

接着说:

如果Swift数组中的某个元素不是AnyObject兼容的,则在桥接到NSArray对象时会发生运行时错误。

CGPathCGPathAnyObject兼容,但Swift 应该试图将我的Swift数组转换成NSArray

嗯,CGPath不AnyObject兼容,但Swift不应该试图将我的Swift数组转换成NSArray。

它必须。 你说你希望它是ObjC兼容的,ObjC不能直接处理Swift数组。 所以它必须将其转换为NSArray。

简单的答案是,这是完全按照logging。 由于这是iOS,所以解决scheme是微不足道的。 只需切换到UIBezierPath(与AnyObject兼容)而不是CGPath。

Swift中与Objective-C兼容的所有对象都使用完整的Objective-C运行时。 这意味着当你从NSObjectinheritance的types(或者被定义为Objective-C兼容)时,它的方法和属性使用消息传递,而不是在编译时链接到你的方法。

要接收消息,所有纯粹的Swift对象,如你的数组,必须被转换为它们的Objective-C对应部分。 无论您是否正在使用Objective-C中的对象,都会发生这种情况,因为无论如何,它都会使用消息传递。

因此,如果您创build一个从NSObjectinheritance的类,则必须假定所有属性都可以转换为Objective-C对应项。 正如你在你的问题中所说,你可以通过使用UIBezierPath而不是UIBezierPathCGPath

从“用cocoa和Objective-C使用Swift”

在Objective-C代码中使用Swift类或协议时,导入器会用NSArrayreplace导入API中任何types的所有Swift数组。

所以根据这个,数组不应该被转换成NSArray。 因为它,我也认为你应该提交一个错误报告。

在此期间,您可以使用相应的Cocoa-Class或将CGPath包装在一个额外的对象中。

 import UIKit class MyClass: NSObject { var list = [CGPath](); override init() { list.append(CGPathCreateMutable()); } } var instance = MyClass() print(instance.list.count) // 1 

这可能是你没有导入Foundaion,这是NSObject的地方:

 import Foundation 

这是包含NSObject的地方(据我所知)。 希望这有助于。 🙂