15 Jan 2020
|
swift
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
인프런, 야곰의 스위프트 기본문법 강좌를 듣고 정리하였습니다.
프로퍼티(property)
- 저장 프로퍼티(stored property)
- 연산 프로퍼티(computed property)
- 인스턴스 프로퍼티(instance property)
- 타입 프로퍼티(type property)
프로퍼티는 구조체, 클래스, 열거형 내부에 구현함으로써 타입과 연관된 값들을 표현할 떄 사용한다.
struct Student {
// 인스턴스 저장 프로퍼티
var name: String = ""
var `class`: String = "Swift"
var koreanAge: Int = 0
// 인스턴스 연산 프로퍼티
var westernAge: Int {
// westernAge 값을 꺼내가려 한다면 koreanAge의 값을 역으로 환산하여 가져간다.
get {
return koreanAge -1
}
// westernAge라는 프로퍼티에 값을 셋팅하면 직접 값을 저장하는게 아니라
// koreanAge의 프로퍼티의 값들을 연산하여 할당하거나 변환해준다.
set(inputValue) {
koreanAge = inputValue + 1
}
}
// 타입 저장 프로퍼티: 타입과 연관되어 저장이 될 프로퍼티
static var typeDescription: String = "학생"
// 읽기 전용 인스턴스 연산 프로퍼티(get만 구현되어있을때)
var selfIntroduction: String {
get {
return "저는 \(self.class)반 \(name)입니다."
}
}
// 타입 메서드
static var selfIntroduction: String {
return "학생 타입입니다"
}
}
// 타입 연산 프로퍼티 사용
print(Student.selfIntroduction) // 학생 타입입니다
// 인스턴스 생성
var zehye: Student = Student()
zehye.koreanAge = 10
// 인스턴스 저장 프로퍼티 사용
zehye.name = "zehye"
print(zehye.name) // zehye
// 인스턴스 연산 프로퍼티 사용
print(zehye.selfIntroduction) // 저는 Swift반 zehye입니다.
print("제 한국나이는 \(zehye.koreanAge)살이고, 미쿸 나이는 \(zehye.westernAge)살 입니다.")
응용
struct Money {
var currentcyRate: Double = 1100
var dollar: Double = 0
var won: Double {
get {
return dollar * currentcyRate
}
set {
dollar = newValue / currentcyRate
}
}
}
var moneyInMyPocket = Money()
moneyInMyPocket.won = 110000
print(moneyInMyPocket.won) // 110000.0
moneyInMyPocket.dollar = 10
print(moneyInMyPocket.won) // 11000.0
저장 프로퍼티와 연산 프로퍼티의 기능은 함수, 메서드, 클로저, 타입 등의 외부에 위치한 지역/전역 변수에도 모두 사용가능하다.
var a: Int = 100
var b: Int = 200
var sum: Int {
return a + b
}
print(sum) // 300
프로퍼티 감시자(property observer)
프로퍼티 감시자를 사용하면 프로퍼티 값이 변경될 때 원하는 동작을 수행할 수 있다.
struct Money {
var currentcyRate: Double = 1100 {
willSet(newRate) {
print("환율이 \(currentcyRate)에서 \(newRate)으로 변경될 예정입니다")
}
didSet(oldRate) {
print("환율이 \(oldRate)에서 \(currentcyRate)으로 변경되었습니다")
}
}
}
즉, currentcyRate 값이 변경될 때 willSet, didSet
이 동작하게 된다.
- willSet: currentcyRate가 바뀌기 직전에 동작
- didSet: currentcyRate가 바뀌고 난 후 동작
var dollar: Double = 0 {
willSet { // willSet의 암시적 매개변수 이름 newValue
print("\(dollar)달러에서 \(newValue)달러로 변경될 예정입니다")
}
didSet { // didSet의 암시적 매겨변수 이름 oldValue
print("환율이 \(oldValue)달러에서 \(dollar)달러로 변경되었습니다")
}
}
연산 프로퍼티에서의 사용
프로퍼티 감시자와 연산 프로퍼티 기능을 동시에 사용은 불가능하다 > willSet, didSet은 저장되는 값이 변경될 때 호출되기 때문
var won: Double {
get {
return dollar * currentcyRate
}
set {
dollar = newValue / currentcyRate
}
}
프로퍼티 감시자의 사용
var moneyInMyPocket: Money = Money()
// 환율이 1100.0에서 1150.0으로 변경될 예정입니다
moneyInMyPocket.currentcyRate = 1150
// 환율이 1100.0에서 1150.0으로 변경되었습니다
// 0.0달러에서 10.0달러로 변경될 예정입니다
moneyInMyPocket.dollar = 10
// 0.0달러에서 10.0달러로 변경되었습니다
print(moneyInMyPocket.won) // 11500.0
프로퍼티 감시자의 기능은 함수, 메서드, 클로저, 타입 등의 외부에 위치한 지역/전역 변수에도 모두 사용가능하다.
var a: Int = 100 {
willSet {
print("\(a)에서 \(newValue)로 변경될 예정입니다"
}
didSet {
print("\(oldValue)에서 \(a)로 변경되었습니다")
}
}
// 100에서 200으로 변경될 예정입니다
a = 200
// 100에서 200으로 변경되었습니다
15 Jan 2020
|
swift
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
인프런, 야곰의 스위프트 기본문법 강좌를 듣고 정리하였습니다.
클로저(Closure)
코드의 블럭으로 일급시민(first-citizen)이다.
일급 객체란 전달 인자로 보낼 수 있고, 변수/상수 등으로 저장하거나 전달할 수 있으며, 함수의 반환 값이 될 수도 있습니다.
따라서 변수, 상수등으로 저장, 전달인자로 전달이 가능하다. 함수의 경우 클로저의 일종으로 이름이 있는 클로저이다.
{ (매개변수 목록) -> 반환타입 in
실행 코드
}
예시는 아래와 같다.
func sumFunction(a: Int, b:Int) -> Int {
return a + b
}
var sumResult: Int = sumFunction(a:1, b:2)
print(sumResult) // 3
// 위 코드를 클로저를 이용해 나타내본다.
var sum: (Int, Int) -> Int = {(a: Int, b:Int) -> Int in return a + b}
sumResult = sum(1,2)
print(sumResult) // 3
함수는 클로저의 일종으로 sum 변수에는 당연히 함수도 할당할 수 있다.
sum = sumFunction(a:b:)
sumResult = sum(1,2)
print(sumResult) // 3
함수의 전달인자로서의 클로저
let add: (Int, Int) -> Int
add = {(a: Int, b:Int) -> Int in return a + b}
let substract: (Int, Int) -> Int
substract = {(a:Int, b:Int) -> Int in return a - b}
let divide: (Int, Int) -> Int
divide = {(a:Int, b:Int) -> Int in return a / b}
func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int { return method(a,b ) }
var calculated: Int
calculated = calculate(a: 50, b: 20, method: add)
print(calculated) // 70
calculated = calculate(a:50, b:20, method: substract)
print(calculated) // 40
calculated = calculate(a:50, b:25, method: divide)
print(calculated) // 2
calculated = calculate(a:50, b:10, method: { (left: Int, right: Int) -> Int in return left * right })
print(calculated) // 500
클로저 고급
너무 다양한 표현법이 있기 떄문에, 적당한 축약 문법어를 사용해야 한다.
- 후행 클로저
- 반환타입 생략
- 단축 인자이름
- 암시적 반환 표현
func calculate(a:Int, b:Int, method: (Int, Int) -> Int) -> Int {
return method(a, b)
}
method라는 이름으로 클로저를 전달받는 함수
후행 클로저
클로저가 함수의 마지막 전달인자라면 마지막 매개변수 이름을 생략한 후 함수 소괄호 외부에 클로저를 구현할 수 있다.
result = calculate(a: 10, b:10) {(left: Int, right: Int) -> Int in return left + right }
print(result) // 20
반환타입 생략
calculate 함수의 method 매개변수는 Int 타입을 반환할 것이라는 사실을 컴파일러도 알기 때문에 굳이 클로저에서 반환타입을 명시해 주지 않아도 된다.
대신 in 키워드는 생략할 수 없다.
result = calculate(a:10, b:10, method: {(left: Int, right: Int) in return left + right })
print(result) // 20
// 후행 클로저와 같이 사용 가능하다.
result2 = calculate(a:10, b:10) {(left: Int, right: Int) in return left + right }
print(result2) // 20
단축 인자이름
클로저의 매개변수 이름이 굳이 불필요하다면 단축 인자이름을 활용할 수 있다.
단축 인자이름은 클로저의 매개변수의 순서대로 $0, $1… 처럼 사용 가능하다.
result = calculate(a: 10, b:10, method: { return $0 + $1 })
print(result) // 20
// 후행 클로저와 같이 사용 가능하다.
result2 = calculate(a:10, b:10) {return $0 + $1}
print(result2) // 20
암시적 반환 표현
클로저가 반환하는 값이 있다면 클로저의 마지막 줄의 결과값은 암시적으로 반환값으로 취급한다.
result = calculate(a: 10, b: 10) { $0 + $1 }
print(result) // 20
15 Jan 2020
|
swift
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
인프런, 야곰의 스위프트 기본문법 강좌를 듣고 정리하였습니다.
Class
- 전통적인 OOP관점에서의 클래스
- 단일 상속
- (인스턴스/타입) 메서드
- (인스턴스/타입) 프로퍼티
- 참조타입
- Apple 프레임워크의 대부분의 큰 뼈대는 모두 클래스로 구성
Struct
- C언어 등의 구조체보다 다양한 기능
- 상속 불가
- (인스턴스/타입) 메서드
- (인스턴스/타입) 프로퍼티
- 값 타입
- Swift의 대부분의 큰 뼈대는 모두 구조체로 구성
Enum (Enumeration)
- 다른 언어의 열거형과는 많이 다른 존재
- 상속 불가
- (인스턴스/타입) 메서드
- (인스턴스/타입) 연산 프로퍼티
- 값 타입
- 유사한 종류의 여러 값을 유의미한 이름으로 한 곳에 모아 정의 (요일, 상태값 월 등..)
- 열거형 자체가 하나의 데이터타입으로 열거형의 case 하나하나 전부 하나의 유의미한 값으로 취급
- 선언 키워드: enum
구조체는 언제사용하나?
- 연관된 몇몇의 값들을 모아서 하나의 데이터타이으로 표현하고 싶을때
- 다른 객체 또는 함수 등으로 전달될 때 참조가 아닌 복사를 원할때
- 자신을 상속할 필요가 없거나, 자신이 다른 타입을 상속받을 필요가 없을 때
- Apple 프레임워크에서 프로그래밍을 할 때에는 주로 클래스를 많이 사용
Value vs Reference?
Value: 데이터를 전달할 때 값을 복사하여 전달
Reference: 데이터를 전달할 때 값의 메모리 위치를 전달 > 단순히 참조값을 전달
code1
struct ValueType {
var property = 1
}
class ReferenceType {
var property = 1
}
let firstStructInstance = ValueType()
var secondStructInstance = firstStructInstance
secondStructInstance.property = 2
print("first struct instance property: \(first struct instance property)") // 1
print("second struct instance property: \(second struct instance property)") // 2
let firstStructInstance = Referencetype()
var secondStructInstance = firstStructInstance
secondStructInstance.property = 2
print("first struct instance property: \(first struct instance property)") // 2
print("second struct instance property: \(second struct instance property)") // 2
code2
struct SomeStruct {
var someProperty: String = "Property"
}
var SomeStructInstance: SomeStruct = SomeStruct()
func someFunction(structInstance: SomeStruct) {
var localVar: SomeStruct = structInstance
localVar.someProperty = "ABC"
}
someFunction(SomeStructInstance)
print(SomeStructInstance.someProperty) // Property
code3
class SomeClass {
var someProperty: String = "Property"
}
var someClassInstace: SomeClass = SomeClass()
func someFunction(classInstance: SomeClass) {
var localVar: SomeClass = classInstance
locarVar.someProperty = "ABC"
}
someFunction(SomeStructInstance)
print(SomeStructInstance.someProperty) // ABC
-> 스위프트는 구조체, 열거형 사용을 선호
-> Apple 프레임워크는 대부분 클래스 사용
-> Apple 프레임워크 사용시 그조체/클래스 선택은 각자의 몫이다
15 Jan 2020
|
swift
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
인프런, 야곰의 스위프트 기본문법 강좌를 듣고 정리하였습니다.
열거형(enum)
열거형은 타입이므로 대문자 카멜케이스를 사용하여 이름을 정의한다.
기본적으로 식별자들을 한 타입으로 사용하고 싶을때 열거형을 선언한다.
- 각 case는 소문자 카멜케이스로 정의한다.
- 각 case는 그 자체가 고유의 값이다.
enum 이름 {
case 이름1
case 이름2
case 이름3, 이름4, 이름5
...
}
예시는 아래와 같다.
enum Weekday {
case mon, tue, wed, thu, fri, sat, sun
}
// 열거형의 case를 나타내는 문법: 열거형 타입이름.case이름
var day: Weekday = Weekday.mon
day = .tru
print(day) // tue
switch day {
case .mon, .tue, .wed, .thu:
print("평일입니다")
case Weekday.fri:
print("불금!")
case .sat, .sun:
print("신나는 주말!!")
}
원시값
C언어의 enum처럼 정수값을 가지게 만들 수 있다.
- rawValue 를 사용하면 된다.
- rawValue는 case별로 각각 다른 값을 가져야 한다.
- 자동으로 1이 증가된 값이 할당된다.
- rawValue를 반드시 지닐 필요가 없다면 굳이 만들지 않아도됨
enum Fruit: Int {
case apple = 0
case grape = 1
case peach
}
print("Fruit.peach.rawValue == \(Fruit.peach.rawValue)") // 2
정수타입 뿐만 아니라 Hashable
프로토콜을 따르는 모든 타입을 원시값의 타입으로 지정할 수 있다.
enum School: String {
case elementary = "초등"
case middle = "중등"
case high = "고등"
case university
}
// 열거형의 원시값 타입이 String일때, 원시값이 지정되지 않는다면 case의 이름을 원시값으로 사용
print("School.middle.rawValue == \(School.middle.rawValue)") // 중등
print("School.university.rawValue == \(School.university.rawValue)") // university
원시값을 통한 초기화
- rawValue를 통해 초기화 할 수 있다.
- rawValue가 case에 해당하지 않을 수 있으므로(3이상의 값) rawValue를 통해 초기화 한 인스턴스는 옵셔널 타입 이다.
let apple: Fruit? = Fruit(rawValue: 0)
if let orange: Fruit = Fruit(rawValue: 5) {
print("rawValue 5에 해당하는 케이스는 \(orange)")
} else {
print("rawValue 5에 해당하는 케이스가 없습니다")
} // rawValue 5에 해당하는 케이스가 없습니다
열거형의 메서드
enum Month {
case dec, jan, feb
case mar, apr, may
case jun, jul, aug
case sep, act, nov
func printMessage() {
switch self {
case .mar, .apr, .may {
print("봄")
}
case .jun, .jul, .aug {
print("여름")
}
case .sep, .oct, .nov {
print("가을")
}
case .dec, .jan, .feb {
print("겨울")
}
}
}
}
Month.mar.printMessage() // 봄
15 Jan 2020
|
swift
개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
인프런, 야곰의 스위프트 기본문법 강좌를 듣고 정리하였습니다.
구조체(struct)
대부분의 타입이 구조체로 이루어져있음 > 타입을 정의 > 값 타입
예시는 아래와 같다.
struct Sample {
// 인스턴스 프로퍼티
var mutableProperty: Int = 100 // 가변 프로퍼티
let immutableProperty: Int = 100 // 불변 프로퍼티
// 타입 프로퍼티
static var typeProperty: Int = 100
// 인스턴스 메서드
func instanceMethod() {
print("instance method")
}
// 타입 메서드
static func typeMethod() {
print("type method")
}
}
프로퍼티: 구조체 안에 들어가는 인스턴스 변수
메서드: 구조체 안에 들어가는 함수
구조체 사용
// 가변 인스턴스 > 인스턴스에서 사용하는 프로퍼티
// Sample이라는 구조체가 타입이 된다.
var mutable: Sample = Sample()
mutable.mutableProperty = 200
mutable.immutableProperty = 200 // 프로퍼티 선언 자체에서 불변으로 선언한 프로퍼티의 값은 변경 불가능하다.
// 불변 인스턴스 > 인스턴스에서 사용하는 프로퍼티
let immutable: Sample = Sample()
immutable.mutableProperty = 100 // 가변 프로퍼티로 설정했다고 하더라도 불변 인스턴스의 갑은 변경 불가능하다.
// 타입 프로퍼티 및 메서드 > Sample이라는 구조체 타입 자체가 사용할 수 있는 프로퍼티, 메서드
Sample.typeProperty = 300
Sample.typeMethod() // type method
// 인스턴스에서 타입 프로퍼티를 사용하는 것은 불가능하다.
mutable.typeProperty = 400
mutable.typeMethod()
예시는 아래와 같다.
struct Student {
var name: String = "unknown"
var `class`: String = "Swift"
// 타입메서드
static func selfIntroduce() {
print("학생 타입입니다...")
}
// 인스턴스 메서드
func selfIntroduce() {
print("저는 \(self.class)반 \(name)입니다...")
}
}
Student.selfIntroduce() // 학생 타입입니다...
var zehye: Student = Student()
zehye.name = "zehye"
zehye.class = "스위프트"
zehye.selfIntroduce() // 저는 스위프트반 zehye입니다...
let kina: Student = Student() // 불변 인스턴스로 프로퍼티값 변경 불가능
kina.name = kina
kina.selfIntroduce() // 저는 스위프트반 unknown입니다...
클래스(class)
구조체와 거의 비슷하지만 값타입인 구조체와는 다르게 클래스는 참조타입 이다.
더 나아가, 다중상속이 불가능하다.
예시는 아래와 같다.
class Sample {
var mutableProperty: Int = 100
let immutableProperty: Int = 100
static var typeProperty: Int = 100
func instanceMethod() {
print("instance method")
}
// 타입 메서드
// 상속을 받았을 때, 재정의 불가 타입 메서드 - static
static func instanceMethod() {
print("type method - static")
}
// 상속을 받았을 때, 재정의 가능 타입 메서드 - class
class func classMethod() {
print("type method - class")
}
}
클래스
클래스는 구조체와 다르게 let, var로 인스턴스 설정하였다고 하더라도 가변 프로퍼티를 통해 값 변경이 가능하다.
var mutableReference: Sample = Sample()
let immutableReference: Sample = Sample()
mutableReference.mutableProperty = 300
immutableReference.mutableProperty = 300
// 불변 프로퍼티를 통한 값변경은 당연히 불가능하다.
mutableReference.immutableProperty = 200
immutableReference.immutableProperty = 200
// 타입 프로퍼티 및 메서드
Sample.typeProperty = 300
Sample.typeMethod()
예시는 아래와 같다.
class Student {
var name: String = "unknown"
var `class`: String = "Swift"
class func selfIntroduce() {
print("학생 타입입니다...")
}
func selfIntroduce() {
print("저는 \(self.class)반 \(name)입니다...")
}
}
Student.selfIntroduce() // 학생 타입입니다...
var zehye: Student = Student()
zehye.name = "지혜"
zehye.class = "스위프트"
zehye.selfIntroduce() // 저는 스위프트반 지혜입니다...
// 구조체와 다르게 가변프로퍼티를 let으로 선언한 인스턴스의 값도 변경이 가능하다.
let kina: Student = Student()
kina.name = "키나"
kina.class = "스위프트"
kina.selfIntroduce() // 저는 스위프트반 키나입니다...