티스토리 뷰

반응형



안녕하세요ㅎㅎ 

어제 BoostCamp에서 yagom님과 lingostar님이 정말 좋은 swift강의를 해주셨는데요 :) 

오늘은 그 강의들을 정리하는 시간을 가져볼려고 해요.

정말정말 좋은 강의였는데, 이 글에 전부 담아 볼 수 있도록 노력해보겠습니다 XD

(야곰님의 블로그는  http://blog.yagom.net에요. iOS프로그래밍과 관련된 글을 많이 쓰셨으니 참고하세요! lingostar님은 따로 블로그가 없으신 것 같아요 ㅠㅠ 찾아봐도 나오질 않네요.)


오늘은  CLASS / STRUCT / ENUM 에 대해서만 볼게요 :)

 CLASS / STRUCT / ENUM  타입이 각각 어떤 역할을 하는지, 차이점이 뭔지 혹시 아시나요?

각각 설명해드리겠습니다.



1. CLASS

  • 전통적인 OOP 관점에서의 클래스swift에서는 객체라는 용어대신에 '인스턴스'라는 용어를 사용하는 것 같아요. 한마디로 클래스타입의 인스턴스를 객체라고 칭하지 않습니다. (인스턴스는 특정타입이 메모리에 적재된 시점의 타입)
  • 단일 상속만 가능합니다.
  • (인스턴스/타입) 메서드, (인스턴스/타입) 프로퍼티
  • 참조타입(=reference type) (call by reference)
  • iOS 프레임워크 대부분이 클래스 구성되어있습니다.


2. STRUCT 
  • CLASS와 다르게 상속이 불가능 합니다.
  • (인스턴스/타입)메서드, (인스턴스/타입)프로퍼티
  • 값타입(=value type) (call by value)
  •  swift의 대부분의 큰 뼈대는 모두 STRUCT(이하 구조체)로 구성이 되어있습니다.
자, 여기서 궁금증이 생기신 분들도 계실 것 같아요.
클래스에서는  "iOS 프레임워크 대부분이 클래스 구성되어있다"
구조체에서는 "swift의 대부분의 큰 뼈대는 모두 구조체로 구성이 되어있다"
이 두 말의 차이점은 뭘까요?
iOS프레임워크? swift? 
iOS는 swift에 기반한 언어아닌가? 뭐가 다른거지?
자 iOS프레임워크를 먼저 생각해볼까요? 
iOS의 프레임워크하면 뭐가 떠오르시나요?


iOS를 하신다면 이 코드는 정말 많이 보셨다고 생각되는데, 저기 ViewController앞에 class. 보이시나요? 이 ViewController 는 UIViewController를 상속받고 있네요? 

UIViewController의 정의부분으로 한번 가볼까요?




자 UIViewController앞에 class. 보이시나요? 

이렇게 iOS는 클래스를 상속받아 해당 클래스, 즉 부모클래스에 있는 기능들을 자식클래스에서 쓸 수 있게됩니다. 

만약 iOS프레임워크가 구조체였다면 이렇게 쓰지 못하겠죠? 

왜냐하면 구조체는 상속이 불가능하기 때문이죠.

그래서 iOS프레임워크에서는 클래스를 사용한다고 할 수 있습니다 :)



그럼? 상속도 안되는 구조체를 왜쓰지..

자 위에서 swift의 대부분의 큰 뼈대는 구조체라고 그랬죠? 

이 '대부분의 큰 뼈대'는 무엇을 의미할까요?

예시 하나로 들면 이해가 빠르실 것 같아 예시를 하나 들고왔어요 :)

우리가 정말 자주쓰는 Int, Double, String...

이 타입들이 어떻게 구현되어있을 것 같으세요?

command키를 눌러 정의부분으로 가봅시다 :)


public struct Int : SignedInteger, Comparable, Equatable


public struct Double 


public struct String


..

struct가 보이시나요? 이런 데이터 타입들은 구조체로 구현이 되어있답니다 :)

public struct Int : SignedInteger, Comparable, Equatable

이 부분을 보시며 "???상속 받은거 아닌가?" 하는 궁금증이 드실 수 있을 것 같아요.
(사실 제가 방금 글쓰며 든 궁금증입니다ㅎㅎ..)
하지만 앞서 말씀드렸듯이, 구조체는 상속이 불가능하죠?
: 뒤에 나오는 것들은 프로토콜이라고 생각하시면 될 것 같습니다.
SignedIntegerComparableEquatable는 "프로토콜"입니다. 
"나는 이러한 프로토콜들을 채택했어"의 느낌으로 보시면 될 것 같아요. 
여기서 저는 궁금증이 드는게 채택과 상속은 다른 느낌 이겠죠? 상속은 상속받을 클래스의 모든 기능을 물려받는 기능이고, 프로토콜 채택은 "내가 이제 이 프로토콜을 준수 하겠어"라는 기능? 하지만 그 프로토콜에 있는 메서드들을 다 사용 할 수 있으니 상속의 느낌도 가지고 있는건가?..라는 궁금증이 드네요ㅎㅎ..
더 공부해봐야겠습니다.

+ 대부분 클래스와 구조체의 차이점에 대해서는 명확히 나와있는 글들이 많지만 공통점에 대해서는 잘 나와있지 않은 것 같아요 :( 
지금 자신에게 질문해보세요. 
"그래. 클래스와 구조체의 차이점에 대해서는 이제 잘 알겠어. 그럼 공통점이 뭐지?"
BoostCamp면접을 봤었는데 이 공통점이 뭐냐고 딱 물어보셨는데 대답을 정확히 못했어요. ㅠㅠ 
그래서 명확히 정리해보려고해요 :)
공통점은
1 . 서로 다른 타입(자료형)들을 하나로 묶을 수 있다.
2. 이러한 묶은 자료형들을 새로운 타입처럼 사용 가능.
3. 클래스/구조체 안에서 함수/프로퍼티 정의 가능
4. extension이 가능.
하다..정도 일까요? 정말 당연한 것 같은 대답을 제대로 하지 못했네요 ㅠㅠ
공통점과 차이점을 분명하게 알아두시길 바랍니다 :)



3.  ENUM(이하 열거형)

  • 다른 언어의 열거형과는 많이 다릅니다! ( 기존에 본인이 알고있던 언어의 열거형과 동치시키며 생각하지마시고 새로운 열거형을 배운다고 생각해주세요 :) )
  • 상속이 불가능합니다.

  • (인스턴스/타입)메서드, (인스턴스/타입)연산 프로퍼티

?여기서 또 궁금증이 생기실 수 있을 것 같아요. 
클래스랑 구조체에서는  (인스턴스/타입) 프로퍼티더니
열거형에서는 (인스턴스/타입) 연산 프로퍼티?
이게 무슨 차이일까요? 
이 차이에 대해서는 따로 글을 작성하겠습니다 :) 조금만 기다려주세요! 



C나 C++에서 열거형을 보셨나요? 열거형을 선언하면, 따로 값을 지정해주지 않는 이상 처음 값은 0으로 할당되죠? 하지만 swift에서는 아니랍니다 :)
swift에서의 열거형은 유사한 종류의 여러값을 유의미한 이름으로 한곳에 모아 정의한 것으로 볼 수 있습니다. 
즉 열거형 자체가 '하나의 데이터 타입'인거죠. 열거형의 케이스 하나하나 전부 하나의 유의미한 값으로 취급합니다. 
그리고 값이 없을 수 있습니다. 
즉 이름 그 자체만으로 고유한 의미를 나타낼 수 있게 되는 것입니다.
(여기서 값이 없다는것은 optional의 의미일까요?)
이때문에 처음부터 0이 들어 간다거나 하는 생각은 swift에서는 버려주세요.
열거형의 간단한 예제를 한번 볼까요?

enum Animal {

    case tiger

    case leopard

    case lion

}


   let tiger2: Animal = Animal.tiger

   let lion2: Animal = .lion


tiger2라는 변수는 Animal타입을 가지고 Animal.tiger라는 값을 주었죠.


lion2도 마찬가지입니다. tiger2는 Animal.tiger라고 쓰고 lion2는 그냥 .lion이라고 써주었죠? 사실 둘은 똑같은 의미를 가진답니다. 처음 변수를 선언할 때 이 아이는 Animal타입이야~ 라고 컴파일러에게 힌트를 주었으므로 또 Animal.tiger라고 쓸 필요 없이 그냥 .lion만 써도 컴파일러는 알아듣게 되는 것이죠. 


  print(tiger2)

  print(lion2)


를 하면 어떻게 될까요?

tiger

lion

이 나오게 됩니다. 값을 주지 않아도 이름 그자체로서 값을 의미한다고 볼 수 있겠네요. C나 C++에서는 아무 값도 할당해주지 않았으니 0과 1이 나왔겠죠? ㅎㅎ




이렇게까지 보시고 이런생각이 드실 수 있어요. 

"아, 나는 swift에서 C나 C++에서 사용하는 열거형을 쓰고싶은데" 

그러시고 싶으시다면, 방법이 있습니다. 

바로 raw value 설정하는 것 입니다. 

raw value가 뭘까요? 의미 그대로 '원시값'입니다.


위의 예제에서 원시값을 넣어볼까요?


enum Animal : Int {

    case tiger = 0

    case leopard

    case lion

}


Animal타입은 Int타입을 상속하는것은 아니고 ㅎㅎ.. : Int타입이라고 타입을 지정해주는 거에요.

자, tiger에게 0이라는 원시값을 할당해주었죠?


print(tiger2.rawValue)

print(lion2.rawValue)

(tiger2와 lion2는 위에서 선언해준 Animal타입 상수입니다.)

를 하면 값이 어떻게 나올까요? 


0

2


이렇게 나오게 된답니다. leopard에게는 1이 할당되었겠죠? 

자 Double형으로도 한번 해볼까요?


enum Animal : Double {

    case tiger = 0

    case leopard

    case lion

}


print(tiger2.rawValue)

print(lion2.rawValue)


을 하면 뭐가 출력될까요?

바로 


0.0

2.0



가 출력되게 됩니다. Double이니 소수점으로 출력이 된 것이겠죠?

자, 그럼 원시값을 0이 아닌 0.1로 줘볼까요?


enum Animal : Double {

    case tiger = 0.1

    case leopard

    case lion

}


이렇게요! 

그럼 어떤일이 발생하시나요?

컴파일러가 오류가 발생했다고 말해줍니다.




이렇게 말이죠.

자 오류를 해석해봅시다!

"이전의 원시값이 정수가 아닐 경우 enum case의 원시값을 정의해주어야 합니다"

이게 무슨 뜻일까요?

앞 case tiger에서 0.1을 원시값으로 지정해주었죠?컴파일러는 leopard의 원시값을 어떤 값으로 줘야할지 몰라서 나는 에러입니다. 1을 주어야 할지, 1.1을 주어야 할지 컴파일러는 모르겠죠?


열거형 타입을 String으로 해주어 봅시다!


enum Animal : String {

    case tiger = "A"

    case leopard

    case lion

}


 print(tiger2.rawValue)

 print(lion2.rawValue)


결과가 뭐가 나오실 것 같나요?


A

C


라고 생각하셨나요?

사실 해보기 전까지 저도 A와 C가 나올 줄 알았답니다 :)..


콘솔에는


A

lion


이 나왔어요.

"열거형은 이름 그 자체만으로 의미를 가진다"라는 점에서 (이름이 String이니까) 이렇게 나오지 않았나 싶어요 :) 


스위프트 개발문서의 열거형쪽을 읽어보시면, 

원시 값은 문자열, 글자, 정수 또는 어떠한 부동 소수점 타입이 될 수 있습니다.

각각의 원시 값은 열거형 정의 안에서 반드시 유일해야 합니다. 

원시 값으로 정수가 사용되었다면, 열거형 멤버의 일부에 아무 값도 설정되지 않은 경우 자동 증가(Auto-incrementation)할 것입니다. 


답이 A와 C로 나오지 않은 이유를 알겠네요! :)

정수가 아니라서 입니다 ㅎㅎ..

원시값은 정수값만을 할당해야만 1씩 증가하게 된답니다 :)


자 또한 열거형에서 알아두셔야 할게 있어요.


"전달한 원시값에 해당하는 케이스가 없을 있기 때문에 원시값을 통한 인스턴스 생성은 옵셔널값으로 반환된다."


예제를 통해 확인해 볼까요?


enum Animal : Int {

    case tiger = 0

    case leopard

    case lion

}


tiger에게 0을 할당했으니 leopard는 1, lion은 2가 되겠죠?

자 그럼


let someAnimal = Animal(rawValue: 4)


이 코드는 무엇을 의미할까요?

"Animal열거형에 원시값 4를 가지는 애를 someAnimal에 넣어줘"가 될 것 같아요 :)

근데 Animal열거형에는 2까지 밖에 없죠? 


print(someAnimal)

를 하면 어떻게 될까요?


nil

이 출력되게 된답니다 :) 신기하죠? 그러면 someAnimal은 optional타입이겠네요!




자 이렇게  CLASS / STRUCT / ENUM을 정리해보았는데 어떠신가요? 

다음 글에서는 이  CLASS / STRUCT / ENUM을 언제 쓰면 좋을지에 대해서 정리해볼려고 해요!!!

지적은 환영입니다. 🙏





반응형