Reputation: 35953
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?
Upvotes: 34
Views: 20060
Reputation: 10283
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 {
// ...
}
Upvotes: 19
Reputation: 38238
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.
Upvotes: 4
Reputation: 3031
With Swift arrays, you can call bridgeToObjectiveC()
on them, and they'll turn into NSArrays. The same is true of Swift dictionaries.
Upvotes: 3
Reputation: 761
For anyone trying to get this to work in Swift, you can do the following:
let arrayColors: NSArray = [UIColor.blackColor().CGColor as AnyObject, UIColor.clearColor().CGColor as AnyObject]
I noticed that in my Objective-C code that I was casting the CGColorRef types to id. Not sure why though. If anyone has a reason why that would be great!
Upvotes: 2
Reputation: 6187
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]
Upvotes: 29