objective c to swift
El elemento de matriz no se puede unir a Objective-C (5)
Con las matrices Swift, puede llamar a bridgeToObjectiveC()
en ellas y se convertirán en NSArrays. Lo mismo es cierto para los diccionarios Swift.
Tengo este código que crea una vista y le aplica un degradado.
import UIKit
import QuartzCore
let rect : CGRect = CGRectMake(0,0,320,100)
var vista : UIView = UIView(frame: rect)
let gradient : CAGradientLayer = CAGradientLayer()
gradient.frame = vista.bounds
let cor1 = UIColor.blackColor()
let cor2 = UIColor.whiteColor()
let arrayColors = [cor1.CGColor, cor2.CGColor]
gradient.colors = arrayColors
view.layer.insertSublayer(gradient, atIndex:0)
Xcode no me da ningún error de compilación, pero el código se bloquea en la línea
let arrayColors = [cor1.CGColor, cor2.CGColor]
con el elemento de matriz de mensajes no se puede unir a Objective-C
De hecho, esperaba que se bloqueara allí, porque no estoy seguro de cómo puedo crear una matriz de CGColors en Swift. La sorpresa aquí es que Xcode menciona Objective-C. En mi mente, estaba creando un CGColorRef a toda velocidad ...
¿Alguna pista? ¿Por qué está mencionando Objective-C y cómo lo resuelvo?
Descubrí que podía solucionar el problema usando explícitamente CGColorRef en lugar de CGColor para mis colores, por ejemplo:
var bottomColour:CGColorRef = UIColor.redColor().CGColor
var topColour:CGColorRef = UIColor(red: 255.0/255.0, green: 123.0/255.0, blue: 37.0/255.0, alpha: 1.0).CGColor
gradientLayer.colors = [bottomColour, topColour]
... funcionó bien, sin ningún casting NSArray o AnyObject. Si elimino el CGColorRef explícito en las declaraciones de tipo para los colores, aparece el error "el elemento de la matriz no puede enlazarse al Objective-C".
Este error de tiempo de ejecución también puede activarse si intenta tender un puente entre una matriz de tipo [MySwiftProtocol]
y Objective-C.
La solución es marcar su protocolo con @objc
:
@objc protocol MySwiftProtocol {
// ...
}
La razón por la cual se menciona Objective-C es porque UIKit y QuartzCore son marcos Objective-C. En particular, gradient.colors = arrayColors
llama a un método Objective-C que espera un NSArray
.
Esto parece un error, ya que la documentación de Apple hace que parezca que la matriz debe puentear automáticamente a un NSArray
siempre que los elementos en la matriz se puedan considerar AnyObject
:
Cuando pasa de una matriz Swift a un objeto NSArray, los elementos de la matriz Swift deben ser compatibles con AnyObject. Por ejemplo, una matriz Swift de tipo Int [] contiene elementos de estructura Int. El tipo Int no es una instancia de una clase, sino porque el tipo Int se une a la clase NSNumber, el tipo Int es compatible con AnyObject. Por lo tanto, puede puentear una matriz Swift de tipo Int [] a un objeto NSArray. Si un elemento de una matriz Swift no es compatible con AnyObject, se produce un error en el tiempo de ejecución cuando realiza un enlace a un objeto NSArray.
También puede crear un objeto NSArray directamente desde un literal de matriz Swift, siguiendo las mismas reglas de puente descritas anteriormente. Cuando escribe explícitamente una constante o variable como un objeto NSArray y le asigna un literal de matriz, Swift crea un objeto NSArray en lugar de una matriz Swift.
Por ahora, una arrayColors
sería declarar arrayColors
como un NSArray
:
let arrayColors: NSArray = [cor1.CGColor, cor2.CGColor]
O para declarar que toma AnyObject
:
let arrayColors: Array <AnyObject> = [cor1.CGColor, cor2.CGColor]
Para cualquiera que intente hacer que esto funcione en Swift, puede hacer lo siguiente:
let arrayColors: NSArray = [UIColor.blackColor().CGColor as AnyObject, UIColor.clearColor().CGColor as AnyObject]
Noté que en mi código Objective-C estaba transfiriendo los tipos CGColorRef a id. Sin embargo, no estoy seguro de por qué. Si alguien tiene una razón por la que sería genial!