궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFT/Grammar

Swift : 기초문법 [구조체 - Struct]

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

본 게시글은 yagom님의 Swift 프로그래밍 3판을 참고하여 작성되었습니다.

 

STRUCT(구조체)

  • CLASS와 다르게 상속이 불가능합니다.
  • (인스턴스/타입) 메서드, (인스턴스/타입) 프로퍼티 (클래스와 같음)
  • 값타입(value 라고 부름)
  •  Swift의 대부분의 큰 뼈대는 모두 STRUCT(구조체)로 구성이 되어있습니다.
  •  Int, Double, String 등 데이터 타입 

Struct를 사용하는 경우

  • 연관된 몇몇의 값들을 모아서 하나의 데이터 타입으로 표현하고 싶을 때,
  • 다른 객체 또는 함수 등으로 전달될 때 참조가 아닌 복사를 원할 때,
  • 자신을 상속할 필요가 없거나 자신이 다른 타입을 상속받을 필요가 없을 때,
  • Apple 프레임워크에서 프로그래밍을 할 때에는 주로 클래스를 많이 사용한다.

키워드 struct

struct 구조체 이름 {
   프로퍼티와 메서드
}
struct Sport {
    var name: String
}

Sport이름을 문자열로 저장하는 구조체를 만들었습니다. 구조체 내부의 변수를 프로퍼티라고 하므로 속성이 하나인 구조체입니다. 이제 인스턴스를 만들고 사용할 수 있습니다.

var tennis = Sport(name: "Tennis")
print(tennis.name)

예시 

struct Book {
	var title: String
	var author = "Unknown"
	var pageCount = 0
}

 

struct Player {
	var name: String
	var position: String
}
let harry = Player(name: "Harry Kane", position: "Forward")

구조체 인스턴스 생성 및 초기화

구조체를 정의하고 인스턴스를 생성하고 초기화 할때는 멤버와이즈 이니셜라이저를 사용합니다. 구조체의 프로퍼티 이름으로 자동으로 지정됩니다. 

 

만약 인스턴스가 생성되고 초기화된 후에 프로퍼티 값에 접근하려면 마침표를 사용하면 됩니다.

struct character {
    var name: String
    var isfavorite: Bool
    
}

var myCharacter: character = character(name: "포뇨", isfavorite: true)
myCharacter.name = "소피아"
myCharacter.isfavorite = false

print(myCharacter)  //character(name: "소피아", isfavorite: false)

Struct의 장점

  • 속도 : 값 타입은 시스템 리소스를 적게 먹음
  • 안전성 : 클래스는 참조 타입이기 때문에 '원본'에 바로 접근이 가능하지만, 구조체는 원본은 그대로 두고 복사가 일어나기 때문에 원본을 지킬 수 있음. 클래스보다 안전한 코딩이 가능함. 여러 클래스 또는 다중 스레드 환경에서 변수를 전달할 때 유용, 변수의 복사본을 다른 곳으로 보낼 수 있으면 다른 곳에서 변숫값을 변경하는 것에 대해 걱정할 필요가 없음.
  • 구조체의 주요 목적은 비교적 간단한 데이터 값을 캡슐화하는 것
struct Sport {
    var name: String
    var isOlympicSport: Bool

    var olympicStatus: String {
        if isOlympicSport {
            return "\(name) is an Olympic sport"
        } else {
            return "\(name) is not an Olympic sport"
        }
    }
}

만약 lisOlympicSport 가 ture 이거나 false일때 값을 반환도 록 저장하는 기능도 있습니다. 이제 호출해보겠습니다.

let chessBoxing = Sport(name: "chessBoxing", isOlympicSport: true)
print(chessBoxing.olympicStatus)

//chessBoxing is an Olympic sport

예시

struct Code {
    var language: String
    var containsErrors = false
    var report: String {
        if containsErrors {
            return "This \(language) code has bugs!"
        } else {
            return "This looks good to me."
        }
    }
}
let Korean = Code(language: "Korean", containsErrors: true)
print(Korean.report)
//This Korean code has bugs!
struct Race {
	var distance: Int
	var runners = 0
	var description: String {
		return "This is a \(distance)km race with \(runners) runners."
	}
}
let londonMarathon = Race(distance: 42, runners: 40_000)

잘못된 예시

만약 아래 코드와 같이 반환하지 않고 사용한다면 오류가 생깁니다.

struct Dog {
    var breed: String
    var cuteness: Int
    var rating: String {
        if cuteness < 3 {
            print("That's a cute dog!")
        } else if cuteness < 7 {
            print("That's a really cute dog!")
        } else {
            print("That a super cute dog!")
        }
    }
}
let luna = Dog(breed: "Samoyed", cuteness: 11)
print(luna.rating)

반드시 String 값을 return 해줘야 합니다

struct Dog {
    var breed: String
    var cuteness: Int
    var rating: String {
        if cuteness < 3 {
            return "That's a cute dog!"
        } else if cuteness < 7 {
            return "That's a really cute dog!"
        } else {
            return "That a super cute dog!"
        }
    }
}
let luna = Dog(breed: "Samoyed", cuteness: 11)
print(luna.rating)

Struct는 그럼 언제 써야 해?

구조체를 먼저 말씀드리면,

  • 참조가 아닌 복사를 원할 때
  • 자신을 상속할 필요가 없거나 자신이 다른 타입을 상속받을 필요가 없을 때 
  • 연관된 몇몇의 값들을 모아서 하나의 데이터 타입으로 표현하고 싶을 때

쓰게 됩니다! 클래스는 반대로 생각하면 됩니다. 하지만 이렇다고 해서 어느 때는 클래스를 써야만 해!! 이때는 구조체만 써! 딱 이런 기준은 없습니다.

 

하지만 swift 언어 가이드에서 도움이 될만한 기준을 제시해주었는데요, 아래의 조건 중에 한 가지 또는 그 이상 해당하는 경우에는 구조체를 생각하시면 됩니다.

  • 구조체의 주목적이 몇몇 연관성 있는 간단한 데이터 값의 캡슐화일 경우
  • 캡슐화 된 값들이 그 구조체의 인스턴스가 할당될 때나 전달될 때 참조보다는 복사가 예상될 경우
  • 구조체에 저장되는 모든 프로퍼티들이 참조보다는 복사가 예상되는 값 형식일 경우
  • 구조체가 다른 형(type)에서부터 프로퍼티나 기능이 상속될 필요가 없을 경우

Struct를 사용하는 좋은 예

  • Double형을 갖는 width와 height 프로퍼티의 캡슐화를 하는 기하학적 모형의 사이즈.
  • Int형을 갖는 start와 length 프로퍼티의 캡슐화를 하는 시리즈의 범위에 접근하는 방법.
  • Double형을 갖는 x, y와 z 프로퍼티의 캡 슈화를 하는 3차원 좌표 시스템의 포인터.

이외의 경우에는 클래스로 정의하며, 레퍼런스로 전달되고 관리되는 클래스의 인스턴스를 생성하시면 됩니다.

실질적으로는 대부분의 사용자 데이터 형은 구조체가 아닌 클래스로 정의되어야 합니다.

튜플과 Struct의 차이점

Swift의 튜플을 사용하면 단일 변수 내에 여러 개의 다른 이름이 지정된 값을 저장할 수 있으며 구조체와 거의 동일합니다. 하지만 차이점이 있습니다. 튜플은 이름이 없는 구조체라고 생각하면 쉽습니다. (name: String, age: Int, city: String) 과 같이 말이죠. 이것을 구조체로 작성하면 아래와 같습니다.

struct User {
    var name: String
    var age: Int
    var city: String
}

만약 구조체로 사용하지 않고 튜플로 작성했다면, 문제가 생길 수 있습니다. 튜플은 일회성에서 사용하기 좋지만, 여러 번 사용해야 할 때 귀찮아질 수 있고 문제가 생길 수 도 있습니다.

Struct로 작성한 코드

func authenticate(_ user: User) { ... }
func showProfile(for user: User) { ... }
func signOut(_ user: User) { ... }

튜플로 작성한 코드

func authenticate(_ user: (name: String, age: Int, city: String)) { ... }
func showProfile(for user: (name: String, age: Int, city: String)) { ... }
func signOut(_ user: (name: String, age: Int, city: String)) { ... }

TIP
 
 

따라서 함수에서 두 개 이상의 임의 값을 반환하고 싶을 때 , 튜플을 사용하고 / 여러 번 보내거나 받고 싶은 고정 데이터가 있는 경우 구조체를 선호합니다.

 

읽어주셔서 감사합니다🤟

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.