Error de time de ejecución cuando se utilizan objects CoreFoundation en una subclass Swift NSObject

Aquí hay una class muy simple (subclass de NSObject ) que mantiene una list de objects CGPath y anexa una CGPath a la matriz en init :

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

Cuando intente usar esta class:

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

Produce un feo 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 

El marco # 9 me llamó la atención: libswiftFoundation.dylib\`Foundation._convertArrayToNSArray . ¿Por qué rápidamente intentaría convertir mi bonita y feliz serie Swift en una NSArray ?

Este problema solo ocurre cuando se usan objects CFType en una matriz. Puedo usar subclasss NSObject en la matriz muy bien (Ej. [UIBezierPath] )

El problema puede solucionarse fácilmente al no subclasificar NSObject , pero quiero saber qué es exactamente lo que está haciendo rápidamente en mi matriz inocente . Además, cómo todavía puedo usar NSObject como la class base y tener matrices de objects CGPath como CGPath .

También se señaló (¡Gracias, @ user102008!) Que no tiene que ser una subclass de NSObject , pero la propiedad solo tiene que ser declarada @objc .

Hay alguna documentation a propósito de usar @objc y subclasificar una class Objective-C en Swift:

Cuando define una class Swift que henetworkinga de NSObject o cualquier otra class de Objective-C, la class es automáticamente compatible con Objective-C.

Sin embargo, estoy intentando usar mi class Swift desde Swift. No se mencionan los efectos secundarios en la documentation de diferentes comportamientos cuando se subclasifica una class Objective-C y se usa dentro de Swift. Pero la documentation también menciona unir las matrices Swift a NSArray :

Cuando puentes desde una matriz Swift a un object NSArray , los elementos en la matriz Swift deben ser compatibles con AnyObject .

Y continúa diciendo:

Si un elemento en una matriz Swift no es compatible con AnyObject , se produce un error de time de ejecución al NSArray un object NSArray .

Hmmmm, CGPath no es compatible con AnyObject , pero Swift no debe tratar de convertir mi matriz Swift en una NSArray .

Hmmmm, CGPath no es compatible con AnyObject, pero Swift no debe tratar de convertir mi matriz Swift en una NSArray.

Tiene que. Dijiste que quieres que sea compatible con ObjC, y ObjC no puede manejar matrices Swift directamente. Entonces tiene que convertirlo a un NSArray.

La respuesta corta es que esto funciona exactamente como está documentado. Como esto es iOS, la solución, sin embargo, es trivial. Simplemente cambie a UIBezierPath (que es compatible con AnyObject) en lugar de CGPath.

Todos los objects en Swift que son compatibles con Objective-C, utilizan el time de ejecución Objective-C completo. Esto significa que cuando crea un tipo que henetworkinga de NSObject (o se define como compatible con Objective-C), sus methods y properties utilizan Mensajería en lugar de vincular en time de compilation a su método.

Para recibir un post, todos los objects puramente Swift, como su matriz, deben convertirse en su contrapartida Objective-C. Esto sucede independientemente de si está utilizando el object en Objective-C porque no importa qué, utiliza los posts.

Por lo tanto, si crea una class que henetworkinga de NSObject, debe asumir que todas las properties se pueden convertir en una contrapartida de Objective-C. Como dijiste en tu pregunta, puedes lograr esto usando UIBezierPath lugar de CGPath .

Desde "Uso de Swift con Cocoa y Objective-C"

Cuando utiliza una class o protocolo Swift en el código Objective-C, el importador reemplaza todas las matrices Swift de cualquier tipo en la API importada con NSArray.

Entonces, de acuerdo con esto, la matriz no debe convertirse a NSArray. Como lo hace, también creo que debería presentar un informe de error.

Mientras tanto, puedes usar la correspondiente class de cocoa o envolver tu CGPath en un object extra.

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

Probablemente sea el hecho de que no importó Foundaion, que es donde NSObject es:

 import Foundation 

Aquí es donde se contiene NSObject (hasta donde sé). Espero que esto haya ayudado. 🙂