Swift 2주차
출처 - https://www.kxcoding.com/course/essential-swift
Essential Swift
iOS 앱 개발을 가볍게 시작해 보세요. Swift를 다양한 예제, 상세한 설명과 함께 정복할 수 있습니다. 문법적 기초가 튼튼해야 원하는 기능을 자유롭게 구현할 수 있습니다.
www.kxcoding.com
아래 내용들은 KxCoding의 essential-swift강의를 보고 작성되었습니다.
Working with Variables
변수(Variable)
어떤 값을 저장하는 공간
언제든지 새로운 값을 저장할 수 있다.
var variableName(변수이름) = initialValue(초기값) //=: Assignment Operator(할당연산자)
var name = "Swift" // Swift라는 문자열 값이 name라는 변수에 저장
// "Swift": String Literal(문자열 리터럴)
var thisYear = 2024
var valid = true
name //메모리에 저장된 값을 읽어오기만 함, 의미 X
print(name) //실제 프로젝트에서 저장된 값을 확인할 때는 print나 dump함수 이용
variableName = initialValue //변수에 새로운 값 저장
name //Ambiguous use of 'name'
print(name) //Ambiguous use of 'name'
var name = "Steve" //err, Invalid redeclaration of 'name'
name = "Steve" //변수에 저장되어있는 값이 새로운 값으로 바뀜
name = "윤아"
print(name) //윤아
var anotherName = name
anotherName = "Tim"
print(name, anotherName) //윤아, Tim
//변수의 값을 바꿔도 다른 변수의 값은 바뀌지 않음
thisYear = "2024" //err, Cannot assign value of type 'String' to type 'Int'
상수(Constant)
let constantName = initialValue
let name = "Yoona"
name
name = "Steve" //err, Cannot assign to value:'name' is a 'let' constant
//상수는 한 번만 저장이 가능하고 그 다음부터는 읽기만 가능하다
Naming Convention
CamelCase
이름에 포함된 첫번째 문자를 표기하는 방법, 두 개 이상의 단어가 포함되어 있을때 단어를 구분하는 방법 규정
케이스 유형 | 설명 | 예시 | 적용되는 항목 |
UpperCamelCase | 이름에 포함된 모든 첫 번째 문자를 대문자로, 나머지는 모두 소문자로 함. | Name, BookIndex, MemberNumber, CreditCard, UserStatusCode | Class, Structure, Enumeration, Extension, Protocol |
lowerCamelCase | 첫 번째 문자는 항상 소문자, 나머지는 UpperCamelCase와 같음. | name, bookIndex, memberNumber, creditCard, userStatusCode | Variable, Constant, Function, Property, Parameter |
Scope(범위)
Global Scope(전역범위)
어떤 브레이스에도 속하지 않음
딱 하나밖에 없다
Local Scope(지역범위)
무조건 브레이스 안에 있음
여러 단계로 중첩 가능 -> 두 개 이상 존재 가능
Declaration Scope(선언범위)
import UIKit
// #1 Global Scope
let g1 = 23 //Global Scope안에서 더이상 g1이라는 이름은 사용할 수 없음
func doSomething() {
// #3 Local Scope
let local1 = 123
let g1 = 789
if true {
// #4 또 다른 Local Scope
let local3 = 123
}
// #5 Local Scope
let local2 = 123
}
// #2 Global Scope
let g2 = 456
struct Scope {
// #6 Declaration Scope
var a = g1
func doSomething() {
// #7 Declaration Scope안에 있는 Local Scope
}
}
#1, #2 둘 다 어떤 브레이스에도 속하지 않는 Global Scope
#3, #4 둘다 Local Scope에 있지만 4번이 3번 아래에 포함되어있음
#3, #5는 동일한 함수 내부에 있고 깊이도 동일 -> 동일한 로컬 스코프
규칙
1. 동일한 스코프에 접근할 수 있다.
2. 글로벌 스코프에서는 선언 순서에 상관없이 접근할 수 있다.
3. 로컬 스코프에서 상위 스코프나 글로벌 스코프에 접근할 수 있다.
4. 글로벌 스코프가 아니라면 이미 선언되어있는 요소에만 접근할 수 있다.
5. 상위 스코프는 하위 스코프에 접근할 수 없다.
6. 서로 다른 스코프에 동일한 이름이 존재한다면 가장 가까운 스코프에 있는 이름을 사용한다.
7. 글로벌 스코프가 아닌 다른 모든 스코프는 시작과 끝이 명확해야 한다.
Literals, Data Types
메모리의 구조와 크기
Memory
0과 1을 저장할 수 있는 반도체
전기가 들어오면 1, 들어오지 않으면 0 저장
Bit
0이나 1을 저장할 수 있는 가장 적은 공간, 정보의 기본 단위
Byte
bit가 8개 모인 공간, 프로그래밍 언어에서 사용하는 기본 단위
양수: 0 ~ 255, 양수와 음수 모두: -1328 ~ 127 까지 저장 가능
ex) 22 -> 00010110
Most Significant Bit Least Significant Bit
MSB LSB
0 0 0 1 0 1 1 0
<---------------------------------------->
Data Bit
Singed와 Unsigned
Signed | 음수와 양수, 숫자 0을 모두 저장할 수 있는 타입 |
Unsigned | 음수는 저장하지 않고 양수와 0만 저장 |
Sing Bit
최상위 비트에 저장된 값 | 0 | 양수(Positive Number) |
1 | 음수(Negative Number) |
2's Complement
양수의 비트값을 반전시킨 다음 1을 더해 음수를 표현하는 방식
ex) 22 -----> 0 0 0 1 0 1 1 0 --Bitwise Not--> 1 1 1 0 1 0 0 1 --+1--> 11101010
실수를 저장하는 방법
1. 실수를 저장할 때는 지수와 가수로 나눠서 저장한다.
2. 동일한 메모리 크기에서 정수보다 더 넓은 범위를 저장할 수 있다
3. 부동 소수점에는 오차가 있어서 100% 정확한 값을 저장할 수 없다
Data Types
Built-in Data Type | |
Integer Type | 정수 저장 |
Floating-Point Type | 소수점이 포함된 수를 저장 |
Boolean Type | 참과 거짓 저장 |
Character Type | 하나의 문자를 저장 |
String Type | 0개 이상의 문자 저장 |
Custom Data Type
구조체와 클래스로 직접 만드는 자료형
Numbers
Number Literal
123 //정수 리터럴
+123 //양수, +기호 생략가능
-123 //음수, -기호 생략 불가능
1.23 //실수, 정수 부분 생략 불가능
1.23e4 //10진수 실수는 지수의 형태로 표현할 수 있음
0xAP2 //16진수 실수
1_000_000 //금액 표시, ,대신 _사용
0b1010 //10진수 10 2진수로 표현
0o12 //8진수로 표현
0xA //16진수
Integer Type
Int8.min //-128
Int8.max //127
Int16.min //-32,768
Int16.max //32,767
Int32.min //-2,147,483,648
Int32.max //2,147,483,647
Int64.min //-9,223,372,036,854,775,808
Int64.max //9,223,372,036,854,775,807
Signed vs Unsigned
Floating-point Type
Float: 4byte
Double: 8byte
let f: Float = 3.141592653589793238462643383279502884197169
let d: Double = 3.141592653589793238462643383279502884197169
print(String(format: "%.20f", f)) //3.14159274101257324219
print(String(format: "%.20f", d)) //3.14159265358979311600
정수를 사용할 때는 Int, 실수를 사용할때는 Double을 사용
Boolean
Boolean Literal
true, false 두 개뿐이고 모두 소문자로 써야함
let happy = true
let happy = false
let isHappy: Bool = true
let str = ""
str.isEmpty
Strings and Characters
String Literal, 문자열 타입과 문자 타입
"Have a nice day"
"123"
let str = "1"
type(of: str) // String.Type
let ch: Character = "1"
type(of: ch) //Character.Type
//let doubleCh: Character ="AA" // err
let emptyCh: Character = " " //Character Type에 빈 문자를 저장하고 싶으면 하나의 공백으로 저장해야 한다
Type Inference
Type Inference
let num = 123
type(of: num) //Int.Type
let temp = 11.2
type(of: temp) //Double.Type
let str = "Swift"
type(of: str) //String.Type
let a = true
let b = false
type(of: a) //Bool.Type
type(of: b) //Bool.Type
Type Annotation
let name: Type = value
var name: Type = value
let num: Int = 123
let value: Double
value = 12.3
Type Inference Rules
123 | Int |
1.23 | Double |
"Hello" | String |
true | Bool |
false | Bool |
Operators
Operator Basics
연산자와 피연산자
a + b
+: Operator
a, b: Operand
피연산자 수에 따른 분류
+a | Unary Operator(단항 연산자) |
a + b | Binary Operator(이항 연산자) |
a ? b : c | Ternary Operator(삼항 연산자) |
연산자와 공백
단항 연산자 | +a | o |
+ a | x | |
이항 연산자 | a + b | o |
a+b | o | |
a +b | x | |
a+ b | x | |
삼항 연산자 | a ? b : c | o |
연산자 위치에 따른 분류
단항 연산자 | +a | Prefix Operator(전치 연산자) |
a+ | Postfix Operator(후치 연산자) | |
이항 연산자 | a + b | Infix Operator(중치 연산자) |
연산자 우선순위
Precedence
연산자 결합규칙
Left Associative | 왼쪽부터 계산 |
Right Asscoiative | 오른쪽부터 계산 |
Arithmetic Operator
+연산자
let a = 12
let b = 34
Plus
+a //12
a + b //46
12 + 34
a + 34
Minus
-a //-12
-b //-32
a - b //-22
Multiplication
a * b //408
Division
a / b //0
b / a //2
let c = Double(a)
let d = Double(b)
c / d //0.3529411764705883
d / c //2.833333333333333
Remainder
a % b //12
c % d //err, 실수 연산은 지원하지 않음
c.truncatingRemainder(dividingBy: d) //12
overflow
let num: Int8 = 9 * 9 //81
//let num2: Int8 = 9 * 9 * 9 //err, overflow
let num2: Int = 9 * 9 * 9 //729
Comparison Operators
let a = 12
let b = 34
Equal to Operator
a == b //false
"swift" == "Swift" //false
Not equal to Operator
a != b //true
Greater than Operator
a > b //false
"swift" > "Swift" //true
Greater than or equal to Operator
7 >= 7 //true
Less than Operator
a < b
Less than or equal to Operator
a <= b
Logical Operators
!연산자
let a = 12
let b = 34
Logical Not Operators
!a //err
!true //false
!false //true
a < b //true
!(a < b) //false
Logical AND Ooerators
a > 10 && b > 10 //true
a > 100 && b > 10 //false
true && true //true
true && false //false
false && true //false
false && false //false
Logical OR Operators
true || true //true
true || false //true
false || true //true
false || false //false
Ternary Conditional Operator
condition ? expr1 : expr2
let hour = 12
hour < 12 ? "오전" : "오후" //오후
hour < 12 ? 123 : 456 //456
hour < 12 ? 123 : "456" //err
Assignment Operators
할당 연산자
let a = 12 //왼쪽 피연산자는 항상 메모리 공간을 가지고 있어야 함
12 = 12 //err
12 + 3 //err
var b = 12
b = 34 //할당연산자가 결과를 리턴하지 않음
LValue
할당 연산자 왼쪽에서 메모리 공간을 나타내는 표현식
RValue
할당 연산자 오른쪽에서 저장할 값을 나타내는 표현식
Compaound Assignment Ooperators
Addition Assignment Operator
var a = 0
a = a + 1
a += 1 //위와 같은 코드
Subtraction Assignment Operator
a -= b
a = a - b
if Statement
if 문
조건의 참과 거짓을 판단한 다음에 실행한 코드를 결정
if condition {
statements
} //Condition == 조건 ==Boolean
결과가 true면 if블록을 실행하고 false이면 실행하지 않음
ex) 간단한 로그인 코드
let id = "root"
let password = "1234qwer"
if id == "root" {
print("valid id")
}
if password == "1234qwer" {
print("valid password")
}
if id == "root" && password == "1234qwer" {
print("go to admin page")
}
if-else 문
if condition{
statements
} else {
statements
}
if블록이 false이면 else문 실행
if id == "root" && password == "1234qwer" {
print("go to admin page")
} else {
print("incorrect value")
}
if-else if 문
if condition {
statements //if 블록, 항상 처음에. 하나만. 필수
} else if condition {
statements // else if 블록, 두 블록 사이에. 하나 이상. 생략 가능
} else {
statements //else 블록, 항상 마지막에. 하나만. 생략 가능
}
let num = 123
if num >= 0 {
print("Positive number or zero") //실행
} else if num % 2 == 0 && num >= 0 {
print("positive even number")
} else if num % 2 == 1 && num >= 0 {
print("positive odd number")
} else {
print("negative number")
}
위의 코드는 문제가 두 가지가 있다
- 조건이 중복되고 있음
- if의 condition과 나머지 else if에 있는 condition이 겹치고 있음
let num = 123
if num >= 0 {
print("Positive number or zero") //실행
if num % 2 == 0 {
print("positive even number")
} else if num % 2 == 1 {
print("positive odd number") //실행
}
} else {
print("negative number")
}
위의 문제를 수정한 코드
let num = 123
if num > 0 {
print("positive number")
} else if num > 10 {
print("positive number over 10")
} else if num > 100 {
print("positive number over 100")
}
무조건 첫번째 if문만 동작
let num = 123
if num > 100 {
print("positive number over 100")
} else if num > 10 {
print("positive number over 10")
} else {
print("positive number")
}
위의 문제를 수정한 코드
guard Statement
gurad문
if문과 마찬가지로 condition을 평가한 다음에 실행한 코드 결정
guard condition else {
statements
}
guard optionalBinding else {
statements
}
else문 생략 불가능, 반드시 else문 안에서 스코프를 종료해야 함
import UIKit
func validate(id: String){
guard id.count >= 6 else {
print("too short")
return
}
print("OK")
}
validate(id: "short") //함수 호출
실행 결과: too short
import UIKit
func validate(id: String){
guard id.count >= 6 else {
print("too short")
return
}
print("OK")
}
validate(id: "kxcondingAdim")
실행 결과: OK
import UIKit
func validate(id: String){
guard id.count >= 6 else {
print("too short")
return
}
guard id.count <= 20 else {
print("too long")
return
}
print("OK")
}
validate(id: "kxcondingAdimdfasfhkafdskjfdhakjdhfjkahfdkjhafkj")
실행 결과: too long
위의 코드 if문으로 구현
func validateUsingIf(id: String){
if id.count >= 6 {
if id.count <= 20 {
print("OK")
} else {
print("too long")
}
} else {
print("too short")
}
}
switch Statement
switch 문
값을 비교한 다음에 값이 일치하면 코드를 실행
switch valueExpression {
case pattern:
statements
case pattern, pattern:
statements
default:
statements
}
ex)
let num = 1
switch num {
case 1:
print("one")
case 2, 3:
print("two or three")
default:
break
}
switch valueExpression {
case pattern:
statements
case pattern where condition:
statements
default:
statements
}
위처럼 where절 추가도 가능하다
Interval Matching
let temperature = Int.random(in: -10 ... 30) //범위연산자, -10에서 30 사이의 값을 만듦
switch temperature {
case ...10: //10 이하의 값 매칭
print("cold")
case 11...20: //11부터 20까지 매칭
print("cool")
case 21...27:
print("warm")
case 28...:
print("hot")
default:
break
}
Fall Through
다음 case로 이동
let attempts = 10
switch attempts {
case ...9:
print("warning")
case 10:
print("locked")
fallthrough
default:
print("send warning email")
}
실행 결과: locked
send warning email