在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
对象时会发生运行时错误。
CGPath
, CGPath
不AnyObject
兼容,但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
而不是UIBezierPath
来CGPath
。
从“用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的地方(据我所知)。 希望这有助于。 🙂