Jihyeonnn
송지현
Jihyeonnn
전체 방문자
오늘
어제
  • Jihyeon Song (29)
    • C++ (0)
    • C (0)
    • Linux (0)
    • iOS (23)
    • JAVA (0)
    • Python (1)
    • GitHub (0)
    • 개인 프로젝트 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Mac
  • 프로그래밍
  • swift
  • generic
  • 파이썬 #python #개발 #기초
  • iOS개발
  • iOS 개발
  • 개발
  • 코딩
  • Mac사용법
  • optionalchaining
  • 개발자
  • ios
  • 기초
  • UI
  • array
  • IT
  • 스위프트

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Jihyeonnn

송지현

iOS

Swift - enum, struct, extension

2025. 4. 16. 15:43

[enum - 열거형]

 

열거형은 처음에만 열거형 이름을 사용하고, 그 후부터는 이름은 생략하고 .부터 사용한다.

enum Compass {
	case North
	case South
	case East
	case West
}

//enum Compass {
//	case North, case South, case East, case West
//} 이렇게도 가능하다.

//var x : Compass // Compass형 인스턴스 x
print(Compass.North) // North
var x = Compass.West
print(type(of:x)) // Compass
x = .East
print(x) // East

 

Swich ~ case 문으로 기능을 만들어 줄 수도 있다.

enum Compass {
    case North
    case South
    case East
    case West
}

var direction : Compass
direction = .North

switch direction { //switch의 비교값이 열거형 Compass
    case .North: //direction이 .North이면 "북" 출력
   	print("북")
    case .South:
    	print("남")
    case .East:
    	print("동")
    case .West:
    	print("서") //모든 열거형 case를 포함하면 default 없어도 됨
}

 

열거형 멤버에 Method도 넣을 수 있다.

enum Week {
    case Mon, Tue, Wed, Thur, Fri, Sat, Sun

    // 각 요일에 대해 "주중" 또는 "주말"을 출력하는 메서드
    func printWeek() {
        switch self {
        case .Mon, .Tue, .Wed, .Thur, .Fri:
            print("주중")
        case .Sat, .Sun:
            print("주말")
        }
    }
}

// 사용 예시
Week.Sun.printWeek()  // "주말" 출력

 

열거형의 rawValue다. Int로 지정했을 때는 아래의 예시와 같이 출력된다.

enum Color: Int {  // 원시값(rawValue) 지정
    case red       // red는 기본값 0을 가짐
    case green = 2 // green은 2로 지정
    case blue      // blue는 기본값 3을 가짐 (green이 2이고 그 뒤는 자동으로 +1)
}

print(Color.red)          // Color.red
print(Color.blue)         // Color.blue
print(Color.red.rawValue) // 0
print(Color.blue.rawValue) // 3

 

String으로 지정했을 때, 값이 지정되지 않으면 case의 이름이 할당된다.

enum Week: String {
    case Monday = "월"
    case Tuesday = "화"
    case Wednesday = "수"
    case Thursday = "목"
    case Friday = "금"
    case Saturday  // 원시값이 지정되지 않으면 케이스 이름 "Saturday"가 자동 할당됨
    case Sunday    // 원시값이 지정되지 않으면 케이스 이름 "Sunday"가 자동 할당됨
}

// 사용 예시
print(Week.Monday)          // Week.Monday
print(Week.Monday.rawValue) // 월
print(Week.Sunday)          // Week.Sunday
print(Week.Sunday.rawValue) // Sunday

 

연관 값을 갖는 enum. todayDate = Date.st~ 구문을 주석 처리하면 2025년 4월 30일이 출력된다.

enum Date {
    case intDate(Int, Int, Int)  // (Int, Int, Int)형 연관값을 갖는 intDate
    case stringDate(String)      // String형 연관값을 갖는 stringDate
}

var todayDate = Date.intDate(2025, 4, 30)  // 연관값이 (2025, 4, 30)인 intDate
todayDate = Date.stringDate("2025년 5월 20일")  // 연관값이 "2025년 5월 20일"인 stringDate로 변경

switch todayDate {
case .intDate(let year, let month, let day):  // intDate일 경우
    print("\(year)년 \(month)월 \(day)일")
case .stringDate(let date):  // stringDate일 경우
    print(date)
}

 

옵셔널은 연관 값을 갖는 enum이다.

let age: Int? = 30  // Optional(30)

switch age {
case .none:  // nil인 경우
    print("나이 정보가 없습니다.")
case .some(let a) where a < 20:  // 값이 20 미만일 경우
    print("\(a)살 미성년자입니다.")
case .some(let a) where a < 71:  // 값이 20 이상 71 미만일 경우
    print("\(a)살 성인입니다.")
default:  // 그 외 (71 이상일 경우)
    print("경로우대입니다.")
}

//출력
//30살 성인입니다.
//public enum Optional<Wrapped> {
//	case none
//	case some(Wrapped)
//} 이 소스는 iOS에서 이미 만들어 둔 소스기 때문에 작성하지 않아도 된다.

var x : Int? = 20 //.some(20)
var y : Int? = Optional.some(10)
var z : Int? = Optional.none
var x1 : Optional<Int> = 30
print(x, y, z, x1) 
//Optional(20) Optional(10) nil Optional(30)

 

[struct - 구조체]

 

구조체는 Memberwise Initializer가 자동으로 만들어진다는 게 장점이다.

구조체에 초기값을 지정해 주는 경우다.

struct Resolution {
    var width = 1024
    var height = 768
}

let myComputer = Resolution()
print(myComputer.width)  // 1024

 

초기값이 없는 경우, 보통은 아래처럼 init을 만들어 오류를 제거해 주어야 하는데

struct Resolution {
    var width: Int
    var height: Int
    init(width:Int, height:Int){
        self.width = width
        self.height = height
    }
}

let myComputer2 = Resolution(width: 1920, height: 1080)
print(myComputer2.width)  // 1920

 

Swift는 자동으로 만들어 주기 때문에 없어도 잘 돌아간다!

struct Resolution {
    var width: Int
    var height: Int
}

let myComputer2 = Resolution(width: 1920, height: 1080)
print(myComputer2.width)  // 1920

 

class 안에 struct를 넣을 수 있다.

struct Resolution {
    var width = 1024
    var height = 768
}

class VideoMode {
    var resolution = Resolution()
    var frameRate = 0.0
}

let myVideo = VideoMode()
print(myVideo.resolution.width

 

Swift의 기본 데이터 타입은 모두 구조체이다.

public struct Int
public struct Double
public struct String
public struct Array<Element> 
.
.
.

 

클래스와 구조체는 무엇이 다른가?

 

비교 항목 구조체(struct) 클래스(class)
타입 값 타입. 복사됨 (Value Type) 참조 타입. 참조됨 (Reference Type)
상속 ❌ 지원하지 않음 ✅ 지원함
초기화 멤버와이즈 초기화자 제공 직접 init 정의 필요

 

구조체는 값 타입이기 때문에 lee에 kim을 대입하였을 때 복사가 된다. kim의 나이를 바꿔도 lee의 나이는 변하지 않는다.

struct Human {
    var age : Int = 1
}
var kim = Human()
var lee = kim //값 타입
print(kim.age, lee.age) //1 1
lee.age = 20
print(kim.age, lee.age) //1 20
kim.age = 30
print(kim.age, lee.age) //30 20

 

하지만 클래스는 참조 타입이라 kim과 lee가 한 번에 바뀐다. struct에서 class로만 바뀌었는데 머리가 아파진다.

kim과 lee가 '같은 객체'를 참조하고 있기 때문에 lee가 바뀌어도 kim이 함께 바뀐다!

(lee = kim임에도 같은 객체를 가리키는 참조, 주소를 공유하기 때문에! kim은 lee에게 자신의 주소를 대입한 것이다.)

class Human {
    var age : Int = 1
}
var kim = Human()
var lee = kim //값 타입
print(kim.age, lee.age) //1 1
lee.age = 20
print(kim.age, lee.age) //20 20
kim.age = 30
print(kim.age, lee.age) //30 30

 

그 다른 예제이다.

// 구조체 정의
struct Resolution {
    var width = 0
    var height = 0
}

// 클래스 정의
class VideoMode {
    var resolution = Resolution()
    var frameRate = 0
    var name: String?
}

// 구조체는 값 타입 (Value Type)
var hd = Resolution(width: 1920, height: 1080)
var highDef = hd  // 복사됨

print(hd.width, highDef.width)  // 1920 1920

hd.width = 1024  // hd만 변경됨
print(hd.width, highDef.width)  // 1024 1920

// 클래스는 참조 타입 (Reference Type)
var xMonitor = VideoMode()
xMonitor.resolution = hd
xMonitor.name = "LG"
xMonitor.frameRate = 30

print(xMonitor.frameRate)  // 30

var yMonitor = xMonitor  // 같은 객체를 참조

yMonitor.frameRate = 25

print(yMonitor.frameRate)  // 25
print(xMonitor.frameRate)  // 25 (같은 객체이므로 함께 변경됨)

 

[Class vs Struct]

덩치가 커지거나, 기능적으로 많은 것들이 필요한 경우 클래스를 사용한다.

하지만, 멀티 쓰레드 환경이라면 구조체가 더 안전하며 상속할 필요가 없는 경우에 사용한다.

그 예로 너비, 높이 표현하는 기하학적 모양 / 시작값, 증분, 길이 등의 순열 / 3차원 좌표 시스템의 각 좌표 등이 있다.


[extension] 

클래스, 구조체, 열거형, 프로토콜에 새로운 기능을 추가할 때 사용한다.

extension은 기존 클래스에 메서드나 생성자, 계산 프로퍼티 등 기능을 추가할 때 사용한다.

 

앞서 말했듯이 Double 역시 iOS에서 구조체로 만들어 두었다. isZero도 그 안에 만들어져 있는 친구다.

여기에 내가 원하는 기능을 함수와 같이 추가할 수 있는데, 그것이 extension의 역할이다.

아래의 예시를 참고하면 되겠다.

extension Double {
        var squared : Double {
        return self * self
    }
}

let myValue: Double = 3.0
print(myValue.squared) //과제
print(3.5.squared) //Double형 값에도 .으로 바로 사용 가능
print(myValue.isZero) //instance property

 

 

'iOS' 카테고리의 다른 글

Swift - Open API 기반 앱 만들기  (0) 2025.05.07
Swift - Optional Chaining, Throwing function, Generic, Array  (0) 2025.04.09
Swift - TableView  (0) 2025.04.02
Swift - 프로토콜  (0) 2025.03.26
Swift의 주요 문법 복습  (0) 2025.03.26
    'iOS' 카테고리의 다른 글
    • Swift - Open API 기반 앱 만들기
    • Swift - Optional Chaining, Throwing function, Generic, Array
    • Swift - TableView
    • Swift - 프로토콜
    Jihyeonnn
    Jihyeonnn

    티스토리툴바