티스토리 뷰

iOS

[Swift] 중첩 타입 (Nested Types)

Peppo 2022. 6. 24. 12:55
728x90

열거형 (Enum)은 특정 구조체나 클래스의 기능을 처리하기 위해 자주 사용됩니다. 

특정 문맥에서 좀 더 복잡한 타입을 위해 사용할 수 있는 유틸리티 클래스나 구조체를 정의할 수 있는데,

이를 위해  Swift에서는 중첩 타입을 지원합니다. 

 

핵심

열거형, 클래스, 구조체를 해당 타입 안에서 다시 정의할 수 있습니다.

 


중첩 타입의 사용 (Nested Types in Action)

 

아래는 블랙잭 게임에서 사용되는 카드를 BlackjackCard 구조체를 정의한 예시 입니다.

BlackjackCard 구조체는 SuitRank 라는 두개의 중첩 열거 타입을 포함합니다.

 

블랙잭에서 Ace 카드는 1 또는 11 입니다. 

이 기능은 Rank 열거형 중첩타입인 Values라는 구조체로 표시됩니다.

 

// 구조체 BlackjackCard 안에 열거형 Suit, Rank이 들어가 (중첩) 있음.
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 { // enum안에 struct가 들어가는 것도 가능합니다.
             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
     }
 }

 

열거형 Suit 의 값은 카드에서 사용하는 모양을 Character 타입으로 각각의 raw값을 이용해  표현 합니다.

("♠", "♡", "♢", "♣" )

 

열거형 Rank는 카드에서 사용 가능한 13가지 카드 순위를 표현 합니다. raw 값은 그 순위의 값을 나타냅니다.

(이 raw Int 값은 Jack, Queen, King, Ace 카드에서는 사용되지 않습니다.)

 

위에서 언급했듯, 열거형 Rank는 중첩된 구조체 Values를 정의 합니다.

이 구조체는 대부분의 카드가 하나의 값을 갖고 있지만, Ace 카드는 두개의 값을 갖고 있다는걸 캡슐화 합니다.

구조체 Values 는 두 프로퍼티들을 표현 합니다.

 struct Values {
            let first: Int, second: Int?
        }
  • first, Int 타입
  • second, Int? (optional Int) 타입

 

또한 Rank 는 연산 프로퍼티를 정의합니다.

ace, jack, queen, king 등 first와 second 값을 모두 갖는 카드는 그것에 맞게 값을 반환하고, 나머지에 대해선 first 값만 존재해 second의 값은 nil을 반환 합니다.

 

BlackjackCard는 rank와 suit 두개의 프로퍼티를 갖고 있습니다.

description이라고 불리는 연산 프로퍼티도 정의 합니다. 

BlackjackCard는 커스텀 초기자가 없는 구조체이기 때문에 암시적인 멤버 초기자 (Implicit memberwise initializer)를 갖습니다. 

이 초기자를 사용하여 theAceOfSpades라는 새 상수를 초기화 할 수 있습니다.

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

.ace, .spadesBlackjackCard안에 중첩 타입으로 선언되어 있기 때문에 타입 추론이 가능하여 BlackjackCard 초기화시 .ace, .spades로 사용할 수 있습니다.

 

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
     }

위 예시에서, description 프로퍼티의 output에 values.second 값도 있기 때문에 해당 부분이 적용됩니다.

 output += " or \(second)"

 


중첩 타입의 언급 (Referring to Nested Types)

중첩 타입을 선언 외부에서 사용하려면 선언된곳부터 끝까지 적어줘야 합니다.

let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
print(heartsSymbol)
// ♡
728x90

'iOS' 카테고리의 다른 글

[iOS] Unit Test  (0) 2022.07.10
[Swift] 익스텐션 (Extensions)  (0) 2022.07.01
[iOS] indexPath.row , IndexPath.item 의 차이점  (0) 2022.06.22
[Swift] ARC (Automatic Reference Counting)  (0) 2022.06.19
[Swift] NSCache, 이미지캐시 개념  (0) 2022.06.17