I have this code that creates a view and applies a gradient to it.
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 is giving me no compile error, but the code is crashing on the line
let arrayColors = [cor1.CGColor, cor2.CGColor]
with the message array element cannot be bridged to Objective-C
In fact I was expecting it to crash there, because I am not sure how I can create an array of CGColors on Swift. The surprise here is Xcode mentioning Objective-C. In my mind I was creating a CGColorRef in swift...
Any clues? Why is it mentioning Objective-C and how do I solve this?
The reason Objective-C is mentioned is because UIKit and QuartzCore are Objective-C frameworks. In particular, gradient.colors = arrayColors
is calling an Objective-C method that expects an NSArray
.
This seems like a bug, as Apple's documentation makes it sound like that the array should auto-bridge to an NSArray
so long as the items in the array can be considered AnyObject
:
When you bridge from a Swift array to an NSArray object, the elements in the Swift array must be AnyObject compatible. For example, a Swift array of type Int[] contains Int structure elements. The Int type is not an instance of a class, but because the Int type bridges to the NSNumber class, the Int type is AnyObject compatible. Therefore, you can bridge a Swift array of type Int[] to an NSArray object. If an element in a Swift array is not AnyObject compatible, a runtime error occurs when you bridge to an NSArray object.
You can also create an NSArray object directly from a Swift array literal, following the same bridging rules outlined above. When you explicitly type a constant or variable as an NSArray object and assign it an array literal, Swift creates an NSArray object instead of a Swift array.
For now, a work around would be either to declare arrayColors
as an NSArray
:
let arrayColors: NSArray = [cor1.CGColor, cor2.CGColor]
Or to declare it as taking AnyObject
:
let arrayColors: Array <AnyObject> = [cor1.CGColor, cor2.CGColor]
This runtime error can also be triggered if it tries to bridge an array of type [MySwiftProtocol]
over to Objective-C.
The solution is to mark your protocol with @objc
:
@objc protocol MySwiftProtocol {
// ...
}
I found that I could fix the problem by explicitly using CGColorRef rather than CGColor for my colours, e.g.:
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]
...worked fine, without any NSArray or AnyObject casting. If I take out the explicit CGColorRef in the type declarations for the colours, I get the "array element cannot be bridged to Objective-C" error.
With Swift arrays, you can call bridgeToObjectiveC()
on them, and they'll turn into NSArrays. The same is true of Swift dictionaries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With