구조체
struct 구조체이름 {
}
클래스
class 클래스이름 {
}
- Camel Case
- 구조체 이름의 첫 글자는 대문자로 시작한다
- ❌ 언더바는 사용하지 않는게 좋다 ❌
Properties
- 내부에서 정의된 변수, 상수
- 특정 값을 저장하기 위함
Method
- 내부에서 정의된 특정 기능을 담당하는 함수
- Properties& Method 구조체 EX
struct Resolution {
var width = 0
var height = 0
func desc() -> String {
return "Resolution 구조체"
}
}
- 저장 프로퍼티 - width, height
- 0으로 초기화 되었으므로 타입추론규칙에 의해 Int 데이터 타입으로 추론된다
- Properties& Method 클래스 EX
class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
func desc() -> String {
return "VideoMode 클래스"
}
}
- name은 초기값 할당되지 않음 + 옵셔널 타입 프로퍼티
- 이런 경우에는 nil 값으로 초기화된다 (값이 존재하지 않음)
Instance
- 클래스로부터 만들어진 객체
- 실제로 메모리에 할당되어서 동작할 수 있는 모양을 갖춘 것
// Resolution 구조체에 대한 인스턴스를 생성하고 상수 insRes에 할당
let insRes = Resolution()
// VideoMode 클래스에 대한 인스턴스를 생성하고 상수 insVMode에 할당
let insVMode = VideoMode()
- 구조체/클래스 뒤에 오는 소괄호는 인스턴스 생성 연산자
- . 점 구문(Dot Syntax)를 이용해서 인스턴스 하위 객체(혹은 프로퍼티의 값)에 접근 / 할당 할 수 있다
<인스턴스 이름>.<프로퍼티 이름>
// 연속해서 사용할 수 있다
vMode.res.width
- 점 구문을 연속으로 연결해서 사용할 수 있다
- 이것을 체인 Chain 방식이라고 한다
Initialize
- 명시적인 초기화
- 프로퍼티를 선언하는 동시에 초기값 지정
- 초기화 메서드 안에서 프로퍼티의 초기값 지정
- ⭐ 모든 프로퍼티는 인스턴스가 생성되는 시점까지는 반드시 초기화되어야 한다 ⭐
- 명시적인 초기화의 경우가 아니라면, 옵셔널 타입으로 선언해서 자동으로 nil을 할당받게 만들어주어야 한다
- 구조체 Initialize
- 멤버와이즈 초기화 구문 Memberwise Initialiser
- 모든 프로퍼티의 값을 인자값으로 입력받아 초기화하는 기본 초기화 구문
- 인스턴스를 생성하는 형식 정의
- 입력된 인자값을 이용해서 프로퍼티를 초기화
// width와 height를 매개변수로 하여 Resolution 인스턴스를 생성
let defaultRes = Resolution(width: 1024, height: 768)
print("width : \(defaultRes.width), height : \(defaultRes.height)")
// 실행 결과
width : 1024, height : 768
- 빈 괄호 초기화 구문
- 아무런 인자값을 입력받지 않음
- 어떤 프로퍼티도 초기화하지 않음
- 단순히 구조체의 인스턴스를 생성하기만 한다
- 사용하려면, 모든 프로퍼티는 선언과 동시에 초기화가 되어 있어야 한다
- 클래스 Initialize
- 빈 괄호 초기화 구문 사용
- 클래스의 초기화 원칙
- 모든 프로퍼티는 정의할 때 초기화를 한다 OR 옵셔널 타입으로 선언한다
- 인스턴스를 생성할 때는 클래스 명 뒤에 소괄호() - 인스턴스 생성 연산자 - 를 붙여준다
구조체의 값 전달 Value Type
- 복사에 의한 전달
- 생성하는 모든 구조체 인스턴스들이 상수나 변수에 할당될 때 / 함수의 인자값으로 사용될 때 복사해서 사용된다
- 정수, 문자열, 배열 또는 딕셔너리 등 기본 자료형들은 모두 복사를 통해 값이 전달된다
- 해당 자료형이 구조체로 구현되었기 때문에
- 변수에 대입된 인스턴스와 기존의 인스턴스는 서로 독립적
- 구조체 인스턴스를 변수에 대입하면 기존의 인스턴스가 그대로 대입되는 것이 아니라 이를 복사한 새로운 값이 대입
- 서로에게 전혀 영향을 미치지 않는다
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
#1
print("cinema 인스턴스의 width 값은 \(cinema.width)입니다")
// 실행 결과
cinema 인스턴스의 width 값은 2048입니다
#2
print("hd 인스턴스의 width 값은 \(hd.width)입니다")
// 실행 결과
hd 인스턴스의 width 값은 1920입니다
클래스의 값 전달 Reference Type
- 참조에 의한 전달
- 참조❓
- 인스턴스가 저장된 메모리 주소 정보가 전달
- 항상 메모리 주소를 사용해 객체 자체를 전달
- 단순히 값을 넘긴다고 생각해도 된다
- 클래스는 참조 타입이기 때문에, 한 곳에서 수정할 경우 다른 곳에서도 적용된다
- 다양한 인자값에서 동시에 참조할 수 있어서, 메모리에 대한 이슈가 있다
- 클래스의 값 전달 Reference Type EX
let video = VideoMode()
video.name = "Original Video Instance"
print("video 인스턴스의 name 값은 \(video.name!)입니다.")
// video 인스턴스의 name 값은 Original Video Instance입니다.
let dvd = video
dvd.name = "DVD Video Instance"
print("video 인스턴스의 name 값은 \(video.name!)입니다")
// video 인스턴스의 name 값은 DVD Video Instance입니다
- 상수 video 는 클래스 VideoMode를 초기화하여 생성한 인스턴스이다
- 인스턴스 video의 name 값을 입력해주었고, 설정되었다
- 상수 dvd 는 인스턴스 video를 할당받았다
- dvd의 속성값을 변경하였더니 video 의 속성값(프로퍼티)도 변경되었다
func changeName(v: VideoMode) {
v.name = "Function Video Instance"
}
changeName(v: video)
print("video 인스턴스의 name 값은 \(video.name!)입니다")
// video 인스턴스의 name 값은 Function Video Instance입니다
- changeName 함수가 인자값으로 video 인스턴스를 전달받아서 프로퍼티 값을 변경하였다
- inout 키워드가 없지만, 클래스 타입이기 때문에 원본 인스턴스의 참조가 전달되었다
- inout 키워드에 대한 설명 > https://yy-dev.tistory.com/13
ARC
- Auto Reference counter
- 지금 클래스 인스턴스를 참조하는 곳이 모두 몇 군데인지 자동으로 카운트해주는 객체
- 인스턴스를 모니터링하며 변수나 상수, 함수의 인자값으로 할당되면 카운트를 1 증가
- 해당 변수나 상수들이 종료되면 카운트를 1 감소
- 위의 두가지 계산을 통해 인스턴스의 참조 수를 파악
- 인스턴스의 참조 카운트가 0이 되면 메모리 해제 대상으로 간주하여 적절히 메모리에서 해제
클래스 인스턴스의 비교 연산자
- 동일 인스턴스인지 비교 : ===
- 동인 인스턴스가 아닌지 비교 : !==
if (video === dvd) {
print("video와 dvd는 동일한 VideoMode 인스턴스를 참조하고 있군요")
} else {
print("video와 dvd는 서로 다른 VideoMode 인스턴스를 참조하고 있군요")
}
// 실행 결과
video와 dvd는 동일한 VideoMode 인스턴스를 참조하고 있군요
- video는 VideoMode 클래스의 인스턴스를 참조받았다
- dvd는 video 인스턴스를 참조받았다
- 두 상수는 동일한 클래스 인스턴스를 참조한다
- 비교 연산 true
let vs = VideoMode()
let ds = VideoMode()
if (vs === ds) {
print("vs와 ds는 동일한 VideoMode 인스턴스를 참조하고 있습니다")
} else {
print("vs와 ds는 서로 다른 VideoMode 인스턴스를 참조하고 있습니다")
}
// 실행 결과
vs와 ds는 서로 다른 VideoMode 인스턴스를 참조하고 있습니다
- vs 인스턴스와 ds 인스턴스는 각각 VideoMode 클래스의 인스턴스를 새롭게 생성하여 참조받았다
- 동일한 타입의 인스턴스이지만, 같은 메모리 주소를 참조하는 것은 아니다
- 비교 연산 false
구조체를 사용하는 경우
- 서로 연관된 몇 개의 기본 데이터 타입들을 캡슐화하여 묶는 것이 목적일 때
- 캡슐화된 데이터에 상속이 필요하지 않을 때
- 캡슐화된 데이터를 전달하거나 할당하는 과정에서 참조 방식보다는 값이 복사되는 것이 합리적일 때
- 캡슐화된 원본 데이터를 보존해야 할 때
- 위의 4가지에 해당하지 않는다면 클래스를 정의해서 사용하는 게 좋다
'iOS > Swift' 카테고리의 다른 글
[Swift] 클래스/구조체 언제 사용할까? (0) | 2023.11.20 |
---|---|
[Swift] 열거형 enum (0) | 2023.11.20 |
[Swift] 일급함수(일급객체), 클로저(익명함수) (0) | 2023.11.14 |
[Swift] 함수,매개변수,inout 키워드 (0) | 2023.11.14 |
[Swift] 옵셔널 Optional (0) | 2023.11.14 |