[Swift] 중첩 타입

임승섭·2023년 6월 27일
0

Swift

목록 보기
14/35

Nested Type

타입의 내부에 타입 선언

  • 사용하는 이유
    1. 특정 타입 내에서만 사용하기 위함. -> 사용 범위 한정
      (Bstruct는 Aclass와만 관련이 있고, Aclass가 없으면 의미가 없다)
    2. 타입 간 연관성을 명확하게 구분, 내부 구조 디테일하게 설계
class Aclass {
	struct Bstruct {
    	enum Cenum {
        	case aCase
            case bCase
            
            struct Dstruct {
            }
        }
        var name: Cenum		// name의 타입이 Cenum
        
        /*memberwise initializer 자동 제공
        init(name: Cenum) {
        	self.name = name
        }
        */
    }
}

let aClass: Aclass = Aclass()

// 타입 선언 시 주의
let bStruct: Aclass.Bstruct = Aclass.Bstruct(name: .bCase)	// 구조체에는 멤버와이즈 initializer 제공

let cEnum: Aclass.Bstruct.Cenum = Aclass.Bstruct.Cenum.aCase	// 열거형은 case 선택

let dStruct: Aclass.Bstruct.Cenum.Dstruct = Aclass.Bstruct.Cenum.Dstruct()

Example - 블랙잭

struct BlackjackCard {
	
    // Suit 열거형 - 원시값 사용
    enum Suit: Character {
    	case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
    }
    
    // 순서 열거형 - 원시값 사용
    enum Rank: Int {
    	case two = 2, three, four, five, six, seven, eight, nine, ten
        case jack, queen, king, ace		// 원시값이 존재하지만 사용하지 않고자 할 때 values
        
        // Values 타입 정의 -> 열거형 값을 이용해서 새로운 타입을 반환
        struct Values {
        	let first: Int, second: Int?
        }
        
        // (읽기) 계산 속성
        var values: Values {
        	switch self {	// self : Rank 타입의 인스턴스 중 하나를 의미한다
            case Rank.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)
            }
        }
    }
    
    // 블랙잭 카드 속성 & 메서드
    // 두 개의 저장 속성 : 순서(숫자), 세트(suit)
    let rank: Rank, suit: Suit	// 저장 속성의 타입이 열거형
    
    // (읽기) 계산속성 (get 생략 가능)
    var description: String {
    	get {
        	var output = "\(suit.rawValue) 세트,"		// 원시값 : 모양
            output += "숫자 \(rank.values.first)"		// 숫자 추가
            
            if let second = rank.values.second {	 // second 값이 있는 경우 (.ace)
            	output += "또는 \(second)"
            }
            
            return output
        }
    }
}

// A 스페이드
let card1 = BlackjackCard(rank: .ace, suit: .spades)
print("1번 카드: \(card1.description)")

// 5 다이아몬드
let card2 = BlackjackCard(rank: .five, suit: .diamonds)
print("2번 카드: \(card2.description)")

// 정의한 타입을 외부에서 사용하기 위해서는 중첩되어 있는 타입도 붙여야함(강제) ====> 훨씬 명확해짐
let heartsSymbol: Character  = BlackjackCard.Suit.hearts.rawValue
let suit: BlacjackCard.Suit = BlackjackCard.Suit.hearts

Example - 실제 API

let formatter = DateFormatter()

formatter.dateStyle = .full
// formatter.dateStyle = DateFormatter.Style.full	// 동일한 의미

/**==========================================================
 - var dateStyle: Style { get set }                 (타입확인)
 - var dateStyle: DateFormatter.Style { get set }   (내부정의)
============================================================**/

// 타입을 명시적으로 써주면 뒤에를 줄여도 된다
let setting1: DateFormatter.Style = .full

// 타입을 명시적으로 써주지 않았으면 뒤에를 무조건 full name으로 적어줘야 한다
let setting2 = DateFormatter.Style.medium
  • 중간 타입에 대문자가 나오면, 중첩 타입임을 인지하자
  • 중첩 타입으로 선언된 API를 보는 연습!!

0개의 댓글