Swift 기초 문법 정리
Updated:
1.상수와 변수
-
상수는 변하지 않는 일정한 값
-
변수는 변할 수 있는 값을 갖는것
import Foundation
// 상수
// let 상수명: 데이터 타입 = 값
let a: Int = 100
// 변수
// var 변수명: 데이터 타입 = 값
var b: Int = 200
b = 400
2.Swift 기본 데이터 타입
-
Int: 64bit 정수가
-
UInt: 부호가 없는 64bit 정수형
-
Float: 32bit 부동 소수점
-
Double: 64bit 부동 소수점
-
Bool: true, false 값
-
Character: 문자
-
String: 문자열
-
Any: 모든 타입을 지정하는 키워드
import Foundation
// Int
var someInt: Int = -100
someInt = 100
// UInt
var someUInt: UInt = 200
// Float
var someFloat: Float = 1.1
someFloat = 1
print(someFloat)
// Double
var someDouble: Double = 1.1
someDouble = 1
// Bool
var someBool: Bool = true
someBool = false
// Character
var someCharacter: Character = "가"
someCharacter = "A"
someCharacter = "😄"
// String
var someString: String = "안녕하세요 👉"
// 타입추론
var number = 1
3.컬렉션 타입
-
Array : 데이터 타입의 값들을 순서대로 지정하는 리스트
-
Dictionary : 순서 없이 key 와 value 의 한 쌍으로 데이터를 저장하는 컬렉션 타입
-
Set : 같은 데이터 타입의 값을 순서 없이 저장하는 리스트
Array 예제
import UIKit
// 빈 Array 만들기
var numbers: Array<Int> = Array<Int>()
// 1을 Array 에 추가하기
numbers.append(1)
numbers.append(2)
numbers.append(3)
// Array 요소에 Index 값으로 접근하기
numbers[0]
numbers[1]
// Array 안에 중간에 insert 하기 = 숫자 4를 index 2 번 자리에 넣기
numbers.insert(4, at: 2)
numbers
// Array 안에 값 index 0 번 자리에서 지우기
numbers.remove(at: 0)
numbers
// 출력된 문법으로 Array 를 생성하기
var names:[String] = []
Dictionary 예제
// Dictionary 만들기
var dic: Dictionary<String, Int> = Dictionary<String, Int>()
// 축약된 형태로 Dictionary 만들기 = 초기값을 선언해서 만들수 있음
var dic2: [String: Int] = ["Jacob": 1]
// Dictionary 에 값 추가 하기
dic2["Emma"] = 3
dic2["John"] = 5
dic2
// Dictionary 에 값 변경하기
dic2["Jacob"] = 6
dic2
// Dictionary 값 제거하기
dic2.removeValue(forKey: "Jacob")
dic2
Set 예제
// 순서와 상관없이 data 의 중복을 허용하지 않는 Set 만들기 = Set 는 축약형 으로 사용하는 방법은 없기 때문에 아래와 같이만 사용해야 함
var set: Set = Set<Int>()
// Set 에 값을 넣기
set.insert(10)
set.insert(20)
set.insert(30)
set.insert(30) // inserted false 됨 중복되기 때문에
set
// Set 안에 값 지우기
set.remove(20)
set
4.함수
함수는 작업의 가장 작은 단위이자 코드의 집합입니다 : 반복적인 프로그래밍을 피하기 위해서 사용합니다
- 함수의 기본적인 형태
func 함수명(파라미터 이름: 데이터 타입) -> 반환 타입 {
return 반환 값
}
import UIKit
// func 함수명(파라미터 이름: 데이터 타입) -> 반환 타입 {
// return 반환 값
// }
// 함수 생성
func sum(a: Int, b:Int) -> Int {
return a + b
}
// 함수 호출
sum(a: 5, b: 3)
// 문자열 출력
func hello() -> String {
return "hello"
}
hello()
// 반환값이 없는 함수작성
func printName() {
}
// me 값으로 Jacob 이라는 기본값을 사용할 수 있음
func greeting(friend: String, me: String = "Jacob") {
print("Hello, \(friend)! I'm \(me)")
}
greeting(friend: "Emma")
// 전달인자 label 을 사용해서 함수 만들기
/*
func 함수 이름(전달인자 레이블: 매개변수 이름: 매개변수 타입, 전달인자 레이블: 매개변수 이름: 매개변수 타입...) -> 반환 타입 {
retrun 반환 값
}
*/
func sendMessage(from myName: String, to name: String) -> String {
return "Hello \(name)! I'm \(myName)"
}
sendMessage(from: "Jacob", to: "Emma")
// 전달 인자 label 을 사용하지 않을경우 wildcard 식별자를 사용함 : _ 를 앞에다 붙여 줌
func sendMessage2(_ name: String) -> String {
return "Hello \(name)!"
}
sendMessage2("Jacob")
// 몇개의 값이 변수로 들어올지 모를때 가변 매개변수를 사용하는 함수 : 배열처럼 사용이 가능, 함수마다 가변 매개변수는 한가지만 가질 수 있음
func sendMessage3(me: String, friends: String...) -> String {
return "Hello \(friends)! I'm \(me)"
}
// 여러개의 문자열을 넘기는데 array 안에 3명이 들어감
sendMessage3(me: "Jacob", friends: "Emma", "Json", "John")
5.조건문
주어진 조건에 따라서 어플리케이션을 다르게 동작하도록 하는것
if
/*
if 조건식 {
실행할 구문
}
*/
let age = 20
if age < 19 {
print("미성년자 입니다")
}
/*
if 조건식 {
조건식이 만족하면 해당 구문 실행
} else {
만족하지 않으면 해당 구문 실행
}
*/
if age < 19 {
print("미성년자")
} else {
print("성년자")
}
/*
if 조건식1 {
조건식1 을 만족할 때 실행할 구문
} else if 조건식2 {
조건식2를 만족 할때 실행할 구문
} else {
아무 조건식도 만족하지 않을 때 실행할 구문
}
*/
let animal = "강아지"
if animal == "dog" {
print("강아지 사료주기")
} else if animal == "cat" {
print("고양이 사료주기")
} else {
print("해당하는 동물 사료가 없음")
}
switch
/*
switch 비교대상 {
case 패턴 1:
// 패턴 1 일치할때 실행되는 구문
case 패턴 2, 패턴 3:
// 패턴 2,3 이 일치할때 실행되는 구문
default:
// 어느 비교 패턴과도 일치하지 않을 때 실행되는 구문
}
*/
let color = "red"
switch color {
case "blue" :
print("파란색 입니다")
case "green":
print("초록색입니다")
case "yello":
print("노란색 입니다")
default:
print("찾는 색상이 없습니다")
}
// switch 문을 사용해서 숫자 범위 -20 에서 9도까지는 겨울입니다 라고 나타 내는 것
let temp = 30
switch temp {
case -20...9:
print("겨울 입니다")
case 10...14:
print("가을 입니다")
case 15...25:
print("봄 입니다")
case 26...35:
print("여름 입니다")
default:
print("이상기온 입니다")
}
6.반복문
반복적으로 코드가 실행되게 만드는 구문
for-in
/*
for 루프 상수 in 순회 대상 {
// 실행할 구문..
}
*/
for i in 1...4 {
print(i)
}
let arr = [1, 2, 3, 4, 5]
for i in arr {
print(i)
}
while
/*
while 조건식 {
// 실행할 구문
}
*/
var num = 5
while num < 10 {
num += 1
}
num
repeat-while
/*
repeat {
// 실행할 구문
} while 조건식
*/
var x = 6
repeat {
x += 2
} while x < 5
// 조건에 맞지 않아도 한번은 실행되기 때문에 +2 가 되서 8이 출력이 됨
print(x)
7.옵셔널
값이 있을 수도 있고 없을 수도 있는 것임
nil 은 dart 언어나 다른 언어에서의 null 을 가리킴
var name: String? = nil
- optional
nil
을 사용할때는 type 뒤에 ? 를 붙여 줘서 사용해야 함
var name: String?
// optional 변수에 초기값으로 값을 넣을 수 있음
var optionalName: String? = "Jacob"
print(optionalName) // 출력값으로 Optional("Jacob") 이라고 optional 값으로 출력되기때문에 재대로 실행하려면 optional binding 이 필요함
Optional binding
-
명시적 해제 : 강제 해제, 비강제 해제 (옵셔널 바인딩)
-
변수 명 뒤에 ! (느낌표) 를 붙여서 optional 을 강제로 해제 시키는데, 이방법을 사용하게 되면 강제로 프로그램 error 가 발생 할 수도 있음
-
안전하게 해제 하기 위해서는 비강제 해제 방식 사용
-
-
묵시적 해제 : 컴파일러에 의한 자동 해제, 옵셔널의 묵시적 해제
var name: String?
// optional 변수에 초기값으로 값을 넣을 수 있음
var optionalName: String? = "Jacob"
print(optionalName)
// optional 강제 해제
print(optionalName!)
// optional 비강제 해제
if let result = optionalName {
print(result)
} else {
}
// 묵시적으로 해제 optional 을 ? 대신 ! 을 사용해서 optional 을 해제시킴
let string = "12"
var stringToInt: Int! = Int(string)
print(stringToInt + 1)
8.구조체
프로퍼티와 메소드를 사용해서 구조화된 data 와 기능을 가질 수 있는 하나의 사용자 정의 데이터 타입을 만드는 것임
/*
struct 구조체 이름 {
프로퍼티와 메서드
}
*/
// structure 생성
struct User {
var nickname: String
var age: Int
// struct 안에 method 정의
func information() {
print("\(nickname) \(age)")
}
}
// instance 생성
var user = User(nickname: "Jacob", age: 30)
// 실행
user.nickname
// user nickname 변경
user.nickname = "John"
user.nickname
// struct 의 method 실행
user.information()
9.클래스
/*
class 클래스 이름 {
프로퍼티와 메서드
}
*/
// class 생성
class Dog {
var name: String = ""
var age: Int = 0
// class 에서는 constructor 를 생성해줘야 함 초기화 값임
init() {
}
// method 생성
func introduce() {
print("name \(name) age \(age)")
}
}
// class 의 instance 생성
var dog = Dog()
dog.name = "coco"
dog.age = 3
dog.name
dog.age
dog.introduce()
10.초기화(initialization)
- 클래스 구조체 또는 열거형의 인스턴스를 사용하기 위한 준비 과정
import UIKit
/*
init(매개변수: 타입, ...) {
// 프로퍼티 초기화
ㅁㄴㅇㄴ
}
*/
// 클래스 선언
class User {
var nickname: String
var age: Int
// 초기화 dart 나 Js 에서 this 가 self 로 쓰임
init(nickname: String, age: Int) {
self.nickname = nickname
self.age = age
}
// 초기값에 기본값 설정
init(age: Int) {
self.nickname = "Emma"
self.age = age
}
// deinitialize: instance 가 메모리에 해제되기 직전에 호출되고 클래스 인스턴스와 관련해서 정의 작업을 할 수 있음
deinit {
print("deinit user")
}
}
// User instance 생성
var user = User(nickname: "Jacob", age: 30)
user.nickname
user.age
var user2 = User(age: 27)
user2.nickname
user2.age
// Swift 는 instance 가 더이상 필요하지 않으면 자동으로 소멸을 시켜 버림 user3 에 nil 을 대입 시키면 더이상 필요 없다고 판단함
var user3: User? = User(age: 23)
user3 = nil
11.프로퍼티
-
클래스, 구조체 또는 열거형 등에 관련된 값을 뜻합니다
-
저장 프로퍼티: 인스턴스의 변수, 상수를 의미
-
연산 프로퍼티: 연산의 값을 저장하는 것이 아니라 특정 연산값을 실행하는 것을 의미함
-
타입 프로퍼티: 특정 인스턴스에서 사용되는것이 아닌
-
import Foundation
// 저장 프로퍼티
// 구조체
struct Dog {
var name: String
let gender: String
}
var dog = Dog(name: "Jacob", gender: "Male")
print(dog)
dog.name = "제이콥"
// dog2 는 let 으로 선언되었기 때문에 변경 프로퍼티 변경 안됨
let dog2 = Dog(name: "Emma", gender: "female")
// 구조체는 value type 이기 때문에 상수로 선언하게 되면 변수로 선언된 property 라고 해도 값이 변경이 안됨
// 단 클래스의 reference type 이여서 구조체와 다르게 클래스 instance 는 상수로 선언을해도 변수로 선언된 property 의 값을 바꿀 수 있음
// 클래스
class Cat {
var name: String
let gender: String
// intialization 생성
init(name: String, gender: String) {
self.name = name
self.gender = gender
}
}
// 상수로써 instance 선언
let cat = Cat(name: "json", gender: "male")
cat.name = "Jacob"
print(cat.name)
// 연산 프로퍼티 : 저장 프로퍼티는 구조체와 클래스에서만 사용되지만, 연산 프로퍼티는 구조체, 클래서, 열거형에서도 사용이 가능함
// 연산 프로퍼티는 값을 직접적으로 저장하지는 않지만, getter, setter 를 사용해서 다른 property 와의 값들을 직접적으로 접근할 수 있게 됨
struct Stock {
var averagePrice: Int
var quantity: Int
var purchasePrice: Int {
get {
return averagePrice * quantity
}
// set 에 property 값을 입력하지 않으면 newVal 의 값이 기본값으로 설정이 됨
set(newPrice) {
averagePrice = newPrice / quantity
}
}
}
var stock = Stock(averagePrice: 2300, quantity: 3)
print(stock)
// 연산형 프로퍼티 접근
stock.purchasePrice // 평균값 6900
stock.purchasePrice = 3000 // purchasePrice 에서 3000 으로 바꾸미
stock.averagePrice // averageProce : 1000
// 프로퍼티 옵져버: 프로퍼티의 값의 변화를 관찰하고 반영함 새로운 값이 같다고 하더라도, 프로퍼티가 set 될때마다 호출 된다고 보면 됨
// 프로퍼티 옵져버는 3가지 경우에만 사용이 가능: 저장 프로퍼티, overriding 이 된 계산 프로퍼티에서만 사용이 가능함
class Account {
var credit: Int = 0 {
// 프로퍼티 옵저버에는 값이 저정되기 직전에 호출되는 willSet 옵져버 : 새로 저장될 property 의 값을 상수 매개변수로 전달을 함 만약 지정하지 않으면 newValue 의 값이 매개변수의 값이 됨
willSet {
print("잔액이 \(credit)원에서 \(newValue) 원으로 변경될 예정입니다")
}
// 값이 저장된 직후에 호출되는 didSet 옵져버: property 의 기존값이 상수 매개변수로 전달되어짐 이 매개변수의 이름은 didSet 구문안에 사용될 수 있도록 지정할 수 있음. 만약 지정하지 않으면 기본값인 oldValue 가 매개 값이 됨
didSet {
print("잔액이 \(oldValue) 원에서 \(credit) 원으로 변경되었습니다")
}
}
}
// account instance
var account = Account()
account.credit = 1000 // 잔액이 0원에서 1000 원으로 변경될 예정입니다
// 잔액이 0 원에서 1000 원으로 변경되었습니다
// Type Property : instance 생성없이 객체 내에 property 에 접근이 가능하게 하는것인데, 프로퍼티 타입 자체와 연결하는 것을 말함 static 키워드를 사용해서 정의함
struct SomeStructure {
static var stroedTypeProperty = "Some value." // 스토어
static var computedTypeProperty: Int {
return 1
}
}
// instance 를 생성안해도 type property 는 타입 이름과 프로퍼티 이름을 연결해서 바로 사용 가능
SomeStructure.stroedTypeProperty
SomeStructure.computedTypeProperty
12.클래스와 구조체의 차이
Class 와 structure 의 공통점
-
값을 저장할 프로퍼티를 선언할 수 있습니다.
-
함수적 기능을 하는 메서드를 선언 할 수 있습니다.
-
내부 값에 .을 사용하여 접근할 수 있습니다.
-
생성자를 사용해 초기 상태를 설정할 수 있습니다
-
Protocol 을 채택하여 기능을 설정할 수 있습니다.
차이점
Class
-
참조타입
-
ARC 로 메모리 관리
-
상속이 가능
-
타입 캐스팅을 통해 런타임에서 클래스 인스턴스의 타입을 확인할 수 있음
-
deinit 을 사용해서 클래스 인스턴스의 메모리 할당을 해제할 수 있음
-
같은 클래스 인스턴스를 여러개의 변수에 할당한 뒤 값을 변경 시키면 모든 변수에 영향을 줌 (메모리가 복사 됨)
Structure
-
값 타입
-
구조체 변수를 새로운 변수에 할당 할 때마다 새로운 구조체가 할당 됩니다.
-
즉 같은 구조체를 여러 개의 변수에 할당한 뒤 값을 변경시키더라도 다른 변수에 영향을 주지 않음 (값 자체를 복사)
// Class vs Struct
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 // class1 의 값이 2로 변경됨 왜냐면 class 는 참조 타입이기 때문에 같은 class 의 instance 를 할당하게 되면 참조된 instance 의 값이 같이 변경이 됨 즉, 변수를 복사하더라도 하나의 instance pointer 를 가리키기 때문에 원본, 복사본이 모두 같은 값을 가지게 됨
// 구조체는 다르게 값 타입이기때문에 복사하더라도 원본이 바뀌지 않음
var struct1 = SomeStruct()
var struct2 = struct1
var struct3 = struct2
struct2.count = 3
struct3.count = 4
struct1.count // 0
struct2.count // 3
struct3.count // 4
// 즉 구조체는 각각 다른 값을 가지게 됨. 왜냐면 구조체는 값 타입이라서 구조체 instance 를 할당하더라도 매번 새로운 메모리가 할당되어서 값을 변경하더라도 구조체에 영향을 주지 않음
13.상속
- class 가 다른 클래스로 부터 method, property 등을 상속받아서 사용하는 특성. 상속 받는 class 를 child class, 상속 주는 class 는 super class 라고 합니다
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "Traveling at \(currentSpeed) miles per hour "
}
func makeNoise() {
print("Speaker on")
}
}
// 상속
/*
class 클래스 이름: 부모클래스 이름 {
// 하위 클래스 정의
}
*/
class Bicycle: Vehicle {
var hasBasket = false
}
// bicycle 인스턴스 생성
var bicycle = Bicycle()
bicycle.currentSpeed // 0 출력
bicycle.currentSpeed = 15.0
bicycle.currentSpeed // 15 출력
// override
class Train: Vehicle {
// makeNoise 를 override 하기 (기능을 재정의)
override func makeNoise() {
super.makeNoise() // 자식 class 에서 makeNoise 가 호출될때 super class 에서 먼저 makeNoise() 를 실행함
print("choo choo")
}
}
var train = Train()
train.makeNoise() // Speaker on choo choo 출력
// 프로퍼티를 overring 하기
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + "in gear \(gear)"
}
}
var car = Car()
car.currentSpeed = 30.0
car.gear = 2
print(car.description) // Traveling at 30.0 miles per hour in gear 2
// overring 된 상태에서 property obsever 를 추가하기
// 상속된 property 에 overring 을 사용하면 property 옵져버를 추가 할 때는 상수저장, read-only 저장 프로퍼티는 프로퍼티 옵져버를 추가 할 수 없음. 그 이유는 값을 설정할 수 없기 때문에 willSet 이나, didSet 을 사용할 수 없기 때문임
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10) + 1
}
}
}
var automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)") // AutomaticCar: Traveling at 35.0 miles per hour in gear 4
// 타입 앞에 final 을 작성하게 되면 overriding 이 되지 않음
14.타입 캐스팅
-
인스턴스의 타입을 확인하거나 어떠한 클래스의 인스턴스를 해당 클래스 계층 구조의 슈퍼 클래스나 서브 클래스로 취급하는 방법
-
is
,as
로 값을 확인하거나 다른 타입으로 변환 하는데 키워드로 사용함
// 타입 확인
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
let library = [
Movie(name: "기생충", director: "봉준호"),
Song(name: "Butter", artist: "BTS"),
Movie(name: "올드보이", director: "박찬욱"),
Song(name: "Wonderful", artist: "Oasis"),
Song(name: "Rain", artist: "이적")
]
var movieCount = 0
var songCount = 0
for item in library {
if item is Movie {
movieCount += 1
} else if item is Song {
songCount += 1
}
}
print("Media library contains \(movieCount) movies and \(songCount) songs") // Media library contains 2 movies and 3 songs
// 타입 변환
for item in library {
if let movie = item as? Movie {
print("Movie: \(movie.name), dir. \(movie.director)")
} else if let song = item as? Song {
print("Song: \(song.name), by \(song.artist)")
}
}
/*
Movie: 기생충, dir. 봉준호
Song: Butter, by BTS
Movie: 올드보이, dir. 박찬욱
Song: Wonderful, by Oasis
Song: Rain, by 이적
*/
// as? 는 optional 로 타입 변형을 하는것이고, as! 을 사용하면 확실하게 강제로 타입 변환을 하는것임(! 을 사용해서 잘못된 class type 으로 변경 하면 runtime error 발생되서 프로그램 강제 종료됨)
15.assert 와 guard
-
assert
- 특정 조건을 체크하고, 조건이 성림되지 않으면 메세지를 출력하게 할 수 있는 함수 - assert 함수는 디버깅 모드에서만 동작하고 주로 디버깅 중 조건의 검증을 위하여 사용합니다
-
guard 문
- 뭔가 검사하여 그 다음에 오는 코드를 실행할지 말지 결정 하는것 - guard 문에 주어진 조건문이 거짓일 때 구문이 실행됨 - 주로 early exit 이라고 해서 guard 문을 사용해서 조건을 만족하지 않으면 (false 일때,) code 를 실행하지 않도록 하는 방어코드로 사용을 주로 합니다.
// assert : 조건의 검증을 위해서 사용함
var value = 0
assert(value == 0)
value = 2
// assert(value == 0, "값이 0이 아닙니다") // Assertion failed : 값이 0이 아닙니다
// guard
/*
guard else {
// 조건이 false 이면 else 구문이 실행되고
return or throw or break 을 통해 이 후 코드를 실행하지 않도록 함
}
*/
// value 가 0일 때만 안녕하세요 실행되고 아닐때는 guard 문 이 실행되어 return 됨
func guardTest(value1: Int) {
guard value1 == 0 else { return }
print("안녕하세요")
}
guardTest(value1: 0)
16.Protocol
특정 역활을 하기 위한 method, property, 기타 요구사항등의 청사진을 말함
// protocol
/*
protocol 이름 {
// 프로토콜 요구사항
}
*/
// get, set 을 사용해서 읽기만 가능한지, 쓰기와읽기가 가능한지 설정 가능
protocol FirstProtocol {
var name: Int {get set}
var age: Int {get}
}
protocol AnotherProtocol {
static var someTypeProperty: Int {get set}
}
protocol FullNames {
var fullName: String {get set}
func printFullName()
}
protocol SomeProtocol3 {
func someTypeMethod()
}
// struct 에서 protocol 채택 (다수일때 아래와 같이 , 로 구분)
struct Person: FullNames {
var fullName: String
func printFullName() {
print(fullName)
}
}
// class 에서 protocol 채택 (상속받을 superClass 를 먼저 쓰고, 프로토콜을 순서대로 작성함)
/*
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol{
}
*/
// protocol initializer 요구사항 : protocol 은 자신을 체택한 타입에 생성자도 요구할 수 있음
protocol SomeProtocol4 {
init(someParameter: Int)
}
protocol SomeProtocol5 {
init()
}
class SomeClass: SomeProtocol5 {
required init() {
}
}
17.Extensions
기존 클래스, 구조체, 열거형, 프로토콜에 새로운 기능을 추가하는 기능을 가리킵니다
-
extension 이 type 에 추가 할 수 있는 기능
- 연산 타입 프로퍼티 / 연산 인스턴스 프러퍼티 - 타입 메서드 / 인스턴스 메서드 - 이니셜라이저 - 서브스크립트 - 중첩 타입 - 특정 프로토콜을 준수할 수 있도록 기능 추가
// Extension
/*
extension SomeType {
// 추가 기능
}
*/
// Int 형태의 타입이 짝수인지 홀수 인지 판단하는 extension 생성
extension Int {
var isEven: Bool {
return self % 2 == 0
}
var isOdd: Bool {
return self % 2 == 1
}
}
var number = 3
number.isOdd // true
number.isEven // false
// type 에 method 추가하기
extension String {
func converToInt() -> Int? {
return Int(self)
}
}
var str = "0"
str.converToInt() // Int 형 타입으로 0 이 변경되서 출력됨
18.Enum
연관성이 있는 값을 모아 놓은 것을 말함
// enum
// enum 의 각 항목은 그 자체로의 고유값임
enum CompassPoint {
case north
case south
case east
case west
}
// enum 을 만들게 되면 하나의 type 처럼 사용 할 수 있음
var direction = CompassPoint.east // east
direction = .west // west 로 변경됨
// 열거형은 switch 구문과 함께 쓰면 다양하게 활용 할 수 있음
switch direction {
case .north:
print("북으로 가라~")
case .east:
print("동쪽으로 가라")
case .south:
print("남으로 가라")
case .west:
print("서쪽으로 가라")
} // 서로쪽으로 가라 출력
// 특정 type 을 원시 값으로 가지게 하기: enum 을 사용해서 type 을 명시해 주기
// 각 항목에 초기값 설정
enum CompassPoint2: String {
case north = "북"
case south = "남"
case east = "동"
case west = "서"
}
// 선언된 초기값을 사용하려면 rawValue 를 통해서 원시값을 가져 올 수 있음
var direction2 = CompassPoint2.east
switch direction2 {
case .north:
print(direction2.rawValue)
case .east:
print(direction2.rawValue)
case .south:
print(direction2.rawValue)
case .west:
print(direction2.rawValue)
} // 동 출력됨
// 원시값을 가지고 enum 을 출력하기
let direction3 = CompassPoint2(rawValue: "남") // direction3 는 south 값을 가지게 됨
// 연관값 을 추출해서 사용하기
enum PhoneError {
case unknown
case batteryLow(String)
}
let error = PhoneError.batteryLow("배터리가 곧 방전됩니다.")
switch error {
case .batteryLow(let message):
print(message) // message 문으로 배터리가 곧 방전됩니다 가 출력됨
case .unknown:
print("알수 없는 에러 입니다")
}
19.Optional chaining
옵셔널에 속해 있는 nil 일지도 모르는 프로퍼티, 메서드, 서브스크립션 등을 가져오거나 호출할 때 사용할 수 있는 일련의 과정입니다
// optional chaining
struct Developer {
let name: String
}
struct Company {
let name: String
var developer: Developer?
}
var developer = Developer(name: "Emma")
var company = Company(name: "Jacob", developer: developer)
print(company.developer) // Optional(__lldb_expr_37.Developer(name: "Emma")) 출력됨
// optional chaining
print(company.developer?.name) // Optional("Emma")
print(company.developer!.name) // Emma
20.try-catch
에러 처리를 위한 try-catch 문 : 프로그램 내에서 에러가 발생한 상황에 대해 대응하고 이를 복구 하는 과정
runtime 과정에서 error 처리를 위한 단계는 4가지가 있습니다
-
throwing(발생)
-
catching(감지)
-
propagating(전파)
-
manipulating(조작)
import Foundation
// try-catch
enum PhoneError: Error {
case unknown
case batteryLow(batteryLevel: Int)
}
// throw 를 사용해서 error 를 발생 시키기
// throw PhoneError.batteryLow(batteryLevel: 20)
// 함수에서 발생한 error 를 해당 함수에 전파하는 방법
func checkPhoneBatteryStatus(batteryLevel: Int) throws -> String{
guard batteryLevel != -1 else { throw PhoneError.unknown}
guard batteryLevel > 20 else { throw PhoneError.batteryLow(batteryLevel: 20)}
return "배터리 상태가 정상입니다."
}
/*
do {
try 오류 발생 가능 코드
} catch 오류 패턴 {
처리 코드
}
*/
do {
try checkPhoneBatteryStatus(batteryLevel: 20)
} catch PhoneError.unknown {
print("알 수 없는 에러입니다.")
} catch PhoneError.batteryLow(let baterryLabel) {
print("배터리 전원 부족 남은 배터리 : \(baterryLabel) %")
} catch {
print("그 외 오류 발생 : \(error)")
} // 배터리 전원 부족 남은 배터리 : 20 % 출력됨
let status = try? checkPhoneBatteryStatus(batteryLevel: 30)
print(status) // nil
// 오류가 절대 발생되지 않을것이라고 해서 ! 을 사용하는 경우
let status2 = try! checkPhoneBatteryStatus(batteryLevel: 30)
print(status2) //
21.Closer
코드에서 전달 및 사용할 수 있는 독립 기능 블록이며, 일급 객체의 역활을 할 수 있습니다
- 일급 객체: 전달 인자로 보낼 수 있고, 변수/상수 등으로 저장하거나 전달할 수 있으며, 함수의 반환 값이 될 수도 있습니다
import Foundation
// 클로저 표현식
/*
{
(매개 변수) -> 리턴 타입 in
실행 구문
}
*/
let hello = {() -> () in
print("hello")
}
hello()
// parameter 와 return type 이 있는 클로저
let hello2 = { (name: String) -> String in
return "Hello, \(name)"
}
hello2("Jacob")
// 클러저를 함수의 parameter 로 전달하는 함수
func doSomething(closure: () -> ()) {
closure()
}
// doSomething(closure: { <#T##() -> ()#> in
// print("hello")
// })
// 클로져를 반환 하는 type
func doSomething2() -> () -> () {
return { () -> () in
print("hello4")
}
}
doSomething2()() // hello4
// 후행 클로저: 읽기 쉽게 형태를 바꾸는 것인데, 맨 마지막에 매개변수로 전달되는 클로져에만 해당 되므로, 매개변수 클로져를 여러개 전달할때는 마지막 매개변수로만 후행 클로저를 사용할 수 있다
doSomething {
print("hello2")
}
// 다중 후행 클로져 문법
func doSomething2(success: () -> (), fail: ()-> ()) {
}
doSomething2 {
<#code#>
} fail: {
<#code#>
}
22.고차함수
다른 함수를 전달 인자로 받거나 함수 실행의 결과를 함수로 반환하는 함수
swift 에서 제공하는 고차함수로는 map, filter, reduce 등이 있습니다.
// map
// container 내의 data 를 변형하여 새로운 container 를 return 함
let numbers = [0, 1, 2, 3]
let mapArray = numbers.map{ (number) -> Int in
return number * 2
}
print("map: \(mapArray)") // map: [0, 2, 4, 6]
// filter
// container 의 내부의 값을 걸러서 다른 container 로 추출 하는 역활을 함
let intArray = [10, 5, 20, 13, 4]
let filterArray = intArray.filter{ $0 > 5}
print("filter: \(filterArray)") // filter: [10, 20, 13]
// reduce
// container 요소를 하나로 통합할때, 연산자 한개의 value 만 return 할 수 있음
// 총합을 구할 때 자주 사용
let someArray = [1, 2, 3, 4, 5]
// 첫번째 매개변수를 0으로 설정하고, 매개변수
let reduceResult = someArray.reduce(2) {
(result: Int, element: Int) -> Int in
print("\(result) + \(element)")
return result + element
}
print("reduce: \(reduceResult)")
🔶 🔷 📌 🔑
Reference
inswave - http://tech.inswave.com/2018/04/02/Swift/
[Swift 문법] Swift 공식 문서 정리 - https://icksw.tistory.com/2
fastcampus - https://fastcampus.co.kr/dev_online_iosappfinal
Leave a comment