[iOS]enum의 모든 것 - 2편

신용철·2020년 9월 20일
0

iOS_Swift

목록 보기
6/6

1. Associated Values

  • 인스턴스가 생성될 때 case에 상수값을 설정할 수 있는데 이 값을 associated values라고 합니다. 아래부터는 연관값이라 표현하겠습니다.
  • 연관값은 아래와 같이 타입만 입력해 놓았다가 인스턴스화 할 때 값을 넣어줍니다.
enum Mydog {
    case age(Int)
    case name(String)
    case gender
    
}

let age : Mydog = .age(4)

//값을 상수나 변수에 담아서 전달해도 무방합니다.
let num = 4
let age2 : Mydog = .age(num)
  • 연관값을 사용할 때, 연관값이 없는 경우에는 nil을 전달하고 연관값이 있는 경우에는 optional로 값이 전달 됩니다.
  • 연관값의 경우에는 == 연산자를 사용할 수 없습니다. 따라서 값 비교를 하고 싶을 경우 Equatuable 프로토콜을 채택해야 합니다.
  • 연관값을 불러와서 사용하는 가장 일반적인 방법은 switch문을 사용하는 것입니다.
enum OddOrEven {
  case odd(Int)
  case even(Int)
}

var number = OddOrEven.even(20)

switch number {
case .odd(let x): print("홀수 :", x)
case .even(let x): print("짝수 :", x) // "짝수 :, 20"
}

switch number {
case let .odd(x): print("홀수 :", x)
case let .even(x): print("짝수 :", x) // "짝수 :, 20"
}

2. Enum Initializers

  • 생성자를 선언할 때, 반드시 하나의 기본 enum형태를 지정해주어야 하기 때문에 self = ... 형태의 구문이 들어가야 합니다.
enum Filter : String, CaseIterable { 
   case albums = "Albums" 
   case playlists = "Playlists" 
   case podcasts = "Podcasts" 
   case books = "Audiobooks" 
   
   init(_ index:Int) { 
      self = Filter.allCases[index]
    } 
}

//총 3가지 방법으로 인스턴스화가 가능합니다
let type1 = Filter.albums 
let type2 = Filter(rawValue:"Playlists")! 
let type3 = Filter(2) // .podcasts
  • 위의 생성자에는 사실 문제가 있습니다. 만약에 초기화를 할 때 index값에 10이 들어가면 어떻게 될까요? "out of range"라는 런타임 에러가 발생하며 app이 죽게 될 것입니다. 따라서 failable 생성자를 사용해야 합니다.
init?(_ index: Int) { 
    if !Filter.allCases.indices.contains(index) {
      return nil
     } 
     
    self = Filter.allCases[index] 
}
  • 참고로, indices의 내용을 모르시는 분들을 위해 Filter.allCases.indices는 Int Range로 0..<4 를 리턴합니다.
  • 또한, 혹자는 init?(_ index: Int)을 사용하면 scope내부에 'if !Filter.allCases.indices.contains(index)'가 필요없지 않을까 생각하실 수 있는데, 이런 경우 Filter(10)을 입력할 시 nil을 반환하지 않고 똑같이 out of range 에러가 발생하게 됩니다.
  • 생성자는 여러개를 동시에 구현할 수도 있습니다. 위 예시의 let type2 = Filter(rawValue:"Playlists")! 로 인스턴스하는 것에서 param인 rawValue를 생략할 수 있는 생성자를 추가해보겠습니다.
enum Filter : String, CaseIterable { 
   case albums = "Albums" 
   case playlists = "Playlists" 
   case podcasts = "Podcasts" 
   case books = "Audiobooks" 
   
   init?(_ index: Int) { 
    if !Filter.allCases.indices.contains(index) {
          return nil
       } 
     
    self = Filter.allCases[index] 
   }
   
   init?(_ rawValue: String) {
      self.init(rawValue: rawValue) 
   }
   
}

//이제 총 4가지 방법으로 인스턴스화가 가능합니다

let type1 = Filter.albums 
let type2 = Filter(rawValue:"Playlists")! 
let type3 = Filter(2) // .podcasts
let type4 = Filter("Audiobooks")!

3. Enum Properties

  • enum에는 static property와 computed property가 올 수 있습니다.
  • 연산프로퍼티는 enum이 먼저 인스턴스화 되고 난 후에 호출이 가능합니다.
  • 타입프로퍼티는 반드시 enum명을 입력하고 호출되어야 합니다.
enum Filter : String, CaseIterable {
    case albums = "Albums"
    case playlists = "Playlists"
    case podcasts = "Podcasts"
    case books = "Audiobooks"
    static let pod = "Pod"
    
    var sample: SomeFunction {
        switch self {
        case .albums :
            return FistFunction() //SomeFunction의 method
        default :
            return SecondFunction()//SomeFunction의 method
        }
 }
 //연산프로퍼티는 enum이 먼저 인스턴스화 되고 난 후에 호출이 가능합니다.
 let someFunction = Filter.albums.sample // 가능
 let someFunction = Filter.sample // 불가능
 
 //타입프로퍼티는 반드시 'enum이름.프로퍼티' 형식으로 호출되어야 합니다.
 let pod = Filter.pod // 가능
 let pod: Filter = .pod // 불가능

4. Enum Method - mutating

  • 자신의 value를 변경시키는 메서드를 사용할 경우 mutating을 붙여줘야 합니다.
enum Filter : String, CaseIterable {
    
    case albums = "Albums"
    case playlists = "Playlists"
    case podcasts = "Podcasts"
    case books = "Audiobooks"
    
    mutating func advance() {
       if self != .playlists {
        self = .playlists
        //여기서 self는 현재 선택되어있는 case의 값을 포함한 
        //Filter의 인스턴스입니다. ex)Filter.albums
        }
    }
}

var test = Filter.albums
test.advance()
print(test) // playlists
profile
iOS developer

0개의 댓글