구조체는 구조화된 데이터와 기능을 만듦으로써 하나의 사용자 정의 데이터타입을 만들어준다. 구조체의 인스턴스는 값 타입이다.
struct 구조체이름 {
프로퍼티(=멤버변수)와 메서드(=멤버함수)
}
구조체는 따로 생성자를 만들지 않아도 Swift가 알아서 자동으로 멤버변수들을 참조하여 생성자를 준비시켜준다!
struct User {
// 멤버변수
var nickname: String
var age: Int
// 멤버함수
func info() {
print("\(nickname) is \(age)-year old")
}
}
var user = User(nickname: "Gunter", age: 35)
user.nickname
// "Gunter"
user.nickname = "Albert"
user.nickname
// "Albert"
user.info()
// "Albert is 35-year old"
클래스도 구조체와 마찬가지로 구조화된 데이터와 기능을 만듦으로써 하나의 사용자 정의 데이터타입을 만들어준다. 단, 구조체와 달리 클래스의 인스턴스는 참조 타입이다.
class 클래스 이름 {
프로퍼티(=멤버변수)와 메서드(=멤버함수)
}
클래스도 구조체와 동일한 방법으로, 그것의 인스턴스가 멤버변수와 멤버함수에 자유롭게 접근하는 것이 가능하다.
class Dog {
var name: String = ""
var age: Int = 0
func intro() {
print("The name is \(name), age is \(age)")
}
}
var dog = Dog()
dog.name = "Coco"
dog.age = 2
dog.intro()
// "The name is Coco, age is 2"
클래스, 구조체 또는 열거형의 인스턴스를 사용하기 위한 조치를 초기화(Initializer)라고 한다. 흔히 생성자(constructor)라고 부르는 그것이다.
init(매개변수: 타입, ...) {
프로퍼티(=멤버변수) 초기화
인스턴스 생성시 필요한 설정 내용
}
초기화는 반드시 init
구문을 사용해야 하는데, 이때 매개변수를 다양하게 할 때마다 생성자도 그만큼 다양하게 존재할 수 있다.
class User {
var nickname: String
var age: Int
// 멤버변수 nickname, age를 모두 사용하는 생성자
init(nickname: String, age: Int) {
self.nickname = nickname
self.age = age
}
// 멤버변수 age만 사용하는 생성자
init(age: Int) {
self.nickname = "Albert"
self.age = age
}
}
var user = User(nickname: "Gunter", age: 35)
user.nickname
// "Gunter"
user.age
// 35
var user2 = User(age: 23)
user2.nickname
// "Albert"
user2.age
// 23
한편, init
구문과 정반대의 효과를 내는 구문(de-initializer)도 존재한다. 이를 deinit
구문이라고 하며, 인스턴스가 메모리에 해제되기 직전에 호출되어 생성자로 만들어졌던 인스턴스와 그 멤버변수 값이 null이 되면 이것들을 모두 회수해버린다. 따라서 이러한 deinit
구문은 메모리를 '참조'하는 클래스-인스턴스 관계에서만 활용되며, 프로그래머가 원하는 정리작업을 구현해준다.
class User {
var nickname: String
var age: Int
init(nickname: String, age: Int) {
self.nickname = nickname
self.age = age
}
init(age: Int) {
self.nickname = "Albert"
self.age = age
}
// de-initializer
deinit {
print("de-init user!")
}
}
var user3: User? = User(age: 10)
user3 = nil
// de-init user!
클래스, 구조체 또는 열거형 등에 관련된 값으로, 인스턴스의 속성을 의미한다.
클래스, 구조체 또는 열거형 안에서 선언된 상수 또는 변수이다. 구조체 안에서 상수로 선언된 저장 프로퍼티는 인스턴스에서 그 값을 바꿀 수 없다. 또한, 마찬가지로 상수로 선언된 인스턴스는 저장 프로퍼티들의 값을 바꿀 수 없다.
struct Dog {
// 구조체의 저장 프로퍼티 name, gender
var name: String
let gender: String
}
var dog = Dog(name: "Coco", gender: "male")
print(dog)
// Dog(name: "Coco", gender: "male")
dog.gender = "female"
// Cannot assign to property: 'gender' is a 'let' constant
let dog2 = Dog(name: "Kuku", gender: "male")
dog2.name = "Tata"
// Cannot assign to property: 'dog2' is a 'let' constant
반면, 클래스는 참조타입이므로 상수로 선언된 인스턴스라고 할지라도 저장 프로퍼티가 변수형이라면, 인스턴스가 그 저장 프로퍼티의 값을 바꿀 수 있다. 물론, 구조체와 마찬가지로 애초에 상수로 선언된 저장 프로퍼티에 대해서는 인스턴스가 임의로 그 값을 바꿀 수 없다.
class Cat {
// 클래스의 저장 프로퍼티 name, gender
var name: String
let gender: String
init(name: String, gender: String) {
self.name = name
self.gender = gender
}
}
let cat = Cat(name: "Latte", gender: "male")
cat.name = "Jason"
print(cat.name)
// "Jason"
Getter와 Setter를 활용하여 특정 연산을 실행하는 결과값이며, 특히, 인스턴스에서 연산 프로퍼티만 실행할 경우 자동으로 getter 구문의 내용이 실행된다.
struct Stock {
var averagePrice: Int
var quantity: Int
// 구조체의 연산 프로퍼티
var purchasePrice: Int {
get {
return averagePrice * quantity
}
set(newPrice) {
averagePrice = newPrice / quantity
}
}
}
var stock = Stock(averagePrice: 2300, quantity: 3)
// 연산 프로퍼티 Getter를 활용한 경우
stock.purchasePrice
// 6900
// 연산 프로퍼티 Setter를 활용한 경우
stock.purchasePrice = 3000
stock.averagePrice
// 1000
프로퍼티가 변경되는 것을 주시하여 그에 따른 결과를 리턴하는 것으로, willSet
옵져버와 didSet
옵져버가 대표적이다.
class Account {
var credit: Int = 0 {
// 소괄호 이름 지정
willSet {
print("잔액이 \(credit)원에서 \(newValue)원으로 변경예정")
}
didSet {
print("잔액이 \(oldValue)원에서 \(credit)원으로 변경완료")
}
}
}
var account = Account()
account.credit = 1000
// "잔액이 0원에서 1000원으로 변경예정"
// "잔액이 0원에서 1000원으로 변경완료"
인스턴스 생성 없이 객체 내 프로퍼티에 접근 가능하게 해주는 것으로, 프로퍼티를 애초에 static
키워드를 사용하여 선언해주면 된다
struct SomeStructure {
// 스토어
static var storedTypeProperty = "Some value"
// 컴퓨티드
static var computedTypeProperty: Int {
return 1
}
}
SomeStructure.computedTypeProperty
// 1
SomeStructure.storedTypeProperty
// "Some value"
SomeStructure.storedTypeProperty = "hello"
SomeStructure.storedTypeProperty
// "hello"
.
을 사용하여 접근 가능extension
을 사용하여 기능확장 가능Protocol
을 채택하여 기능설정 가능deinit
을 사용하여 클래스 인스턴스의 메모리 할당을 해제할 수 있다.class SomeClass {
var count: Int = 0
}
struct SomeStruct {
var count: Int = 0
}
var class1 = SomeClass()
var class2 = class1
var class3 = class1
class3.count = 2
class1.count
// 2
var struct1 = SomeStruct()
var struct2 = struct1
var struct3 = struct1
struct2.count = 3
struct3.count = 4
struct1.count
// 0