2

Apple gives us an example of downcasting an object of the same type as such:

let someObjects: [AnyObject] = [
    Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
    Movie(name: "Moon", director: "Duncan Jones"),
    Movie(name: "Alien", director: "Ridley Scott")
]

We can then access each individual attribute by creating an abstract variable "object" and casting it as what we expect it to be (a movie) :

for object in someObjects {
    let movie = object as! Movie
    print("Movie: '\(movie.name)', dir. \(movie.director)")
}

But what if we go to the next level and for example we have subclasses of movies:

Silent films

Comedy

Action

Each of which all have the same attributes - name & director

I've tried to cast it the same way we did above as a "Movie" since I assumed as a parent class, it would be able to recognize its subclasses, but of course this has not worked otherwise this question would not have existed!

JAL
  • 41,701
  • 23
  • 172
  • 300
mir-aclewhip
  • 127
  • 2
  • 11
  • Can you show the code, how you tried to cast the subclasses in the same way? – ronatory Mar 08 '16 at 17:50
  • I can't reproduce your problem. It works fine when I try it (not that this is a good idea. You shouldn't need `AnyObject` very often, and you should generally avoid subclasses and down-casting if you can avoid them.) As ronatory notes, you should show the code that *doesn't* work, rather than just the code that *does*. – Rob Napier Mar 08 '16 at 17:54
  • Don't forget to come back and accept an answer or vote on the answers that helped you. – JAL Mar 09 '16 at 15:19
  • Have you tried using `as?` instead of `as!` – mccoyLBI Mar 09 '16 at 20:34

2 Answers2

1

As I understand your question right. So the cast works the same way with the subclass as in your example. Maybe you missed something (Hints are in the code comments):

// here the subclass SilentFilm
class SilentFilm:Movie {

}

// Here the array with SilentFilm objects
let someOtherObjects: [AnyObject] = [
    SilentFilm(name: "silentname", director: "silentdirector"),
    SilentFilm(name: "silentname2", director: "silentdirector2")
]

for object2 in someOtherObjects {
    // Here the cast to Movie like in your example
    let movie = object2 as! Movie
    // or cast to SilentFilm works also
    // let movie = object2 as! SilentFilm
    print("Movie: '\(movie.name)', dir. \(movie.director)")
}

// Expected Output
// Movie: 'silentname', dir. silentdirector
// Movie: 'silentname2', dir. silentdirector2

Correct me if I missunderstood your questions!

ronatory
  • 7,156
  • 4
  • 29
  • 49
0

Why not create a class hierarchy with a parent Movie class and check the type of the movie while iterating through your array? There is no need to force cast from AnyObject if you specify your array contains Movie objects, and have all of your sub-genres inherit from Movie.

class Movie {
    var name: String!
    var director: String!
    
    init(name: String, director: String) {
        self.name = name
        self.director = director
    }
}

class Comedy: Movie {
    var laughTrack: Bool!
    
    init(name: String, director: String, laughTrack: Bool) {
        super.init(name: name, director: director)
        self.laughTrack = laughTrack
    }
}

let someObjects: [Movie] = [
    Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
    Movie(name: "Moon", director: "Duncan Jones"),
    Movie(name: "Alien", director: "Ridley Scott"),
    Comedy(name: "Caddyshack", director: "Harold Ramis", laughTrack: false)
]

for movie in someObjects {
    if movie is Comedy {
        print("\(movie.name) is a comedy")
    } else {
        print("\(movie.name) is a movie")
    }
}

Output:

2001: A Space Odyssey is a movie

Moon is a movie

Alien is a movie

Caddyshack is a comedy

Community
  • 1
  • 1
JAL
  • 41,701
  • 23
  • 172
  • 300