[Swift๐Ÿฆฉ] #19 ํƒ€์ž… ์บ์ŠคํŒ… #20 ์ค‘์ฒฉ๋œ ํƒ€์ž…

28404 ๋‹จ์–ด swiftiOSiOS

Type Casting

  • ์ธ์Šคํ„ด์Šค์˜ ํƒ€์ž…์„ ํ™•์ธํ•˜๊ฑฐ๋‚˜
  • ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค๋ฅธ ์ƒ์œ„ ํด๋ž˜์Šค or ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ๋ฐฉ๋ฒ•
  • is, as ์—ฐ์‚ฐ์ž๋กœ ๊ตฌํ˜„๋œ๋‹ค.
  • ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š”์ง€๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ.



์˜ˆ์‹œ ํด๋ž˜์Šค ์ •์˜

class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}

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

class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}


// MediaType ๊ณผ ๊ทธ๊ฑธ ์ƒ์†ํ•œ Movie, Song ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—
// [MediaType] ์œผ๋กœ ์ถ”๋ก ๋จ.
let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]



1. ํƒ€์ž… ๊ฒ€์‚ฌ

  • is ๋กœ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜์œ„ ํด๋ž˜์Šค ํƒ€์ž…์ด๋ฉด true ์•„๋‹ˆ๋ฉด false
  • ์ •๋ง ๊ทธ ํƒ€์ž…์ธ์ง€ ํ™•์ธ๋งŒ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ.
var movieCount = 0
var songCount = 0

for item in library {
    if item is Movie {
        movieCount += 1
    } else if item is Song {
        songCount += 1
    }
}

print("Media library contains \(movieCount) movies and \(songCount) songs")
// Prints "Media library contains 2 movies and 3 songs"



2. ๋‹ค์šด์บ์ŠคํŒ…

  • ํŠน์ • ํด๋ž˜์Šค ํƒ€์ž…์˜ ์ƒ์ˆ˜/๋ณ€์ˆ˜๋Š” ํ•˜์œ„ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ™•์‹ ๋˜๋Š” ๊ฒฝ์šฐ,
  • as? as! ๋ฅผ ์ด์šฉํ•ด์„œ ํ•˜์œ„ ํด๋ž˜์Šค ํƒ€์ž…์œผ๋กœ ๋‹ค์šด์บ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์‹คํŒจ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Optional ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ? ๊ณผ ๊ฐ•์ œ๋กœ ๋‹ค์šด์บ์ŠคํŠธ ํ•˜๋Š” !
for item in library {
    // ํ•˜์œ„ ํƒ€์ž…์ด์–ด์•ผ movie.director, song.artist ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
    if let movie = item as? Movie {
        print("Movie: \(movie.name), dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: \(song.name), by \(song.artist)")
    }
}



3. Any, AnyObject ์— ๋Œ€ํ•œ ํƒ€์ž…์บ์ŠคํŒ…

  • ํŠน์ •๋˜์ง€ ์•Š์€ ํƒ€์ž…์„ ์œ„ํ•ด์„œ
    • Any : ํ•จ์ˆ˜ ํƒ€์ž…์„ ํฌํ•จํ•œ ๋ชจ๋“  ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Œ.
    • AnyObject : ๋ชจ๋“  ํด๋ž˜์Šค ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Œ.
  • ๋‘๊ฐ€์ง€ ํƒ€์ž…์„ ์ œ๊ณตํ•œ๋‹ค.
  • optional ๊ฐ’์„ Any ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ as Any ๋กœ ์บ์ŠคํŠธํ•˜์ž.
var things: [Any] = []

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })

let optionalNumber: Int? = 3
things.append(optionalNumber as Any) // optional ๊ฐ’์„ ๋„ฃ์œผ๋ ค๋ฉด Any ๋กœ ์บ์ŠคํŠธํ•˜์ž.

// switch ๊ตฌ๋ฌธ์„ ํ†ตํ•ด์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
for thing in things {
    switch thing {
    case 0 as Int:
        print("zero as an Int")
    case 0 as Double:
        print("zero as a Double")
    case let someInt as Int:
        print("an integer value of \(someInt)")
    case let someDouble as Double where someDouble > 0:
        print("a positive double value of \(someDouble)")
    case is Double:
        print("some other double value that I don't want to print")
    case let someString as String:
        print("a string value of \"\(someString)\"")
    case let (x, y) as (Double, Double):
        print("an (x, y) point at \(x), \(y)")
    case let movie as Movie:
        print("a movie called \(movie.name), dir. \(movie.director)")
    case let stringConverter as (String) -> String:
        print(stringConverter("Michael"))
    default:
        print("something else")
    }
}



Nested Types

  • ๋ณต์žกํ•œ ํƒ€์ž…์˜ ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด struct, class, enum ์•ˆ์— ์ค‘์ฒฉํ•˜์—ฌ struct, class, enum ์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•„์š”ํ•œ ๋งŒํผ ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ๋‹ค.

1. ๋™์ž‘

struct BlackjackCard > enum Suit
struct BlackjackCard > enum Rank > struct Values

struct BlackjackCard {

    // nested Suit enumeration
    enum Suit: Character {
        case spades = "โ™ ", hearts = "โ™ก", diamonds = "โ™ข", clubs = "โ™ฃ"
    }

    // nested Rank enumeration
    enum Rank: Int {
        case two = 2, three, four, five, six, seven, eight, nine, ten
        case jack, queen, king, ace
        struct Values {
            let first: Int, second: Int?
        }
        var values: Values {
            switch self {
            case .ace:
                return Values(first: 1, second: 11)
            case .jack, .queen, .king:
                return Values(first: 10, second: nil)
            default:
                return Values(first: self.rawValue, second: nil)
            }
        }
    }

    // BlackjackCard properties and methods
    let rank: Rank, suit: Suit
    var description: String {
        var output = "suit is \(suit.rawValue),"
        output += " value is \(rank.values.first)"
        if let second = rank.values.second {
            output += " or \(second)"
        }
        return output
    }
}

์ง€์ •๋œ init์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฉค๋ฒ„๋ณ„ ์ดˆ๊ธฐ์ž ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// Prints "theAceOfSpades: suit is โ™ , value is 1 or 11"

2. ์ฐธ์กฐ

์ค‘์ฒฉ๋œ ํƒ€์ž…์˜ ์ด๋ฆ„์„ chaining ์ฒ˜๋Ÿผ . ์„ ๋ถ™์—ฌ์„œ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol is "โ™ก"

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ