Reputation: 27275
I'm making a class that is similar to CLLocation and I wanted to be able o do:
customClass as! CLLocaiton
Do I need to implement any special protocols or anything like that?
Upvotes: 2
Views: 82
Reputation: 126127
The as
/as!
/as?
family of operators is not for conversion of one type to another; it's for casting.
Casting is when you tell the compiler that a value of one type can be safely interpreted as a value of another type. In Swift, this specifically (due to the "safe" part) means types that are related in the type hierarchy — subtypes and supertypes. If you have a SomeClass
type, and a SomeSubclass
type that extends it, or a SomeProtocol
type and a SomeType
(class, struct, or enum) that adopts that protocol, you can always safely upcast from the more specific type to the more general type (the superclass or protocol) with the as
operator. And you can downcast a general type to a more specific type with the as!
or as?
operator — those involve some possibility of failure because the compiler can't know if you're going down the right branch of the type hierarchy.
If you have types that aren't related through the type hierarchy (that is, one is not a subclass of the other, or one is not a protocol adopted by the other), you can't cast. Instead, you convert.
In Swift, conversion is (almost) always explicit — you create a value of the converted-to type using one of its initializers that takes a value of the converted-from type. Examples:
// convert numeric types
let one: Int = 1
let onePointOh = Float(one)
// convert a sequence to an array
let oneToTen = Array(1...10)
So, if you're writing a class that's like CLLocation
, but isn't actually a subclass of CLLocation
, and you want to use it in a context that requires a CLLocation
instance, you need to create the way to get a CLLocation
instance from your class.
You could do that with a method or computed property:
extension MyLocationClass {
var asCLLocation: CLLocation {
return CLLocation(latitude: self.lat, longitude: self.long)
}
}
Or, if you like the construction/conversion syntax used in the standard library, by extending CLLocation
to add a convenience initializer based on your class:
extension CLLocation {
convenience init(_: MyLocationClass) {
self.init(latitude: lat, longitude: long)
}
}
Upvotes: 0
Reputation: 5945
You should not need to do anything special. Just make CustomClass
a subclass of CLLocation
and it will be implicitly upcast any time it is needed. Upcasting with the as
keyword should also work.
class CustomClass: CLLocation {}
let customLocation = CustomClass()
let upcastCustomLocation = customLocation as CLLocation
If for some reason you are not able or willing to make CustomClass
a relative of CLLocation
through inheritance, you will not be able to use the as
keyword (as pointed out by matt).
Upvotes: 0
Reputation: 535229
You cannot cast from CustomClass to CLLocation, because they are not related to one another. Thus, you won't be able to do it that way at all; you have no power over how the as
operator works (you cannot customize its behavior).
You can, however, coerce from CustomClass to CLLocation, in just the same way as you would write e.g. Double(myInteger)
. What you need to do, in other words, is to write an extension to CLLocation that implements init(customClass:CustomClass)
. Thus you'll be able to hand an instance of your CustomClass over to this initializer and get back a new CLLocation instance based upon it.
So, let's pretend you custom class is something like this:
class CustomClass {
var lat : Double = 0
var long : Double = 0
}
Then you could extend CLLocation like this:
extension CLLocation {
convenience init(_ cc:CustomClass) {
self.init(latitude:cc.lat, longitude:cc.long)
}
}
And now you can make a CustomClass instance like this:
let cc = CustomClass()
cc.lat = 30
cc.long = 40
And later you can coerce it to a CLLocation like this:
let loc = CLLocation(cc) // ta-daa!
Thus you are talking just the way you would talk with Double(myInteger)
.
Alternatively, just write a method in CustomClass that returns an "equivalent" CLLocation. This approach is probably easier. So, let's pretend your class is something like this:
class CustomClass {
var lat : Double = 0
var long : Double = 0
func location() -> CLLocation {
return CLLocation(latitude: lat, longitude: long)
}
}
So now you can work with an instance of your CustomClass:
let cc = CustomClass()
cc.lat = 30
cc.long = 40
And then later you can "convert" it to a CLLocation:
let loc = cc.location()
Upvotes: 2