Seize the day
article thumbnail

변수와 상수

변수(variable) 은 var, 상수(constant)는 let 으로 사용합니다.

var name = "Lee SeongHyeon"
let birthday = 1999

만약 이름을 바꾸고 싶다면 바꿀 수 있지만 생일은 바꿀 수 없습니다.(변수와 상수 차이)

name = "Hong gildong" // 가능
birthday = 2000 // 불가능

또한 swift는 정적 타이핑 언어로, 변수나 상수를 정의할 때 그 자료형(타입)이 어떤 것인지 명시를 해주어야 합니다.

var name: String = "Lee SeongHyeon"
let birthday: Int = 1999
var height: Float = 178.5

만약 다른 자료형끼리 연산을 하려고 하면 컴파일 에러가 발생합니다.

따라서 변환을 통해 연산이 가능할 수 있도록 해야합니다.

String(birthday) + "년 " + name + "(이)가 태어났습니다." // 1999년 이성현(이)가 태어났습니다.
// swift식 간단한 표현
"\(birthday)년 \(name)(이)가 태어났습니다."

하지만 처음 예제를 보면 자료형을 명시하지 않았는데도 타입을 알 수 있었습니다.

swift 컴파일러는 "타입 추론(Type Inference)"가 가능합니다.

 

배열과 딕셔너리

배열과 딕셔너리는 대괄호를 사용해 파이썬과 비슷하게 정의할 수 있습니다.

var name = ["이성현", "홍길동", "파이썬"] //배열
var capitals = [
	"한국": "서울",
    "일본": "도쿄",
    "중국": "베이징",
]

// 값에 접근할 때도 대괄호를 사용
name[0] // 이성현
name[1] = "자바"

capitals["한국"] //서울
capitals["프랑스"] = "파리"

// 빈 배열이나 딕셔너리 정의
var languages: [String] = []
var capitals: [String: String] = [:]

// 좀 더 간단한 정의(생성자 사용)
var languages = [String]()
var capitals = [String: String]()

조건문과 반복문

조건을 검사할 땐 if, switch를 사용합니다.

var age = 19
var student = ""

if age >= 8 && age < 14 {
  student = "초등학생"
} else if age < 17 {
  student = "중학생"
} else if age < 20 {
  student = "고등학생"
} else {
  student = "기타"
}

student // 고등학생

if 문의 조건절에는 무조건 Bool 타입을 사용해야 합니다. 다른 언어에서처럼 0, 1 로 True, False를 구분할 수 없습니다.

 

switch는 패턴 매칭이 가능하다는 특별함을 가지고 있습니다.

switch age {
case 8..<14:
  student = "초등학생"
case 14..<17:
  student = "중학생"
case 17..<20:
  student = "고등학생"
default:
  student = "기타"
}

위의 예제와 같이 8..<14를 사용해 age가 8이상 14이하에 포함된다면 초등학생으로 정할 수 있습니다.

 

반복문은 for, while을 사용합니다.

for 구문을 사용해 배열과 딕셔너리를 차례로 순환해보겠습니다.

for language in languages {
  print("저는 \(language) 언어를 다룰 수 있습니다.")
}

for (country, capital) in capitals {
  print("\(country)의 수도는 \(capital)입니다.")
}

//단순한 반복문 만들기
for i in 0..<100 {
  i
}

파이썬과 마찬가지로 _를 사용해 무시할 수 있습니다.

 

옵셔널(Optional) 📖

swift가 가지고 있는 가장 큰 특징 중 하나는 바로 옵셔널입니다. 말 그대로 옵션, 값이 있을 수도 있고 없을 수도 있다는 것을 의미합니다.

예로 문자열의 값으로 "가나다"가 있다고 했을 때, 만약 값이 없다면 ""일까요? 아닙니다. 값이 없는게 아니라 값이 비어있다는 의미죠. 바로 값이 없다는 뜻은 nil 입니다.

만약 정수형의 값이 없다면 0 이 아니라 nil입니다.

배열과 딕셔너리의 경우에도 똑같이 값이 없으면 nil을 사용합니다.

하지만 모든 변수에 nil을 넣을 수 있는 건 아닙니다.

var name: String = "이성현"
name = nil // 컴파일 에러 발생

옵셔널 변수를 정의할 때는 타입에 ?를 붙여야 합니다. 이렇게 정의한 변수를 옵셔널이라고 합니다.

만약 초깃값을 지정하지 않으면 기본값은 nil 입니다.

var email: String?
print(email) // nil

email = "zxl3651@naver.com"
print(email) // Optional("zxl3651@naver.com")

옵셔널은 기존 변수와는 다릅니다. 따라서 아래와 같은 코드는 컴파일 에러가 발생합니다.

let optionalEmail: String? = "zxl3651@naver.com"
let requiredEmail: String = optionalEmail // 컴파일 에러!

옵셔널에 값을 정의했지만 실제로 코드가 실행되기 전까지는 값이 있는지 없는지 알 수 없습니다.

그래서 swift 컴파일러는 안전을 위해 옵셔널로 선언된 변수를 대입할 수 없게 만들었습니다.

 

옵셔널 바인딩(Optional Binding)

만약 옵셔널의 값을 가져오고 싶을 땐 옵셔널 바인딩을 사용하면 됩니다.

옵셔널 바인딩은 옵셔널의 값이 존재하는지 검사 후, 존재하면 그 값을 다른 변수에 대입시켜줍니다.

if let, if var를 사용해 옵셔널 바인딩을 사용할 수 있고, 만약 옵셔널에 값이 있다면 if문 안으로 들어가고 nil 이라면 그냥 통과하게 됩니다.

예를 들어, 아래의 코드에서 optionalEmail에 값이 존재한다면 email이라는 변수 안에 실제 값이 저장되고, if문 내에서 그 값을 사용할 수 있습니다. 만약 optionalEmail nil이라면 if문이 실행되지 않고 넘어갑니다.

if let email = optionalEmail {
  print(email) // optionalEmail의 값이 존재한다면 해당 값이 출력됩니다.
}
// optionalEmail의 값이 존재하지 않는다면 if문을 그냥 지나칩니다.

하나의 if문에서 콤마(,) 를 사용해 여러 옵셔널을 바인딩 할 수 있습니다. 모든 옵셔널의 값이 존재해야 if문 안으로 진입합니다.

var optionalName: String? = "이성현"
var optionalEmail: String? = "zxl3651@naver.com"

if let name = optionalName, email = optionalEmail {
  // name과 email 값이 존재
}

// 옵셔널 바인딩과 조건을 함께 지정할 수 있다.
var optionalAge: Int? = 22

if let age = optionalAge, age >= 20 { //이때 옵셔널이 벗겨진 값을 가지고 조건을 검사
  // age의 값이 존재하고, 20 이상입니다.
}

옵셔널 체이닝(Optional Chaning)

swift 코드를 간결하게 만들어주는 많은 요소 중, 옵셔널 체이닝이 있습니다.

복잡한 코드를 간결하게 줄여주는 옵셔널 체이닝의 예제를 보면서 이해할 수 있습니다.

만약 옵셔널 배열이 있을때, 이 배열이 빈 배열인지 검사하려면 어떻게 해야 할까요?

let array: [String]? = []
var isEmptyArray = false

if let array = array, array.isEmpty {
  isEmptyArray = true
} else {
  isEmptyArray = false
}

isEmptyArray

//옵셔널 체이닝을 사용하면
let array: [String]? = []
let isEmptyArray = array?.isEmpty == true

위의 빈 배열인지 검사하는 코드를 ? 키워드로 아래처럼 한줄로 줄일 수 있습니다.

array?.isEmpty의 결과로는 nil, true, false 입니다. isEmpty의 반환값은 Bool인데, 옵셔널 체이닝으로 Bool?을 반환하도록 바뀐 것입니다. 따라서 실제로 true인지 확인을 하려면, == true를 해주어야 확인할 수 있습니다.

 

옵셔널 벗기기

옵셔널을 사용할 때마다 옵셔널 바인딩을 하는 것이 바람직하지만, 개발을 하다보면 분명히 값이 존재하지만 옵셔널로 사용해야 하는 경우가 있습니다. 이럴 땐 옵셔널에 값이 있다고 가정하고 바로 값에 접근할 수 있도록 도와주는 ! 키워드를 사용하면 됩니다.

print(optionalEmail) // Optional("zxl3651@naver.com")
print(optionalEmail!) // devxoul@gmail.com

! 키워드를 사용할 땐, 만약 옵셔널의 값이 nil 이라면 런타임 에러가 발생합니다.

Java의 NullPointerException과 비슷하다고 생각하면 됩니다.

 

암묵적으로 벗겨진 옵셔널(Implicitly Unwrapped Optional)

만약 옵셔널을 정의할 때 ? 대신 ! 를 붙이면 Implicitly Unwrapped Optional이라는 옵셔널로 정의됩니다.

var email: String! = "zxl3651@naver.com"
print(email) // zxl3651@naver.com

이렇게 정의된 옵셔널은 nil을 포함할 수 있는 옵셔널이지만, 접근 시 옵셔널 바인딩이나 옵셔널을 벗기는 과정을 거치지 않아도 바로 값에 접근할 수 있다는 점이 일반적인 옵셔널과 다릅니다.

만약 값이 없는데 접근을 시도하면 런타임 에러가 발생합니다.

 

가급적이면 일반적인 옵셔널을 사용해 정의하고, 옵셔널 바인딩 또는 옵셔널 체이닝을 통해 값에 접근하는 것이 더 바람직합니다.

profile

Seize the day

@성 현

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!