1 Structure
- 여러 타입의 변수를 묶어서 하나의 타입으로 동작하는 자료구조를 만들 수 있다.
- 데이터 + 메서드로 구성되어있고 이를 하나의 object라고 한다.
- value타입으로 전달 시 복사되어 값이 전달 된다. (pass by value)
- structure생성시 stack에 할당된다.
2 Class와의 차이
- class도 structure처럼 여러 변수와 함수를 묶어서 표현하는 도구이다.
- 단 structure와 달리 reference type으로 생성시 heap에 할당된다.
- 두 타입의 차이를 아래 코드에서 살펴보자.
class PersonClass {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
struct PersonStruct {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let pClass1 = PersonClass(name: "Jason", age: 5)
let pClass2 = pClass1
pClass2.name = "Hey"
pClass1.name
pClass2.name
var pStruct1 = PersonStruct(name: "Jason", age: 5)
var pStruct2 = pStruct1
pStruct2.name = "Hey"
pStruct1.name
pStruct2.name
- struct는 값이 복사되기 때문에 나중에 pStruct2를 변경시켜도 pStruct1에는 변화가 없다.
- 하지만 pClass1과 pClass2는 같은 객체를 가리키고 있기 때문에 하나를 변경 시키면 둘다 바뀌는 것이다. 두 변수의 값은 {Jason, 5} 객체의 주소값이라고 생각하자.
3. struct 활용
- struct를 활용해서 내 위치에서 가장 가까운 편의점을 찾는 프로그램을 만들어보자.
import UIKit
// Given distance func
func distance(current: Location, target: Location) -> Double {
// 피타고라스..
let distanceX = Double(target.x - current.x)
let distanceY = Double(target.y - current.y)
let distance = sqrt(distanceX * distanceX + distanceY * distanceY)
return distance
}
struct Location {
let x: Int
let y: Int
}
struct Store {
let loc: Location
var name: String
let deliveryRange = 2.0
func isDeliverable(userLoc: Location) -> Bool {
let distanceToStore = distance(current: userLoc, target: loc)
return distanceToStore < deliveryRange
}
}
// Given stores
let store1 = Store(loc: Location(x: 3, y: 5), name: "gs")
let store2 = Store(loc: Location(x: 4, y: 6), name: "seven")
let store3 = Store(loc: Location(x: 1, y: 7), name: "cu")
// Given printClosestStore func
func printClosestStore(currentLocation: Location, stores: [Store]) {
var closestStoreName = ""
var closestStoreDistance = Double.infinity
var isDeliverable = false
for store in stores {
let distanceToStore = distance(current: currentLocation, target: store.loc)
closestStoreDistance = min(distanceToStore, closestStoreDistance)
if closestStoreDistance == distanceToStore {
closestStoreName = store.name
isDeliverable = store.isDeliverable(userLoc: currentLocation)
}
}
print("Closest store: \(closestStoreName) deliverable: \(isDeliverable)")
}
// Set stores and myLocation
let stores = [store1, store2, store3]
let myLocation = Location(x: 2, y: 5)
// Use printClosestStore func to print
printClosestStore(currentLocation: myLocation, stores: stores)
4 Protocol
- java의 interface와 유사하다. 바로 코드로 살펴보자.
import UIKit
// 도전 과제
// 1. 강의 이름, 강사 이름, 학생수를 가지는 Struct 만들기 (Lecture)
// 2. 강의 어레이이와 강사이름을 받아서 , 해당 강사의 강의 이름을 출력하는 함수 만들기
// 3. 강의 3개 만들고 강사이름으로 강의 찾기
// CustomStringConvertible
struct Lecture: CustomStringConvertible {
var description: String {
return "Title: \(name), Instructor: \(instructor)"
}
let name: String
let instructor: String
let numOfStudent: Int
}
func printLectureName(from instructor: String, lectures: [Lecture]) {
var lectureName = ""
for lecture in lectures {
if instructor == lecture.instructor {
lectureName = lecture.name
}
}
// let lectureName = lectures.first { $0.instructor == instructor }?.name ?? ""
print("아 그 강사님 강의는요: \(lectureName)")
}
let lec1 = Lecture(name: "iOS Basic", instructor: "Jason", numOfStudent: 5)
let lec2 = Lecture(name: "iOS Advanced", instructor: "Jack", numOfStudent: 5)
let lec3 = Lecture(name: "iOS Pro", instructor: "Jim", numOfStudent: 5)
let lectures = [lec1, lec2, lec3]
printLectureName(from: "Jack", lectures: lectures)
print(lec1)
- struct Lecture: CustomStringConvertible에서 CustomStringConvertible이 protocol에 해당한다.
- Lecture라는 struct를 사용하기 위해서는 반드시 CustomStringConvertible를 만족하도록 강제하는 것이다.
- CustomStringConvertible의 조건을 만족시키기 위해서 struct 안에 var description: String를 정의해 주어야 한다.
- description을 정의하고 print(lec1)을 해보면 직접 정의한대로 객체를 설명해준다.
5 Property
- struct 혹은 class가 소유하고 있는 멤버 변수를 stored property라고 한다.
struct Lecture: CustomStringConvertible {
var description: String {
return "Title: \(name), Instructor: \(instructor)"
}
let name: String
let instructor: String
let numOfStudent: Int
}
- 여기서 name, instructor, numOfStrudent가 stored property라고 한다.
- 정보를 저장하지는 않지만 접근될 때마다 정보를 가공해서 제공하는, 예시의 description같은 변수를 computed property라고 한다.
- 두 property를 활용해보자
struct Person {
var firstName: String
var lastName: String
var fullName: String {
get {
return "\(firstName) \(lastName)"
}
}
}
var person = Person(firstName: "Jsd", lastName: "Ysw")
person.firstName = "Yoon"
person.lastName = "sw"
person.fullName
- 위 예제에서는 computed property의 값을 가져오는 것만 가능하다. 이번에는 fullName을 set할 수 있게 해보자
import UIKit
struct Person {
var firstName: String
var lastName: String
var fullName: String {
get {
return "\(firstName) \(lastName)"
}
set {
if let firstName = newValue.components(separatedBy: " ").first {
self.firstName = firstName
}
if let lastName = newValue.components(separatedBy: " ").last {
self.lastName = lastName
}
}
}
}
var person = Person(firstName: "Jsd", lastName: "Ysw")
person.fullName = "Jsd Ysw"
- 지금까지는 person이라는 객체의 인스턴스를 만들어서 프로퍼티에 값을 채웠다
- 이번에는 인스턴스를 생성하지 않고 객체의 property에 접근할 수 있는 type property를 알아보자.
- c++이나 Java에서 클래스 내에 static 멤버변수를 추가하는 것과 비슷하다.
import UIKit
struct Person {
var firstName: String
var lastName: String
static let isAlien: Bool = false
}
Person.isAlien
6 Observation (didset, willset)
- property가 변할 때 감지할 수 있는 방법이다.
- didset을 이용하면 property의 값이 변경되었을 때 실행되는 동작을 정의할 수 있다.
- firstName이 바뀔때마다 변경내역을 출력해보자.
- willset은 값이 변경되기 전에 실행되는 블럭이다.
- "기존의 값에서 새로운 값으로 변경할 것이다"라는 문구를 출력해보자
import UIKit
struct Person {
var firstName: String {
willSet {
print("willSet: \(firstName) ---> \(newValue)")
}
didSet {
print("didSet: \(oldValue) ---> \(firstName)")
}
}
var lastName: String
var fullName: String {
get {
return "\(firstName) \(lastName)"
}
set {
if let firstName = newValue.components(separatedBy: " ").first {
self.firstName = firstName
}
if let lastName = newValue.components(separatedBy: " ").last {
self.lastName = lastName
}
}
}
}
var person = Person(firstName: "Jsd", lastName: "Ysw")
person.firstName = "Yoon"
person.lastName = "sw"
7 Lazy Property
- property에 접근할 때 실행되는 동작을 정의할 수 있다.
- lazy property는 cost가 상대적으로 많이 드는 property의 경우 혹은 모든 Person instance가 접근하는 porperty가 아니고 간혹 사용되는 경우라면 사용자가 property에 접근할 때 동작하도록해서 활용 가능하다.
import UIKit
struct Person {
lazy var isPopular: Bool = {
if fullName == "Famous star" {
return true
} else {
return false
}
}()
}
8 Property vs Method
struct Person {
var firstName: String
var lastName: String
var fullName: String {
return "\(firstName) \(lastName)"
}
func fullName2() -> String {
return "\(firstName) \(lastName)"
}
}
var person = Person(firstName: "Jsd", lastName: "Ysw")
person.fullName
person.fullName2()
- 위의 코드처럼 computed property(fullName)과 method(fullName2)는 서로 같은 결과를 보장한다.
- 그럼 어떤게 더 좋은 방법일까?
- 개인적인 선호가 다를테지만 setter를 사용하는 경우는 computed property를 사용한다. setter를 사용하지 않더라도 위의 예시처럼 단순히 값을 리턴하는 가벼운 동작을 수행한다면 computed property로도 충분할 것이다.
- 반대로 setter를 사용하지 않는데 여러 연산이 필요한 경우는 method가 적절하다.
9 Method
- function이 instance에 귀속된 경우 method라고 한다.
struct Lecture {
var title: String
var maxStudents: Int = 10
var numOfRegistered: Int = 0
func remainSeats() -> Int {
let remainSeats = maxStudents - numOfRegistered
return remainSeats
}
mutating func register() {
// 등록된 학생수 증가시키기
numOfRegistered += 1
}
static let target: String = "Anybody want to learn something"
static func 소속학원이름() -> String {
return "00학원"
}
}
var lec = Lecture(title: "iOS Basic")
lec.remainSeats()
lec.register()
lec.register()
lec.remainSeats()
Lecture.target
Lecture.소속학원이름()
- mutating은 함수가 property를 변경하고자 하는 경우에 붙여야하는 키워드이다.
- static으로 type property를 만들었던 것 처럼 type method도 만들 수 있다. 이 메서드는 인스턴스를 생성하지 않고도 Lecture.으로 접근 가능하다.
10 Extension
- 기존의 구조체에 기능을 확장하고 싶을때 사용한다.
- 기존 구조체의 파일이 숨겨져 있거나 접근할 수 없을때 extension키워드로 손쉽게 확장이 가능하다.
struct Math {
static func abs(value: Int) -> Int {
if value > 0 {
return value
} else {
return -value
}
}
}
Math.abs(value: -20)
// 제곱, 반값
extension Math {
static func sqaure(value: Int) -> Int {
return value * value
}
static func half(value: Int) -> Int {
return value/2
}
}
Math.sqaure(value: 5)
Math.half(value: 20)
- 이번에는 이미 존재하는 Int struct를 확장 해보자
var value: Int = 10
extension Int {
func square() -> Int {
return self * self
}
func half() -> Int {
return self/2
}
}
// 제곱, 반값
value.square()
value.half()
'ComputerScience > ios App(Storyboard)' 카테고리의 다른 글
ios - 12 Table View, Table View Cell (0) | 2021.07.25 |
---|---|
ios - 11 swift 기본문법(Class) (0) | 2021.07.25 |
ios - 9 swift 기본문법 (Closure) (0) | 2021.07.21 |
ios - 8 swift 기본문법(Array, Dictionary, Set) (0) | 2021.07.21 |
ios - 7 swift 기본문법(Function, Optional) (0) | 2021.07.15 |