[iOS]enum의 모든 것 - 1편

신용철·2020년 9월 19일
0

iOS_Swift

목록 보기
5/6

1. enum의 type지정과 rawValue

  • enum에 type지정을 할 수 있는데, 이는 rawValue의 타입을 의미합니다.
  • Int로 타입지정한 경우 case 별로 rawValue에 아무 값도 할당하지 않으면, 첫 번째부터 0, 1, 2 순으로 값이 매겨집니다.
  • String 타입지정한 경우 rawValue를 할당하지 않으면 case의 값 자체가 rawValue가 됩니다.
enum Normal : Double {
	case fahrenheit = 98.6
	case centigrade = 37 
}

enum PepBoy : Int {
	case manny = 1 
	case moe // 2 implicitly 
	case jack = 4 
} 

enum Filter : String { 
	case albums = "Albums" 
	case playlists = "Playlists" 
	case podcasts = "Podcasts"
	case books = "Audiobooks"
}
  • rawValue를 사용해서 할당된 case가 무엇인지 확인할 수도 있습니다. 해당되는 case가 없을경우 nil을 반환합니다.
enum PaperSize: String {
  case A4, A5, Letter, Legal
}

   print(PaperSize(rawValue: "Legal")
    //print "Optional("PaperSize.Legal")"

   print(PaperSize(rawValue: "Tabloid")
    //print "nil"
  • rawValue를 사용할 수 있는 이유는 enum이 RawRepresentable 프로토콜을 채택하고 있기 때문입니다.
public protocol RawRepresentable {

  associatedtype RawValue
  
  var rawValue: Self.RawValue
  
  init?(rawValue: Self.RawValue)
  
}
  • 위의 RawRepresentable 프로토콜을 보면 Failable 생성자(init?)를 사용했음을 볼 수 있습니다. rawValue를 이용하여 enum을 인스턴스화 할 때, rawValue에 해당하는 case가 없는 경우 init이 실패할 수도 있기 때문입니다. 여기서 중요한 사실은 init? 으로 되어있기 때문에, 이와 같은 방식으로 인스턴스화된 결과는 Optional로 되어있다는 점입니다. 하지만 아마 여러분은 Optional인지 모르고 사용했을 가능성이 높습니다. 왜냐하면 실제로 사용할 때는 이것이 체감되지 않기 때문입니다.
enum Filter : String { 
	case albums = "Albums" 
	case playlists = "Playlists" 
	case podcasts = "Podcasts"
	case books = "Audiobooks"
}

let type = Filter(rawValue: "car")
//여기서 type의 type은 Filter? 입니다.
// 이 경우 car라는 rawValue를 가진 case가 없기 때문에, 
// 인스턴스화가 실패하게 됩니다. 이런 이유로 init?으로 되어있는 것입니다.

let type = Filter(rawValue: "Albums")
if type == .albums { // ... }
/*
type은 init?(rawValue:)로 인스턴스화 되었기 때문에 Filter? 입니다.
그러나 우리가 보통 enum을 값비교 용도 사용하기 때문에
compile 오류를 직면하는 경우가 별로 없습니다.
*/
  • 위의 내용을 쉽게 정리하자면, let type = Filter(rawValue: "Albums") 방식으로 인스턴스화를 하면 optional이 되며 값 비교를 위해 사용하는 것에는 문제가 없지만 optional이라는 사실을 알 필요는 있습니다.

2. static/class 멤버를 사용하는 방법

  • enum에서는 let 또는 var 대신에 case라는 키워드를 사용하지만, 전역 멤버를 선언할 때는 static let 또는 static var를 사용합니다.
enum SomeColor {
    static let thatColorName = "That Color"
    static var someColorName = "Some Color"
    //static case가 아닌 static let/var를 사용했습니다.
}

let colorName = SomeColor.thatColorName
  • 참고로 static/class 멤버에 대한 설명은 Zedd님의 블로그에 설명이 잘 되어 있으니 모르신다면 참고하시기 바랍니다. (https://zeddios.tistory.com/251)

3. struct를 enum처럼 사용하는 방법

  • 여러분은 가끔 UIColor.whie가 아닌 .white와 같은 방식으로 작성되는 코드를 본적이 있으실 겁니다. UIColor는 class이지만 사용되는 것을 보면 마치 enum인 것 같은 착각이 듭니다.
    view.backgroundColor = .white // UIColor.white와 같습니다.
  • struct와 class를 enum처럼 사용할 수 있는 방법이 있습니다. 실제로 많은 Objective-C의 enume들이 Swift와 이러한 방식으로 연결되어 있기 때문에 알아두면 좋습니다. 방법은 enum과 같이 RawRepresentable을 채택하여 rawValue를 주는 것입니다.
struct Thing : RawRepresentable {
    let rawValue : Int
    static let one : Thing = Thing(rawValue:1)
    static let two : Thing = Thing(rawValue:2)
    
}

let thing : Thing = .one

4. case들의 list 만들기 (allCases 사용)

  • enum내의 모든 case들을 한 List로 관리하고 싶을 경우, CaseIterable 프로토콜을 채택한 후 allCases를 사용할 수 있습니다.
  • 단, case 중 하나라도 associated value가 있는 경우에는 사용할 수 없습니다. 왜냐하면 인스턴스화 되기 전까지 값이 확정되지 않기 때문입니다.
enum Filter : String, CaseIterable { 
	case albums = "Albums" 
	case playlists = "Playlists" 
	case podcasts = "Podcasts"
	case books = "Audiobooks"

    static let cases: [Filter] = [.albums, .playlists,
                                  .podcasts, .books]
} 

let list: [Filter] = Filter.allCases
//[.albums, .playlists, .podcasts, .books]
profile
iOS developer

0개의 댓글