brunch

You can make anything
by writing

C.S.Lewis

by MJ Apr 02. 2017

5. Swift 형의 구성요소

Swift 3.x Programming

Swift 언어의 형은 클래스, 구조체, 열거형으로 정의할 수 있다. Swift언어는 대부분이 임베디드된 자료형 구조체로 정의되어 있으며, Cocoa 대부분의 형은 클래스로 정의되어 있다. 이들 자료형에 대해 정리해 보고자 한다.


1 .공통적 형

대표적인 자료형을 구성하는 요소는 형이 가지는 값을 저장하는 속성과 자료형이 어떻게 실행되는지를 나타내는 메소드로 나뉜다. 속성은 자료형에 연결된 변수와 상수로 이를 메소드에 형이 있는 함수로 변경해서 말할 수 있다. 이 두가지 외에 자료형을 구성하는 요소에는 초기화를 할 수 있는 속성 이니셔라이저가 있다.


2. 형의 기본

우선 형 정의 방법과 인스턴스화하는 방법을 설명한다. 인스턴와 형을 구체화한 것이며 형에 정의되어 있는 속성과 메소드를 가진다. 예로 String형의 값 "한국"은 String형의 인스턴스이며 append(_:)메소드등이 있다.


//구조체

struct 구조체명 {

    구조체 정의

}

//클래스

class 클래스명 {

     클래스 정의

}

//열거형

enum 열거형명 {

    열거형 정의

}


여기서 설명하는 자료형을 구성하는 요소는 모두 형의 정의 { }내에서 작성한다.

또한 속성과 메소드등의 정의하는 부분에서는 self키워드를 사용하여 인스턴스 자신에게 접근할 수 있다.


struct ExamStruct {

    let a = 100

    func printValue() {  

        print(a)

    }

}


인스턴스 자체가 아닌 인스턴스 속성이나 메소드에 접근하면 self키워드를 생략할 수 있다.다만, 인스턴스 속성과 동일한 이름을 가진 변수나 상수가 범위내에 존재한다면 구분을 위해 self키워드를 사용한다.


struct ExamStruct {

   let value: Int

   init(value: Int) {

      self.value = value

   }

}


형을 인스턴스화하려면 다음과 같이 형명에 ()을 추가하여 이니셜라이저를 호출한다. ()은 필요에 따라 이니셜라이저 인수를 보낸다.


형명()


예로 ExamStruct형과 ExamClass형은 각각 구조체와 클래스이기 때문에 기본적으로 인수가 없는 이니셜라이저가 준비되어 있어 아래와 같이 인스턴스화할 수 있다.


struct ExamStruct {}

class ExamClass {}

let s = ExamStruct()

let c = ExamClass()


열거형은 기본적인 이니셜라이저가 정의되어 있지 않기 때문에 ExamEnum형은 ExamEnum()으로 초기화할 수 없지만 열거형은 케이스를 지정하는 인스턴스화하는 방법이 있다. 이 부분에 대해서는 나중에 정리해본다.


3. 속성(Property)

속성과 형이 연결된 값으로 형이 대표 속성의 표현등에 사용된다. 예로 책 제목과 저자명이나 설명등의 특성을 가지고 있지만 이를 형과 속성간의 관계로 표현하면 책은 형이 되고, 저자명이나 설명등은 속성으로 말할 수 있다., 책 제목등은 책마다 다르기 때문에 속성은 형 인스턴스에 연결된 변수나 상수라고 말할 수 있다.

속성은 var키워드 또는 let키워드로 정의한다. 변수와 상수가 같이 var키워드는 중복지정이 가능한 속성을 정의하고 let키워드는 중복지정이 불가능한 속성을 지정한다.


struct 구조체명 {

    var 속성명: 속성형 = 식 // 다시 할당 가능

    let 속성명: 속성명 = 식 // 다시 할당 불가능

}


속성에 접근하려면 형의 인스턴스가 할당된 변수와 상수의 속성명으로 변수명, 속성명처럼 작성한다. 아래 예는 ExamStruct형으로 재할당할 수 있는 속성 a와 다시 할당할 수 없는 속성 b를 정의한 것이다.


struct ExamStruct {

    var v = 300 // 다시 할당할 수 있는 속성

    let c = 600 // 다시 할당 불가능한 속성 

}

let examStruct = ExamStruct()

let a = examStruct.v //300

let b = examStruct.c //600


구조체 형의 무결성을 유지하기 위해 인스턴스화가 될 때까지 모든 속성에 값을 할당해야 한다. 따라서 모든 속성을 선언할 때 초기값을 가지고 있는지, 이니셜라이저에서 초기화되는지등 하나의 메소드로 값을 가질 필요가 있다. 이런 속성 초기화 확인에 대해서는 나중에 설명한다.


인스턴스 속성은 인스턴스마다 다른 값을 가질 수 있다. 이를 보통 속성이라고 한다. var, let 키워드로 정의된 속성을 인스턴스 속성이라고 봐도 된다. 아래 예는 SayHello형의 두개 인스턴스를 생성하는 것을 보여준다.


struct SayHello {

    var to = "김명준"

    var body = "안녕하세요"

}

let s1 = SayHello()

var s2 = SayHello()

s2.to = "홍길동"

let t1 = s1.to // 김명준

let t2 = s2.to // 홍길동


정적인 속성은 형 인스턴스가 아닌 형 자체로 인스턴스간의 공통이 되는 값이 있는지에 사용할 수 있다. 정적인 속성을 정의하려면 속성 선언 앞에 static키워드를 추가한다. 또한 정적인 속성에 접근하려면 형명에 정적인 속성명을 붙이고 정적인 속성명처럼 사용한다. 아래 예는 정적인 속성 device를 추가해서 인스턴스마다 다른 대상과 내용, 기기정보를 가지는 것을 보여준다.


struct SayHello {

    static let device = "iPhone7"

    var to = "김명준"

    var body = "안녕하세요"

}

func print(s: SayHello) {

    print("이름: \(s.to)")

    print("내용: \(s.body)")

    print("기기: \(s.device)")

}

let s1 = SayHello()

var s2 = SayHello()

s2.to = "홍길동"

s2.body = "안녕하세요"

print(s: s1)

print(s: s2)


인스턴스 속성은 인스턴스가 생성될 때까지 값을 할당할 수 있으면 속성 선언이외에 이니셜라이저 안에서 값을 대입할 수 있지만, 정적인 속성에는 이니셜라이저에 해당하는 초기화 타이밍이 없기 때문에 선언시 반드시 초기값이 있어야 한다.


속성값을 우지하는 저장속성과 값을 보관유지하는 컴퓨터테드 속성으로 분류되며 저장속성은 변수나 상수처럼 값을 대입하여 저장하는 속성으로 var, let키워드를 사용한다.


var 인스턴스속성명: 속성형 = 식

let 인스턴스속성명: 속성형 = 식

static var 정적인속성명: 속성형 = 식

static let 정적인속성명: 속성명 = 식


아래 예는 다시 할당할 수 있는 인스턴스속성 v, 다시 할당할 수 없는 인스턴스 속성 c, 다시 할당할 수 있는 정적속성 s, 다시 변경할 수 없는 정적인 속성 x를 정의했다.


struct ExamStruct {

    var v = 100

    let c = 300

    static var s = 500

    static let x = 700

}

let examStruct = ExamStruct()

examStruct.v // 100

examStruct.c // 300

examStruct.s // 500

examStruct.x // 700


속성 옵저버는 저장속성값의 변경을 모니터링하고 변경전과 변경후의 문장을 실행한다. 이를 정의하려면 저장속성의 정의에 { }을 추가하고 willSet키워드로 변경전의 실행문을 didSet키워드로 변경후의 실행문을 지정한다.


var 속성명 = 초기값 {

    willSet {

        속성변경전 실행문

        변경후 값은 상수 newValue로 접근 가능

    }

    didSet {

        속성 변경전 실행문

    }

}


willSet시점에서 저장속성은 변경되지 않지만 대신 암시적 상수 newValue를 통해 새 값에 접근할 수 있다.


struct SayHello {

    var to = "김명준" {

        willSet {

            print("willSet \(self.to), newValue=\(newValue)")

        }

        didSet {

            print("didSet \(self.to)")

        }

    }

}

var s = SayHello()

s.to = "홍길동"


계산형 속성(Computed property)은 속성 자체가 값을 저장하지 않고 이미 저장된 속성등으로부터 계산하여 값을 리턴하는 속성을 말한다. 이를 정의하려면 var 키워드 뒤에 속성명과 형을 지정하고 { }내에 get, set을 지정한다.


var 속성명: 형 {

    get {

        return 값 리턴처리

    }

    set {

        값을 변경하는 내용

        속성에 할당된값은 상수 newValue로 접근가능

    }

}


getter는 다른 저장속성등의 값을 얻어 컴퓨터헤드 속성값으로 리턴처리한다. 값 리턴시 return문을 사용한다.


struct SayHello {

    var to = "김명준"

    var body: String {

        get {

            return "안녕하세요 \(to)"

        }

    }

}

let s = SayHello()

s.body


setter는 속성에 할당된 값을 사용하여 다른 저장속성등을 변경하는 프로세스이다. 셋터내에서 암시적으로 선언된 newValue상수를 통해 할당된 값에 접근할 수 있다. 이 값을 사용하여 셋터를 실행한 다음 겟터가 newValue와 같은 값을 리턴할 수 있도록 인스턴스를 변경한다.

아래 예는 단위환산해주는 머신을 만든다고 가정하고 kilometer와 meter를 사용하여 자동 연산해주는 것을 보여준다.


struct UnitMachine {

    var kilometer: Int = 0

    var meter: Int {

        get {

            return kilometer * 1000

        }

        set {

            kilometer = newValue / 1000

        }

     }

}

vat u = UnitMachine()

u.kilometer // 0

u.meter // 0

u.kilometer = 120

u.meter // 12000


계산형 속성은 겟터의 정의는 필요하지만 셋터 정의는 선택사항이다. 셋터가 존재하지 않는 경우 get키워드와 { }를 생략하고 겟터를 만들 수 있다.


struct SayHello {

    var to = "김명준"

    var body: String {

        return "안녕하세요 \(to)")

    }

}

let s = SayHello()

s.body


셋터가 정의되어 있지 않은 계산형 속성에 대입한 값을 변경할 수 없으며 속성을 변경하는 코드는 컴파일 오류가 발생한다. 아래 예는 셋터가 정의되어 있지 않는데 속성 변경을 하기 때문에 컴파일 오류이다.


struct SayHello {

    var to = "김명준"

    var body : String {

        return "안녕하세요 \(to)"

    }

}

let s = SayHello()

s.body = "안녕?" // 컴파일오류



4. 이니셜라이저

이니셜라이저는 형 인스턴스를 초기화한다. 앞에서 이야기했듯이 모든 속성은 인스턴스의 완료에 값이 할당되어 있지 않으면 안되기 때문에 속성 선언시 초기값이 없는 속성은 이니셜라이저에서 초기화해야 한다.

사용방법은 init키워드로 선언하고 인수 및 초기화에 대한 처리를 정의한다.


init(인수) {

    초기화처리

}


아래 예는 이전에 만든 SayHello형에 정의된 이니셜라이저를 사용하여 SayHello형 인스턴스를 초기화한다.


struct SayHello {

    let to: String

    var body: String {

        return "안녕하세요 \(to)")

    }

    init(to: String) {

        self.to = to

    }

}

let s = SayHello(to: "김명준")

let b = s.body


이니셜라이저는 모든 속성을 올바른 형의값으로 초기화하는 역할을 하지만, 이니셜라이저의 인수에 따라 속성을 초기화할 수 없는 케이스가 있다. 초기화에 실패할 가능성이 있는 이니셜라이저는 실패가능한 이니셜라이저(Failable initializer)로 표현하고 결과를 Optional<Wrapped>형으로 리턴한다.

실패가능한 이니셜라이저는 init키워드에 ?를 추가하여 init?(인수)와 같이 정의한다. 초기화 실패는 return nil로 나타내고 이니셜라이저는 nil을 리턴한다. 또한, 초기화를 실패할 경우 인스턴스화되지 않기 떄문에 속성을 초기화되지 않는 상태가 된다.

아래 예는 교과서 과목을 BookItem형 이니셜라이저 init? (dic:)인수 dic에서 id를 Int형을 꺼낼 수 없을 경우 title을 String형으로 꺼낼 수 없는 경우 초기화 실패한다. 리턴형은 BookItem?이 되고 dic이 초기화에 필요한 정보를 가지고 있는 경우 BookItem형의 인스턴스를 리턴하지 않으면 nil을 리턴한다. nil이 리턴되는 경우 인스턴스화되지 않기 때문에 id, title속성 초기화가 되지 않고 컴파일이 된다.


struct BookItem {

    let id: Int

    let title: String    

    init?(dic: [String: Any]) {

        guard let id = dic["id"] as? Int,

              let title = dic["title"] as? String else {

            return nil // 이렇게 하면 id, title은 초기화되지 않는 상태에서도 컴파일가능함

        }        

        self.id = id

        self.title = title

    }

}

let dic2: [[String: Any]] = [

    ["id": 1, "title": "국어"],

    ["id": 2, "title": "수학"],

    ["title": "과학"], // id없는 사전

    ["id": 3, "title": "국사"],

]

for dic in dic2 {

    if let item = BookItem(dic: dic) {

        print(item)

    } else {

        print("오류: 사전 \(dic) Item생성 실패")

    }

}

//결과

//BookItem(id: 1, title: "국어")

//BookItem(id: 2, title: "수학")

//오류: 사전 ["title": "과학"] Item생성 실패

//BookItem(id: 3, title: "국사")


속성 초기화를 컴파일러에 의해 검사되어 하나라도 속성이 초기화가 되지 않으면 형일관성이 없어지기 때문에 컴파일 오류가 발생한다.아래 예처럼 init(to: String)에서 속성 to를 초기화하지 않았기 때문에 컴파일 오류가 발생한다. 이는 SayHello형 초기화할 때 속성to값이 설정되지 않아 SayHello형 인스턴스가 가져야할 값이 모두 갖춰지지 않았기 때문이다.


struct SayHello {

    let to: String

    var body: String {

        return "안녕하세요 \(to)"

    }

    init(to: String) {

        //인스턴스 초기화후 to가 초기값을 가지고 있지 않아 오류발생

    }

}


여기서 이니셜라이저에서 모든 속성을 초기화하면 형일관성을 유지하며 컴파일도 가능해진다.


struct SayHello {

    let to: String

    var body: String {

        return "안녕하세요 \(to)"

    }

    init(to: String) {

        self.to = to        

    }

}


또한, 속성을 초기화하지 않고 인스턴스화를 마치는 조건이 하나라도 있으면 컴파일오류가 발생한다. 아래 예는 dic["to"]값이 존재하지 않으면 속성 to를 초기화하지 않아 상태로 인스턴스가 종료되기 때문에 컴파일 오류가 발생한다.


struct SayHello {

    let to: String

    var body: String {

        return "안녕하세요 \(to)"

    }

    init(dic: [String: String]) {

        if let to = dic["to"] {

            self.to = to  

        }

        // 속성to를 초기화할 수 없는 경우 컴파일 오류

    }

}


이런 경우에는 실패가능 이니셜라이저를 사용하여 컴파일이 가능해진다.


struct Say1 {

    let to: String

    var body: String {

        return "안녕하세요 \(to)"

    }    

    init?(dic: [String: String]) {

        guard let to = dic["to"] else {

            return nil

        }

        self.to = to

    }

}

struct Say2 {

    let to: String

    var body: String {

        return "안녕하세요 \(to)"

    }    

    init(dic: [String: String]) {

        to = dic["to"] ?? "김명준"

            return nil

        }

    }

}



5. 메소드

메소드는 형과 같은 함수이다. 메소드는 형의 인스턴스 동작을 실행하는데 사용한다. 메소드를 정의하려면 형 정의 내부에서 func키워드를 사용한다. 메소드명과 인수와 리턴값 문법이 함수와 동일하다.


func 메소드명(인수) -> 리턴형 {

    메소드호출시 실행되는 문장

}


메소드를 호출하는 형 인스턴스가 할당된 변수 및 상수, 메소드명()을 지정하고 변수명, 메소드명()형태로 작성한다. 메소드에 인수가 있는 경우()에 인수를 ,(콤마)로 구분하여 (인수명1, 인수명2)형태로 작성한다.


struct SayHello {

    func hello(user: String) -> Void {

        print("인녕하세요 \(user)")

    }

}

let s = SayHello()

s.hello(user: "김명준")


속성과 마찬가지로 메소드는 형 인스턴스와 같은 인스턴스 메소드와 형 자체와 같은 정적인 메소드가 있다.

인스턴스 메소드는 형 인스턴스와 같은 메소드로 보통 메소드라고 부른다. func키워드로 정의된 메소드는 기본적으로 인스턴스 메소드이다. 아래 예는 Int형 속성 value를 가진 ExamStruct형을 정의하고 printValue()메소드로 value값을 출력한다.


struct ExamStruct {

    var v = 0

    func printValue() {

        print("값: \(self.v)")

    }

}

vat examStruct1 = ExamStruct()

examStruct1.v = 10

examStruct1.printValue()

vat examStruct2 = ExamStruct()

examStruct2.v = 30

examStruct2.printValue()


정적인 메소드는 형 자체와 같은 메소드이며 인스턴스에 의존하지 않는 처리에 사용한다. 정적인 메소드를 정의하려면 메소드 정의 앞에 static키워드를 사용한다.SayHello형은 정적인 속성 device가 정의되어 있으며 초기값은 "iPhone7"이다. 정적인 메소드 setDevice(withDevice:)이름을 지정하고 이 속성을 변경한다.


struct SayHello {

    static var device = "iPhone7"    

    static func setDevice(withDevice deviceName: String) {

        device = "\(deviceName)"

    }    

    var to = "김명준"

    var body: String {

        return "안녕하세요 \(to) \n \(SayHello.device)"

    }

}

let s = SayHello()

print(s.body)

SayHello.setDevice(withDevice: "iPhone7 Plus")

print(s.body)


오버로드는 다른 형의 인수와 리턴값을 받아 같은 메소드를 여러가지로 준비하고 인수로 전달하는 형과 리턴값의 대입하는 쪽의 형에 따라 실행하는 메소드를 전환하는 방식이다. 오버로드는 입출력 형이 다른 비슷한 처리에 같은 메소드를 준비하고 호출자에게 그차이를 의식하지 않는 용도로 사용한다.

인수를 통해 메소드를 오버로드하려면 인수형이 다른 같은 메소드를 여러가지로 정의한다.  아래 예는 String 형 인수를 put(_:)메소드와 Int형 인수를 put(_:)메소드를 정의한다.모두 같은 put(_:)메소드명이 있는데 실행결과에서 인수형에 의해 실행되는 메소드가 변경되는 것을 알 수 있다.


struct Check {

    func put(_ value: String) [

        print("\(value)")

    }

    func put(_ value: Int) {

        print("\(value)")

    }

}

let c = Check()

c.put("대한민국')

c.put(100)


리턴값에 의해 메소드를 오버로드하려면 리턴갑 형이 다른 같은 이름을 가진 메소드를 여러가지 정의한다. 다음 예에서 String형 리턴값을 가지는 getValue()메소드와 Int형의 리턴값을 가지는 getValue()메소드를 정의한다. 모두 같은 이름의 메소드명이지만 실행결과에서 리턴값의 대입하는 부분의 정수 형에 의해 실행되는 메소드가 바뀐다.


struct ValueStruct {

    let s = "대한민국"

    let i = "100"    

    func getValue() -> String {

        return s

    }

    func getValue() -> Int {

         return i

    }

}

let a = ValueStruct()

let x = a.getValue() //컴파일오류



6. 서브스크립트

서브스크립트는 배열이나 사전등의 컬렉션 요소에 대한 접근을 일괄적으로 표현하기 위한 문법이다.


let arr = [1, 2, 3, 4, 5]

let first = arr[0]

let dic = ["a": 1, "b": 2, "c": 3, "d": 4, "e": 5]

let a = dic["b"] //2


정의하려면 subscript키워드 다음 인수와 리턴형을 지정하고 {}내에서 get, set을 정의한다. 인수와 리턴값 정의하는 것으 함수와 비슷하지만, 서브스크립트는 모든 외부 인수명이 기본적으로 _으로 되어 있다.


subscript(인수) -> 리턴형 {

    get {

        return문으로 값 리턴처리

    }

    set {

        값 변경하는 경우

    }

}


서브스크립트를 사용하려면 형 인스턴스가 할당된 변수 및 상수에 [ ]으로 둘러싸인 인수로 변수명처럼 [인수]형태로 작성한다. 갑을 얻고자 할 때 겟터를 호출하기 위해  변수명을 선언하고, [인수]=신규값 형태로 하면 값이 대입되면 셋터가 호출된다.


// 수열

struct Series {

    var num: [Int]

    subscript(ix: Int) -> Int {

        get {

            return num[ix]

        }

        set {

            num[ix] = newValue

        }

    }

}

var s = Series(num: [3, 5, 7])

let e1 = s[1] // 5

s[1] = 9

let e2 = s[1] // 9


인수가 여러개 있는 경우도 있기 때문에 행렬 Procession형을 정의하고 요소에 대한 접근을 서브스크립트로 한다.


// 행렬

struct Procession {

    var rows: [[Int]]    

    subscript(row: Int, column: Int) -> Int {

        get {

            return rows[row][column]

        }

        set {

            rows[row][column] = newValue

        }

    }

}

let p = Procession(rows: [

        [10, 20, 30],

        [40, 50, 60],

        [70, 80, 90],

    ])

let e = p[2, 2] // 90


계산형 속성과 똑같이 서브스크립트로 겟터의 정의는 필요하지만, 셋터 정의는 선택사항이다. 셋터가 존재하지 않는 경우 get키워드와 {}을 생략하고 겟터를 만들 수 있다. 아래 예는 수열 예제에서 셋터를 제거한 경우를 보여준다.


// 수열

struct Series {

    var num: [Int]

    subscript(ix: Int) -> Int {

        return num[ix]

    }

}

var s = Series(num: [3, 5, 7])

let e1 = s[1] // 5


단, 셋터가 정의되어 있지 않는 서브스크립트에서는 대입으로 값을 변경할 수 없다. 서비스크립트가 값을 변경하는 코드를 넣으면 컴파일 오류가 발생한다.

메소드처럼 서브스크립트도 오버로드할 수 있다. 다른 형의 인수와 리턴값을 받아 같은 이름의 서브스크립트를 여러개 만들고 인수형과 리턴값의 대입하는 쪽의 형에 따라 실행하는 서브스크립트를 바꾼다.


8. 확장(Extension)

Swift언어는 이미지 존재하는 형으로 속성과 메소드 및 이니셜라이저등의 형을 구성하는 요소를 추가할 수 있다. 이런 형의 확장을 확장(Extension)이라고 한다.


extension 확장을 정의하는 대상의 형 {

    대상형에 추가할 요소

}


아래 예는 String형에 대한 확장을 하는 예를 보여준다. 또한, 계산형 속성을 추가할 수 있기때문에 앱을 개발하다보면 기본형으로 사용하기 어려울 때 확장해서 사용이 가능해진다.


extension String {

    var bracketString: String {

        return "<\(self)>"

    }

}

let content = "html".bracketString + " = HTML태그"


여기서 이니셜라이저를 확장에 추가하게 된다면 특정 정보에서 기존 형 인스턴스를 생성하는 것도 가능하다.아래 예는 앱 내부 오류를 나타내는 APIError형을 정의하고 알림화면을 보여주는 UIAlertController라는 클래스에 APIError형값을 인수로 받아서 초기화하는 init(apiError:)를 추가하는 것을 보여준다.


import UIKit

enum APIError: Error {

    case connectionError(Error)

    case fatalError    

    var title: String {

        switch self {

            case .connectionError:

                return "통신오류"

            case .fatalError:

                return "시스템오류"

        }

    }    

    var msg: String {

        switch self {

        case .connectionError(let unError):

            return unError.localizedDescription + "재시도"

        case .fatalError:

            return "담당자에게 문의바람"

        }

    }

}

extension UIAlertController {

    convenience init(apiError: APIError) {

        self.init(title: apiError.title, message: apiError.msg, preferredStyle: .alert)

    }

}

let error = APIError.fatalError

let ac = UIAlertController(apiError: error)



9. 형의 중첩

Swift언어는 형에 형을 정의할 수 있는데 이를 형 중첩이라고 말한다. 중첩된 형은 중첩형이름을 이어받아 형명이 더명확해지고 간결해질 수 있다. 형 중첩은 형 정의 위치를 다른 형의 내부에서 처리한다고 해도 속성과 메소드의 인수에는 영향을 주지 않는다.

형을 중첩하는 예를 하나 살펴보자. 회사공지사항 항목을 나타내는 NoticeItem형과 그 공지사항 분류를 나타내는 NoticeItemType형이 있다고 보자.


enum NoticeItemType {

    case a

    case b

    case c

}

struct NoticeItem {

     let id: Int

     let title: String

     let type: NoticeItemType

}


형명에서 NoticeItemType형은 NoticeItem형의 종류를 나타내는 것으로 이해할 수 있는데 이렇게 하면 이름으로는 추축이 가능하지만 실제 개발해서는 그리 좋지 못한 코드이다. NoticeItemType형을 NoticeItem형에 중첩시켜 Types으로 이름을 만들어보자.


struct NoticeItem {

    enum Types {

        case a

        case b

        case c

    }

    let id: Int

    let title: String

    let type: Types

}

let t = NoticeItem.Types.a

let i = NoticeItem.init(id: 1, title: "이번달실적", type: t)


위와 같이 NoticeItem.Types형은 NoticeItemType형과 비교해보면 NoticeItem형과의 관련성이 뚜렷해진다. 형명또한 더 간결하게 사용할 수 있다.


이처럼 형이 어떤 요소로 구성되어 있는지를 정리해보았다.

매거진의 이전글 4. Swift의 함수
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari