let myDouble = 0.0
let myDoubleAsInt = Int(myDouble)
//myDoubleAsInt: Int
→ The above code is not really "Type casting". The type conversion that is happening above is achieved through " initialization "
ex. "is" example
class Animal{
var name: String
init(n: String){
name = n
}
}
class Human: Animal{
func code(){
print("coding..")
}
}
class Fish: Animal{
func breatheUnderWater(){
print("breathing..")
}
}
let angela = Human(n: "Angela")
let jack = Human(n: "Jack")
let nemo = Fish(n: "Nemo")
let neighbours = [angela, jack, nemo]
//neighbours array is type of "Animal"
if neighbours[2] is Human{
print("is human")
}
//false -> nemo is type of fish
func findNemo(from animals: [Animal]){
for animal in animals{
if animal is Fish{
print(animal.name)
}
}
}
findNemo(from: neighbours)
//Nemo
ex. another example
let cell = UITableViewCell()
if cell is UITableViewCell{
print("it is!")
}
func findNemo(from animals: [Animal]){
for animal in animals{
if animal is Fish{
print(animal.name)
}
}
}
→ In the for-loop, animal is the type of Animal, thus we cannot tap into the "breatheUnderWater( )" method right now.
→ But once we are totally sure that animal is of type Fish, we can downcast it and assign it to a different variable/constant.
func findNemo(from animals: [Animal]){
for animal in animals{
if animal is Fish{
let fish = animal as! Fish
fish.breatheUnderWater()
}
}
}
findNemo(from: neighbours)
//breathing..
→ Force downcast : need to be very careful when using it.
ex.
let fish = neighbours[1] as! Fish
//run-time error
let fish = neightbours[1] as? Fish
//fish becomes type of Fish? (Optional)
fish?.breatheUnderWater()
//Optional chaining -> Checks if fish is not nil, and then performs method
//OR
if let fish = neightbours[1] as? Fish{
fish.breatheUnderWater()
//Optional binding -> no need for chaining
}
else{
print("casting failed")
}
//casting failed
Upcasting
Raise an object to its superclass type
No need to add ? or ! because it is always going to succeed in casting.
→ Because it's just raising it to its superclass. A subclass "always" has a superclass
func findNemo(from animals: [Animal]){
for animal in animals{
if animal is Fish{
let fish = animal as! Fish
fish.breatheUnderWater()
let animalFish = fish as Animal
//animalFish: Animal
}
}
}
let angela = Human(n: "Angela")
let jack = Human(n: "Jack")
let nemo = Fish(n: "Nemo")
let num = 12
let neighbours = [angela, jack, nemo, num]
//error
let neighbours: [Any] = [angela, jack, nemo, num]
// no error
→ Making an array with type Any allows it to accept any kind of data type
AnyObject
let neighbours: [AnyObject] = [angela, jack, nemo, num]
//error (num not allowed)
Why?
A. AnyObject restricts the types to those that comes from classes. Structures are no longer allowed. Int, Double, String are all structures, so they are not allowed.
ex.
class Fish: Animal{
func breatheUnderWater(){
print("breathing..")
}
}
struct Fish{
func breatheUnderWater(){
print("breathing..")
}
}
let neighbours: [AnyObject] = [angela, jack, nemo]
//error
NSObject
let neighbours: [NSObject] = [angela, jack, nemo]
//error
If we make the array as an NSObject type, we get an error. This is because angela, jack, nemo all do not fit to the NSObject.
→ We need to use a class from Foundation, which is made by Apple
let num: NSNumber = 12
let word: NSString = "ABC"
let neighbours: [NSObject] = [num,word]
// This is okay
→ So, depending on how strict your criteria is, you can go through these very broad types : Any, AnyObject, and NSObject. These allow you to create collections of items that are more broad than just writing like "let neightbours: [Animals]"