Potato
μ•ˆλ…•ν•˜μ„Έμš”, κ°μž‘λ‹ˆλ‹€?πŸ₯” ^___^ 😺 github λ°”λ‘œκ°€κΈ° πŸ‘‰πŸ»

Swift/Swift Documents

[Swift] 곡식 λ¬Έμ„œ 정리 (19) - Type Casting (νƒ€μž…μΊμŠ€νŒ…) (λ‹€μš΄μΊμŠ€νŒ…, as, is)

감자 πŸ₯” 2022. 3. 9. 13:28
λ°˜μ‘ν˜•

μ•ˆλ…•ν•˜μ„Έμš”, μ§€μΉ˜μ§€ μ•Šκ³  λŒμ•„μ˜¨ κ³΅μ‹λ¬Έμ„œ 정리 ν¬μŠ€νŒ…μž…λ‹ˆλ‹€. μš”μ¦˜ μ• ν”Œ λ””λ²¨λ‘œνΌ 아카데미도 λΆ™μ—ˆλ‹€, μŠ€ν„°λ””λ„ ν•œλ‹€, ν•˜λ©΄μ„œ κ°œμΈκ³΅λΆ€λ₯Ό 쑰금 μ†Œν™€νžˆ ν•˜κ³  μžˆλŠ”λ°, 정말 λ°˜μ„±ν•˜λŠ” μ˜λ―Έλ‘œλ‹€κ°€ μ˜€λŠ˜μ€ μ’€ 곡뢀도 μ•„μΉ¨ 일찍 μ‹œμž‘ν•΄λ΄€μ–΄μš”... 갓생 μ‚΄μ•„λ³΄μžμ•„γ…μ•„... 

κ°“μƒμ‚°λ‹€κ³ λŠ” ν•˜λŠ”λ°, μ–Έμ œλ‚˜ 만쑱슀러운 갓생을 살아본적은 아직 μ—†λŠ” κ²ƒκ°™μ•„μš”. μ–Έμ œμ―€, 제 κΈ°λŒ€μΉ˜μ— λ§Œμ‘±ν• λ§Œν•œ κ³΅λΆ€μ˜ 양을 μ±„μš°κ³  ν•˜λ£¨λ₯Ό 정말 μ•Œμ°¨κ²Œ μ‚΄ 수 μž‡μ„κΉŒμš”? 흠흠흠... λ…Έλ ₯ν•΄λ΄…μ‹œλ‹€ λͺ¨λ‘ ν™”μ΄νŒ… 그럼 κ³΅μ‹λ¬Έμ„œ 정리 μ‹œμž‘!

Swift document chap.19 Type Casting λ°”λ‘œκ°€κΈ°

 

Type Casting — The Swift Programming Language (Swift 5.6)

Type Casting Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy. Type casting in Swift is implemented with the is and as operators. These tw

docs.swift.org

 


 

Type Casting

  • νƒ€μž…μΊμŠ€νŒ…μ€ μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ„ ν™•μΈν•˜κ±°λ‚˜ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό ν•΄λ‹Ή 클래슀 계측 ꡬ쑰의 슈퍼 ν΄λž˜μŠ€λ‚˜ μ„œλΈŒν΄λž˜μŠ€λ‘œ μ·¨κΈ‰ν•˜λŠ” 방법이닀.
  • Swift의 νƒ€μž…μΊμŠ€νŒ…μ€ is, as μ—°μ‚°μžλ‘œ κ΅¬ν˜„λœλ‹€.
  • νƒ€μž…μ„ ν™•μΈν•˜κ±°λ‚˜ λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ 캐슀트 ν•˜λŠ” 것을 κ°„λ‹¨ν•œ ν‘œν˜„μœΌλ‘œ μ œκ³΅ν•œλ‹€.
  • νƒ€μž…μΊμŠ€νŒ…μ„ μ‚¬μš©ν•˜μ—¬ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λŠ”μ§€ 확인 ν•  μˆ˜λ„ μžˆλ‹€.

 

νƒ€μž…μΊμŠ€νŒ…μ„ μœ„ν•œ 클래슀 계측 ꡬ쑰 μ„ μ–Έ

ν΄λž˜μŠ€μ™€ μ„œλΈŒ 클래슀의 계측ꡬ쑰와 ν•¨κ»˜ νƒ€μž… μΊμŠ€νŒ…μ„ μ‚¬μš©ν•˜μ—¬ νŠΉμ • 클래슀의 μΈμŠ€ν„΄μŠ€ νƒ€μž…μ„ ν™•μΈν•˜κ³  ν•΄λ‹Ή μΈμŠ€ν„΄μŠ€λ₯Ό λ™μΌν•œ 계측 λ‚΄μ˜ λ‹€λ₯Έ 클래슀둜 μΊμŠ€νŒ…ν•  수 μžˆλ‹€.

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

 

MediaItem μ΄λΌλŠ” κΈ°λ³Έ 클래슀λ₯Ό μ •μ˜ν–ˆλ‹€. 이 ν΄λž˜μŠ€λŠ” 디지털 λ―Έλ””μ–΄ λΌμ΄λΈŒλŸ¬λ¦¬μ—λŠ” μ–΄λ–€ μ’…λ₯˜μ˜ ν•­λͺ©μ—λ“  기초 κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€. name 속성과 init 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)
  }
}

MediaItem 을 μ„œλΈŒν΄λž˜μ‹± ν•˜μ—¬ 두 개의 λ‹€λ₯Έ μ„œλΈŒν΄λž˜μŠ€λ₯Ό λ§Œλ“€μ—ˆλ‹€.

첫번째 ν•˜μœ„ 클래슀인 MoiveλŠ” μ˜ν™” 및 필름에 λŒ€ν•œ μΆ”κ°€ 정보λ₯Ό κ°–κ³ μžˆλ‹€. μ΄λŠ” MediaItem μ΄λΌλŠ” 기초 클래슀 μœ„μ— director 속성과 ν•΄λ‹Ή μƒμ„±μžλ₯Ό μΆ”κ°€λ‘œ κ°–κ³  μžˆλ‹€.

λ‘λ²ˆμ§Έ ν•˜μœ„ 클래슀인 Song 은 κΈ°λ³Έ 클래슀 MediaItem μœ„μ— artist 속성과 μƒμ„±μžλ₯Ό μΆ”κ°€ν•œλ‹€.

let library = [
  Movie(name: "Casablanca", director: "Michael Curtiz"),
  Song(name: "Blue Suede Shoes", director: "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"),  
]
// "library" 의 νƒ€μž…μ€ [MediaItem] 이라고 좔둠함

μœ„ μ„Έκ°œμ˜ classλ₯Ό ν™œμš©ν•˜μ—¬ library λΌλŠ” μƒμˆ˜ 배열을 μƒμ„±ν–ˆλ‹€. library λ°°μ—΄μ˜ νƒ€μž…μ€ 이λ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” λ°°μ—΄ κΈ€μž κ°’μ˜ λ‚΄μš©μœΌλ‘œ μΆ”λ‘ ν•œλ‹€. μŠ€μœ„ν”„νŠΈλŠ” Moive와 Song의 곡톡 μƒμœ„ ν΄λž˜μŠ€κ°€ MediaItem μž„μ„ μ΄λŒμ–΄λ‚Ό 수 μžˆμœΌλ―€λ‘œ, library 배열은 Array<MediaItem> νƒ€μž… 이라고 μΆ”λ‘ ν•˜κ²Œ λœλ‹€. (νƒ€μž…μΊμŠ€νŒ…)

ν•˜μ§€λ§Œ, library에 μ €μž₯ν•œ ν•­λͺ©μ˜ 이면은 μ—¬μ „νžˆ Movie, Song μΈμŠ€ν„΄μŠ€μΈλ°, 이 λ°°μ—΄μœΌ μˆœνšŒν•˜κ²Œ 되면 λ°˜ν™˜λ˜λŠ” νƒ€μž…μ€ MediaItem νƒ€μž…μ΄μ§€ Moive λ‚˜ Song이 μ•„λ‹ˆλ‹€. 본래 μžμ‹ μ˜ νƒ€μž…μœΌλ‘œ μž‘μ—…ν•˜κΈ° μœ„ν•΄μ„œλŠ”, νƒ€μž…μ„ κ²€μ‚¬ν•˜κ±°λ‚˜ (check), λ‹€λ₯Ένƒ€μž…μœΌλ‘œ downcastν•˜μ—¬ μ΄μš©ν•΄μ•Ό ν•œλ‹€.


 

νƒ€μž… 검사 (Check)

is μ—°μ‚°μžλ₯Ό μ΄μš©ν•΄ νŠΉμ • μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ„ 확인 ν•  수 μžˆλ‹€. νƒ€μž… 검사 μ—°μ‚°μžλŠ” μΈμŠ€ν„΄μŠ€κ°€ κ·Έ ν•˜μœ„ 클래슀이면 trueλ₯Ό λ°˜ν™˜ν•˜κ³ , μ•„λ‹ˆλ©΄ falseλ₯Ό λ°˜ν™˜ν•œλ‹€.

μ•„λž˜ μ½”λ“œλŠ” library 배열을 μˆœνšŒν•˜κ³  μ•„μ΄ν…œμ΄ νŠΉμ • νƒ€μž…μΌ λ•Œ λ§ˆλ‹€ κ·Έ 숫자λ₯Ό μ¦κ°€ν•˜λŠ” μ½”λ“œμ΄λ‹€.

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")
// "Media library contains 2 movies and 3 songs" λ₯Ό 인쇄함

μœ„ μ½”λ“œμ—μ„œ for-in κ΅¬λ¬Έμ—μ„œ library λΌλŠ” λ°°μ—΄μ˜ λͺ¨λ“  ν•­λͺ©μ— μ ‘κ·Όν•œλ‹€. ν•˜μ§€λ§Œ libraryλŠ” Array<MediaItem> νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— MediaItem νƒ€μž…μ΄ λ°˜ν™˜λ˜κ²Œ λ˜λŠ”λ°, μ΄λ•Œ is μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•˜μ—¬ ν•΄λ‹Ή ν•­λͺ©μ΄ MediaItem의 μ„œλΈŒν΄λž˜μŠ€μΈ Movie, Song ν΄λž˜μŠ€μΈμ§€ 확인할 수 μžˆλ‹€.

 


 

λ‹€μš΄μΊμŠ€νŒ… (Downcasting)

νŠΉμ • 클래슀 νƒ€μž…μ˜ μƒμˆ˜μ™€ λ³€μˆ˜λŠ” μ„œλΈŒν΄λž˜μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μ°Έμ‘°ν•  수 μžˆλ‹€. λ§Œμ•½ μ΄λŸ¬ν•œ κ²½μš°κ°€ λ§Œμ‘±ν•œλ‹€κ³  μƒκ°ν•˜λŠ” 경우 as?, as! λ₯Ό μ‚¬μš©ν•˜μ—¬ μ„œλΈŒν΄λž˜μŠ€ νƒ€μž…μœΌλ‘œ λ‹€μš΄μΊμŠ€νŠΈ ν•  수 μžˆλ‹€.

  • as?
    • λ‹€μš΄μΊμŠ€νŠΈ ν•˜λ €λŠ” νƒ€μž…μ˜ μ˜΅μ…”λ„ 값을 λ°˜ν™˜
    • μΊμŠ€νŒ…μ— μ‹€νŒ¨ν•˜λ©΄ nil 값을 λ°˜ν™˜ (λ‹€μš΄μΊμŠ€νŠΈμ˜ 성곡 μ—¬λΆ€κ°€ λΆˆν™•μ‹€ν•  λ•Œ μ‚¬μš©ν•˜λ©΄ μ’‹μŒ)
  • as!
    • λ‹€μš΄μΊμŠ€νŠΈλ₯Ό μ‹œλ„ν•˜κ³  λ°˜ν™˜λœ μ˜΅μ…”λ„ 값을 κ°•μ œ μ–Έλž˜ν•‘
    • λ‹€μš΄μΊμŠ€νŠΈκ°€ ν™•μ‹€ν•˜κ²Œ 성곡할 것이라고 생각될 κ²½μš°μ—λ§Œ μ‚¬μš©
    • λ‹€μš΄μΊμŠ€νŠΈμ— μ‹€νŒ¨ν•˜κ²Œλ˜λ©΄ λŸ°νƒ€μž„ μ—λŸ¬ λ°œμƒ (ν”„λ‘œκ·Έλž¨ 쀑단될 수 있음)
for item in library {
  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)")
  }
}

// Movie: Casablanca, dir. Michael Curtiz
// Song: Blue Suede Shoes, by Elvis Presley
// Movie: Citizen Kane, dir. Orson Welles
// Song: The One And Only, by Chesney Hawkes
// Song: Never Gonna Give You Up, by Rick Astley

μœ„ μ˜ˆμ œλŠ” library의 각 MediaItem을 λ°˜λ³΅ν•˜μ—¬ 각 ν•­λͺ©μ— μ μ ˆν•œ μ„€λͺ…을 μΈμ‡„ν•˜λ„λ‘ ν•˜λŠ” μ½”λ“œμ΄λ‹€. μ΄λ ‡κ²Œ ν•˜λ €λ©΄ 각각의 ν•­λͺ©μ„ MediaItem 뿐만 μ•„λ‹ˆλΌ Movie λ‚˜ Song 으둜써 μ ‘κ·Όν•  ν•„μš”κ°€ μžˆλ‹€. μ„€λͺ…μ—μ„œ μ‚¬μš©ν•  Moiveλ‚˜ Song의 directorλ‚˜ artist 속성에 μ ‘κ·Όν•  수 있으렀면 이게 ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

이 μ˜ˆμ œμ—μ„œλŠ” 각 ν•­λͺ©μ΄ Movie μ΄κ±°λ‚˜ Song 이닀. 각 ν•­λͺ©μ΄ 뭔지 미리 μ•žμ„œμ„œ μ•Œμˆ˜λŠ” μ—†μœΌλ―€λ‘œ, as?λ₯Ό ν™œμš©ν•˜λŠ”κ²Œ μ’‹λ‹€.

λ§Œμ•½ μœ„ μ½”λ“œμ—μ„œ item에 Movie클래슀 νƒ€μž…μ„ ν¬ν•¨ν•˜λŠ” νƒ€μž…μ΄ μžˆλ‹€λ©΄, movie μƒμˆ˜μ— Movie 클래슀 νƒ€μž…μ΄ ν• λ‹Ήλœλ‹€. 이것이 λ°”λ‘œ λ‹€μš΄μΊμŠ€νŒ…μ΄λ‹€. μΊμŠ€νŒ…μ€ μ‹€μ œλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό μˆ˜μ •ν•˜κ±°λ‚˜ 값을 λ³€κ²½ν•˜μ§€λŠ” μ•ŠλŠ”λ‹€. μΈμŠ€ν„΄μŠ€λŠ” λ™μΌν•˜κ²Œ μœ μ§€λ˜μ§€λ§Œ, 캐슀트 된 νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ‘œ μ²˜λ¦¬λœλ‹€.


 

Any, AnyObject의 νƒ€μž… μΊμŠ€νŒ…

Swiftμ—μ„œλŠ” 두 가지 νŠΉλ³„ν•œ νƒ€μž…μ„ μ œκ³΅ν•œλ‹€.

  • Any : ν•¨μˆ˜ νƒ€μž…μ„ 포함해 λͺ¨λ“  νƒ€μž…μ„ λ‚˜νƒ€λ‚Έλ‹€.
  • AnyObject : 클래슀 νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ§Œ λ‚˜νƒ€λ‚Έλ‹€.

μ΄λŸ¬ν•œ κΈ°λŠ₯을 μ œκ³΅ν•˜μ§€λ§Œ, Any, AnyObject λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒλ³΄λ‹€λŠ” μ‹€μ œ μž‘μ—…μ— μ‚¬μš©λ  νƒ€μž…μ„ ꡬ체적으둜 μ§€μ •ν•˜λŠ” 것이 κ°€μž₯ μ’‹λ‹€.

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)" })

Any λ₯Ό μ‚¬μš©ν•˜μ—¬ μ„œλ‘œλ‹€λ₯Έ νƒ€μž…μ΄ μ„žμΈ λ°°μ—΄ thingsλ₯Ό μƒμ„±ν–ˆλ‹€.

things의 νƒ€μž…μ€ Array<Any> 이기 λ•Œλ¬Έμ— μ΄λŸ¬ν•œ 경우 λͺ¨λ“  ν•­λͺ©μ— λŒ€ν•˜μ—¬ νŠΉμ • νƒ€μž…μ„ μ°Ύκ³  μ‹Άλ‹€λ©΄ switch λ¬Έ case μ ˆμ—μ„œ asλ‚˜ is λ₯Ό μ‚¬μš©ν•˜μ—¬ 확인할 수 μžˆλ‹€.

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("and 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")
  }
}

// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called Ghostbusters, dir. Ivan Reitman
// Hello, Michael

μœ„ μ½”λ“œμ²˜λŸΌ things 의 λͺ¨λ“  ν•­λͺ©μ— μ ‘κ·Όν•  λ•Œλ§ˆλ‹€ switch 문으둜 νƒ€μž… 캐슀트λ₯Ό μ§„ν–‰ν•˜μ—¬ μ„±κ³΅ν•œ μΌ€μ΄μŠ€μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ²Œ λœλ‹€.

let optionalNumber: Int? = 3
things.append(optionalNumber)        // Warning
things.append(optionalNumber as Any) // No warning

Anyνƒ€μž…μ€ μ˜΅μ…”λ„ νƒ€μž…μ„ ν¬ν•¨ν•œ λͺ¨λ“  νƒ€μž…μ˜ 값을 λ‚˜νƒ€λ‚Έλ‹€. SwiftλŠ” Any νƒ€μž…μ˜ κ°’μœΌλ‘œ νŠΉμ • νƒ€μž…μ˜ μ˜΅μ…”λ„ 값을 μ‚¬μš©ν•˜λ €λŠ” κ²½μš°μ— κ²½κ³ λ₯Ό μ€€λ‹€. μœ„ μ½”λ“œμ²˜λŸΌ Int? ν˜•μ„ Any νƒ€μž…μœΌλ‘œ μ‚¬μš©ν•˜λ©΄ 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€λŠ” 것이닀. μ΄λ ‡κ²Œ μ˜΅μ…”λ„ 값을 Any둜 μ‚¬μš©ν•΄μ•Όν•˜λŠ” 경우 as μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•˜μ—¬ νŠΉμ • νƒ€μž…μ˜ μ˜΅μ…”λ„ 값을 Any둜 μΊμŠ€νŒ…ν•΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.

λ°˜μ‘ν˜•