2.4 Structures

Joohyun·2022년 4월 6일
0

Struct

struct Person {
	// properties
	var name: String
    
    // methods
    func sayHello() {
    	print("Hello! My name is \(name)!")
    }
}

// Instances
let person = Person(name: "Joohyun")
person.sayHello() // "Hello! My name is Joohyun!"

Intializers

  • 가장 일반적인 형태는 파라미터를 가지고 있지 않은 init() 이다.
var string = String.init() // ""
var integer = Int.init() // 0
var bool = Bool.init() // false
  • init()은 생략이 가능하다.
var string = String() // ""

1. Memberwise Initializers

  • structure를 정의할 때, custom initializer를 생성하지 않으면 Swift에서 자동으로 memberwise initializers를 생성해준다.
struct Car {
	var make: String
    var model: String
    var year: Int
    var topSpeed: Int
}

// memberwise initializer
let car = Car(make: "Honda", model: "Civic", year: 2010, topSpeed: 120)
  • default value가 설정된 properties가 있다면 여러개의 memberwise initializers가 생성된다.
struct BankAccount {
	var accountNumber: Int
    var balance: Double = 0
}

var account1 = BankAccount(accountNumber: 123)
var account2 = BankAccount(accountNumber: 456, balance: 1200)

Default Values

  • structure를 정의할 때 default value를 설정하면 해당 값 없이 init을 호출할 때 default value로 해당 값이 설정된다.
  • structure에 있는 모든 properties들이 default value를 갖고있다면, init()을 사용할 수 있다.
struct Odometer {
	var count: Int = 0
}

let odometer = Odometer()
print(odometer.count) // 0

2. Custom Initializers

  • 직접 custom initializer를 정의할 수 있다.
  • 단, custom initializer를 정의하면 Swift에서 자동으로 생성해주는 memberwise initializer를 사용할 수 없다.
struct Temperature {
	var celsius: Double
    
    init(celsius: Double) {
    	self.celsius = celsius
    }
    
    init(fahrenheit: Double) {
    	celsius = (fahrenheit - 32) /1.8
    }
    
    init() {
    	celsius = 0
    }
}

let temp1 = Temperature(celsius: 18.5)
let temp2 = Temperature(fahrenheit: 212.0) // celsius : 100.0
let temp3 = Temperature() // celsius : 0

Instance Methods, Properties

  • 해당 type의 instance를 통해 호출할 수 있는 method이다.
  • structure의 properties에 접근하거나 수정할 수 있다.
struct Size {
	var width: Double
    var height: Double
    
    // Instance Method
    func area() -> Double {
    	width * height
    }
}

let size = Size(width: 10.0, height: 5.5)
let area = size.area() // 55.0

1. Mutating Methods

  • instance method를 통해 structure의 property 값을 수정하려면 mutating을 method앞에 붙여주어야 한다.
struct Odometer {
	var count: Int = 0
    
    // mutating methods
    mutating func increment() {
    	count += 1
    }
    
    mutating func increment(by amount: Int) {
    	count += amount
    }
    
    mutating func reset() {
    	count = 0
    }
}

var odometer = Odometer() // count : 0
odometer.increment() // count : 1
odometer.increment(by: 15) // count : 16
odometer.reset() // count : 0

2. Computed Properties

  • 해당 property에 접근될 때 마다, computed property 내부 로직이 실행되어 값이 수정된다.
  • 섭씨와 화씨온도를 property로 갖고 custom initializer를 포함한 Temperature structure를 가정해보자.
struct Temperature {
	var celsius: Double
    var fahrenheit: Double
    
    init(celsius: Double) {
    	self.celsius = celsius
        fahrenheit = celsius * 1.8 + 32
    }
    
    init(fahrenheit: Double) {
    	self.fahrenheit = fahrenheit
    	celsius = (fahrenheit - 32) / 1.8
    }
}
var temp = Temperature(fahrenheit: 212.0) // celsius: 100, fahrenheit: 212.0

// celsius property를 변경했지만 fahrenheit property가 변경되지 않아 섭씨온도와 화씨온도가 일치하지 않는다.
temp.celsius = 18.5 // celsius: 18.5, fahrenheit: 212.0
  • 이 때, custom initializer 대신 computed property를 이용하면 섭씨온도와 화씨온도 중 하나가 바뀌더라도 나머지 하나의 온도가 자동으로 계산되어 변경되도록 설정할 수 있다.
struct Temperature {
	var celsius: Double
    var fahrenheit: Double {
    	celsius * 1.8 + 32
    }
}

var temp = Temperature(celsius: 0.0) // celsius: 0.0, fahrenheit: 32.0
temp.celsius = 18.5

// 이 때, computed property 내부 로직 실행하여 값 변경됨
print(temp.fahrenheit) // 65.3

3. Property Observers

  • 해당 property에 값이 할당될 떄마다 property observers가 호출된다.

willSet

  • 해당 property에 값이 할당되기 직전에 호출된다.
  • newValue: 새롭게 할당되는 값에 접근

didSet

  • 해당 property에 값이 할당된 직후에 호출된다.
  • oldValue: 할당되기 전의 값에 접근
struct StepCounter {
	var totalSteps: Int = 0 {
    	willSet {
        	print("\(newValue)이 totalSteps에 할당된다")
        }
        didSet {
        	if totalSteps > oldValue {
            	print("\(totalSteps - oldValue)이 더해진다")
            }
        }
    }
}
var stepCounter = StepCounter() // totalStep : 0
stepCounter.totalSteps = 40
// console
40이 totalStep에 할당된다
40이 더해진다

Type Properties, Methods

  • type과 관련되어 있는 properties 또는 methods
  • type을 통해 접근한다.
  • static 키워드를 사용한다.
struct Temparature {
	// type property
    // temperature의 모든 instance들의 끓는 온도는 동일하다.
	static var boilingPoint = 100
}
// Double structure의 type method
// 2개의 Double 타입의 parameter 중에 더 작은 값을 반환
let smallerNumber = Double.minimum(100.0, -1000.0)

Instance Properties, Methods VS Type Properties, Methods

  • Instance Properties, Methods
    - type의 instance를 통해 접근 가능
    - 각각 instance마다 고유할 경우
  • Type Properties, Methods
    - type을 통해 접근 가능
    - type과 관련되어 있어 instance들 모두 같은 값이나 행동을 가짐

Copying

  • structure를 variable에 할당하거나 함수의 parameter로 삽입할 때, 해당 structure의 값이 복제되어 할당된다.
var size = Size(width: 250, height: 1000)
var anotherSize = size

size.width = 500

print(size.width) // 500

// anotherSize에 할당된 값은 size의 복제값이기 때문에 값이 바뀌어도 서로에게 영향을 주지 않는다.
print(anotherSize.width) // 250

Self

  • 현재 type의 instance를 뜻한다.
  • instance에 존재하는 instance method 또는 computed property에서 사용된다.
  • 생략이 가능하지만, 동일한 property 또는 method의 이름이 존재하는 경우에는 self 키워드를 꼭 붙여주어야 한다.
struct Temperature {
	var celsius: Double
    
    init(celsius: Double) {
    	// instance의 property 이름과 initializer의 parameter 이름이 동일하기 때문에 self 키워드를 통해 둘을 구별해주어야 한다.
    	self.celsius = celsius
    }
}

property를 variable로 선언하는 이유

  • 일반적으로 structure의 property는 varialbe로 선언한다.
  • 변경되지 않는 property도 variable로 선언하는 이유는 copy를 통해 새로운 데이터의 값을 편리하게 생성하기 위해서이다.
struct Car {
	var make: String
    var year: Int
    var color: Color
    var topSpeed: Int
}

var car1 = Car(make: "Honda", year: 2010, color: .blue, topSpeed: 120)

// make property가 constant였다면 memberwise initializer를 통해 car2를 생성했어야 할것이다.
var car2 = car1
car1.make = "Ford"
  • 해당 instance의 property가 변경되지 않길 원한다면 instance 값을 constant로 설정하자.
let car = Car(make: "Honda", year: 2010, color: .blue, topSpeed: 120)

car.color = .red // Error
profile
Developer

0개의 댓글