IOS/Swift
Swift 기본 문법 정리
montt
2022. 9. 28. 20:34
Swift 기본 문법
상수와 변수 (let, var)
- 상수 : 데이터가 한번 초기화되면 더이상 변하지 않는 수
- 변수 : 데이터를 계속해서 변경할 수 있는 수
let a: Int = 1 // 상수
var b: Int = 2 // 변수
a = 2 // 오류 발생
데이터 타입(Int, UInt, Float, Double, Bool, Character, String, Any)
- Int : 64bit 정수형
- UInt : 부호가 없는 64bit 정수형
- Float: 32bit 부동 소수점
- Double: 64bit 부동 소수점
- Bool: true / false
- Character: 문자형
- String: 문자열
- Any: 모든 타입을 지칭하는키워드
컬렉션 타입(Array, Dictionary, Set)
- Array : 데이터 타입의 값들을 순서대로 저장하는 리스트
- Dictionary : 순서없이 키(key)와 값(Value) 한 쌍으로 데이터를 저장하는 컬렉션 타입
- Set : 같은 데이터 타입의 값을 순서없지 저장하는 리스트
// Array
var numbers: Array<Int> = Array<Int>()
// 추가
numbers.append(1)
numbers.append(2)
numbers.append(3)
// 중간지점 추가
numbers.insert(4, at: 2)
// 해당 인덱스 삭제
numbers.remove(at: 0)
// Dictionary 초기화 선언
var dicData: Dictionary<String, Int> = Dictionary<String, Int>()
// 초기값 선언
var dic: [String: Int] = ["홍길동": 1]
dic["김철수"] = 3
dic["김민지"] = 5
dic["김민지"] = 6
//삭제
dic.removeValue(forKey: "김민지")
// Set 초기화
var set: Set = Set<Int>()
// set 추가
set.insert(10)
set.insert(20)
set.insert(30)
// 중복 추가 안됌
set.insert(30)
// set 삭제
set.remove(20)
함수 정의(func)
/*
func 함수명(파라미터 이름: 데이터 타입) -> 반환 타입 {
return 반환 값
}
*/
// 더하기 함수
func sum(a: Int, b: Int) -> Int {
return a+b
}
// hello 반환하는 함수
func hello() -> String {
return "hello"
}
// me의 기본값으로 Gildong 가지는 함수
func greeting(friend: String, me: String = "Gildong") {
print("Hello, \(friend)! i'm \(me)")
}
// 함수 호출 : "Hello, Minji! i'm Gildong"
greeting(friend: "Minji")
// 매개변수를 사용하는 함수
func sendMessage(from myName: String, to name: String) -> String {
return "Hello \(name)! I'm \(myName)"
}
// 함수 호출 : "Hello Minji! I'm Gildong"
sendMessage(from: "Gildong", to: "Minji")
// 전달인자를 사용하지 않는 함수
func sendMessage(_ name: String) -> String {
return "Hello \(name)"
}
조건문(if, switch)
/*
if 조건식 {
실행할 구문
}
*/
let age = 12
if age < 19 {
print("미성년자 입니다.")
}
/*
if 조건식1 {
조건식1을 만족하면 해당 구문 실행
} else if 조건식 2 {
조건식2를 만족하면 해당 구문 실행
} else {
아무 조건식도 만족하지 않을 때 실행할 구문
}
*/
let animal = "pig"
if animal == "dog" {
print("개")
} else if animal == "cat" {
print("고양이")
} else {
print("기타 동물")
}
/*
switch 비교대상 {
case 패턴1:
// 패턴1 일치할 때 실행되는 구문
case 패턴2, 패턴3:
// 패턴2, 패턴3이 일치할 때 실행되는 구문
default:
// 어느 비교 패턴과도 일치하지 않을 때 실행되는 구문
}
*/
let color = "green"
switch color {
case "blue":
print("파란색 입니다.")
case "green":
print("초록색 입니다.")
case "pink":
print("분홍색 입니다.")
default:
print("찾는 색상이 없습니다.")
}
let temperature = 30
switch temperature {
case -20...9: //-20에서 9 사이
print("겨울 입니다.")
case 10...14:
print("가을 입니다.")
case 15...25:
print("봄 입니다.")
case 26...35:
print("여름 입니다.")
default:
print("이상 기후 입니다.")
}
반복문(for in, while, repeat while)
반복적으로 코드가 실행되게 만드는 구문을 말한다.
/*
for 루프상수 in 순회대상 {
// 실행 구문
}
*/
for i in 1..4 {
print(i) // 1 2 3 4
}
// 컬렉션 타입을 순회대상으로
let array = [1,2,3,4,5]
for i in array {
print(i) // 1 2 3 4 5
}
/*
while 조건식 {
// 실행 구문
}
*/
var number = 5
while number < 10 {
number +=1
}
/* 다른 언어의 do~while 구문과 동일
repeat {
// 실행할 구문
} while 조건식
*/
var x = 6
repeat {
x+=2
} while < 5
옵셔널 (nil)
- 값이 있을 수도 있고, 없을 수도 있는 값
var name: String? // Optional nil var optionalName: String? = "Gildong" // Gildong print(optionalName) // Optional("Gildong")\n
옵셔널 바인딩
- 명시적 해제 : 강제 해제, 비강제 해제(옵셔널 바인딩)
- 묵시적 해제 : 컴파일러에 의한 자동 해제, 옵셔널의 묵시적 해제
// 명시적 해제
// 값이 nil인 optional 강제로 해제하면 에러가 발생한다.
var number: Int? = 3
print(number) // Optional(3)\n
print(number) // 3\n
// Optional 해제 시 에러가 발생하면 else문 실행
if let result = number {
print(result)
} else {
}
// guard문에서 사용하면 계속해서 상수를 사용할 수 있다.
func test() {
let number: Int? = 5
guard let result = number else { return }
print(result)
}
// 묵시적 해제
// 비교 연산자로 비교
let value: Int? = 6
if value == 6 {
print("value가 6입니다.")
} else {
print("value가 6이 아닙니다.")
}
// string의 값이 숫자가 아닐경우 Int로 파싱하면 nil이 된다.
// 따라서 Optional 지정을 해야한다.
// Int! 느낌표는 묵시적으로 옵셔널을 해제한다.
let string = "12"
var stringtoInt: Int! = Int(string)
구조체(struct)
/*
struct 구조체 이름 {
프로퍼티와 메소드
}
*/
// 구조체와 클래스의 이름은 파스칼 정의법(대문자 시작)을 따른다.
struct User {
var nickname: String
var age: Int
func information() {
print("\(nickname) \(age)")
}
}
var user = User(nickname: "Gildong", age: 30)
user.nickname
user.age
// Gildong 30
user.information()
클래스(class)
/*
class 클래스 이름 {
프로퍼티와 메서드
}
*/
class Dog {
var name: String = ""
var age: Int = 0
func introduce() {
print("name \(name) age \(age)")
}
}
var dog = Dog()
dog.name = "CoCo"
dog.age = 3
// name CoCo age 3
dog.introduce()
초기화구문 init
클래스 구조체 또는 열거형의 인스턴스를 사용하기 위한 준비 과정
/*
init(매개변수: 타입, ...) {
// 프로퍼티 초기화
// 인스턴스 생성시 필요한 설정을 해주는 코드 작성
}
*/
class User {
var nickname: String
var age: Int
init(nickname: String, age: Int) {
self.nickname = nickname
self.age = age
}
init(age: Int) {
self.nickname = "grace"
self.age = age
}
deinit {
print("deinit user")
}
}
var user = User(nickname: "Gildong", age: 30)
user.nickname // "Gildong"
user.age // "30"
var user2 = User(age: 27)
user2.nickname //grace
user2.age // 27
user2 = nil // deinit 호출
프로퍼티
클래스, 구조체 또는 열거형 등에 관련된 값을 뜻한다.
- 저장 프로퍼티
- 연산 프로퍼티
- 타입 프로퍼티
클래스와 구조체 차이
공통점
- 값을 적어할 프로퍼티를 선언할 수 있다.
- 함수적 기능을 하는 메서드를 선언할 수 있다.
- 내부 값에 . 을 사용하여 접근할 수 있다.
- 생성자를 사용해 초기 상태를 설정할 수 있다.
- extension을 사용하여 기능을 확장할 수 있다.
- Protocol을 채택하여 기능을 설정할 수 있다.
차이점
클래스
- 참조 타입
- ARC로 메모리를 관리
- 상속이 가능
- 타입 캐스팅을 통해 런타임에서 클래스 인스턴스의 타입을 확인할 수 있음
- deinit을 사용하여 클래스 인스턴스의 메모리 할당을 해제할 수 있음
- 같은 클래스 인스턴스를 여러 개의 변수에 할당한 뒤 값을 변경 시키면 모든 변수에 영향을 줌
구조체
- 값 타입
- 구조체 변수를 새로운 변수에 할당할 때마다 새로운 구조체가 할당된다.
- 즉 같은 구조체를 여러 개의 변수에 할당한 뒤 값을 변경시키더라도 다른 변수에 영향을 주지 않는다.
상속
부모가 자식에게 재산을 물려주는 행위
/*
class 클래스 이름: 부모클래스 이름 {
// 하위 클래스 정의
}
*/
class Vehicle {
var currentSpeed = 0
func makeNoise() {
}
}
class Bicycle: Vehicle {
var hasBasket = false
}
var bicycle = Bicycle()
bicycle.currentSpeed // 0
// override 부모 프로퍼티를 재정의
// super.makeNoise() 부모 프로퍼티 상속
// final class : override 사용 불가능
class Train: Vehicle {
override func makeNoise() {
print("choo choo")
}
}
타입캐스팅(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: ..., artist: ...),
...
]
// is연산자 item 의 클래스가 Movie일 경우 해당 프로퍼티 실행
for item in library {
if item is Movie {
print("movie")
}
}
// as연산자 : 다운캐스팅
// as? -> 조건부 형식 다운캐스팅
// as! -> 강제 다운캐스팅 : 잘못된 타입으로 다운캐스팅 시 런타임 에러 발생
if let movie = item as? Movie
assert와 guard
- assert
- 특정 조건을 체크하고, 조건이 성립되지 않으면 메세지를 출력 하게 할 수 있는 함수
- assert 함수는 디버깅 모드에서만 동작하고 주로 디버깅 중 조건의 검증을 위하여 사용한다.
- gurad
- 뭔가를 검사하여 그 다음에 오는 코드를 실행할지 말지 결정하는 것
- guard 문제 주어진 조건문이 거짓일 떼 구문이 실행됨
// assert
var value = 0
assert(value == 0)
value = 2
// Error 발생
assert(value == 0, "값이 0이 아닙니다.)
// guard
/*
guard 조건 else {
// 조건이 false 이면 else 구문이 실행되고
return opr throw or break 를 통해 이 후 코드를 실행하지 않도록 한다.
}
*/
func guardTest(value: Int) {
guard value == 0 else { return }
print("안녕하세요")
}
guardTest(value: 3)
guardTest(value: 0) // 안녕하세요
// guard 문을 통한 Optional 바인딩
func guardTest2(value: Int?){
guard let value = value else { return }
print(value)
}
guardTest2(value: 2) // 2
프로토콜
특정 역할을 하기 위한 메서드, 프로퍼티, 기타 요구사항 등의 청사진
protocol SomeProtocol {
var name: Int { get set } // 읽고 쓰기 가능
var age: Int { get } // 읽기만 가능
func printPerson()
}
// 상속
struct SomeStructure: SomeProtocol {
var name: Int
var age: Int
func printPerson() {
print(name)
}
}
익스텐션
기존의 클래스, 구조체, 열거형, 프로토콜에 새로운 기능을 추가하는 기능
- 익스텐션이 타입에 추가할 수 있는기능
- 연산 타입 프로퍼티 / 연산 인스턴스 프로퍼티
- 타입 메서드 / 인스턴스 메서드
- 이니셜라이저
- 서브스크립트
- 중첩 타입
- 특정 프로토콜을 준수할 수 있도록 기능 추가
extension Int {
var isEven: Bool {
return self % 2 == 0
}
var idOdd: Bool {
return self % 2 == 1
}
}
var number = 3
number.isOdd // true
number.isEven // false
열거형 (enum)
연관성이 있는 값을 모아 놓은 것을 말한다. 각 항목은 그 자체로 고유값이다.
enum CompassPoint {
case north
case south
case east
case west
}
var direction = Compasspoint.east // east
enum PhoneError {
case unknown
case batteryLow(String)
}
let error = PhoneError.batteryLow("배터리가 곧 방전됩니다") // 연관값 넘겨받기
옵셔널 체이닝
옵셔널에 속해 있는 nil 일지도 모르는 프로퍼티, 메서드, 서브스크립션 등을 가져오거나 호출할 때 사용할 수 있는 일련의 과정
struct Developer {
let name: String
}
struct Company {
let name: String
var developer: Developer?
}
var developer = Developer(name: "Hong")
var company = Company(name: "Gildong", developer: developer)
print(company.developer)
print(company.developer?.name)
print(company.developer!.name)
try-catch
에러처리 : 프로그램 내에서 에러가 발생한 상황에 대응하고 이를 복구하는 과정을 말하며 스위프트는 런타임에러가 발생한 경우 이를 처리하기 위해 발생, 감지, 전파, 조작을 관리하는 클래스를 제공한다.
enum PhoneError: Error {
case unknown
case batteryLow(batteryLevel: Int)
}
// 에러 발생
throw PhoneError.batteryLow(batteryLevel: 20)
// 쓰로잉 함수
func checkPhoneBatteryStatus(batteryLevel: Int) throws -> String {
guard batteryLevel != else { throw PhoneError.unknown }
guard batteryLevel >= 20 else { throw PhoneError.batteryLow(batteryLevel: 20)}
return "배터리 상태가 정상입니다."
}
// do try catch
/*
do {
try 오류 발생 가능 코드
} catch 오류 패턴 {
처리코드
}
*/
do {
try checkPhoneBatteryStatus(batteryLevel: -1)
} catch PhoneError.unknown {
print("알 수 없는 에러입니다.")
} catch PhoneError.batteryLow(let batterryLebel) {
print("배터리 전원 부족 남은 배터리 : \(batterryLebel)%")
} catch {
print("그 외 오류 발생 : \(error)")
}
let status = try? checkPhoneBatteryStatus(batteryLevel: -1) // nil
let status = try! checkPhoneBatteryStatus(batteryLevel: 30) // 오류 발생시 런타임에러
클로저
코드에서 전달 및 사용할 수 있는 독립 기능 블록이며, 일급 객체의 역할을 할 수 있음
일급객체 : 전달 인자로 보낼 수 있고, 변수/상수 등으로 저장하거나 전달할 수 있으며, 함수의 반환 값이 될 수도 있다.
/*
{ (매개 변수) -> 리턴 타입 in
실행 구문
}
*/
let hello = { (name:String) -> String in
return "Hello \(name)"
}
hello("Gildong") // Hello Gildong
고차함수
다른 함수를 전달 인자로 받거나 함수 실행의 결과를 함수로 반환하는 함수
map, filter, reduce
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
let intArray = [10,5,20,13,4]
let filterArray = intArray.filter { $0 > 5 }
print("filter \(filterArray)") // filter [10 ,20, 13]
// reduce
let someArray = [1,2,3,4,5]
let reduceResult = someArray.reduce(0) {
(result: Int, element: Int) -> Int in
print("\(result) + \(element)")
return result + element
}
print("reduce \(reduceResult)")