Swift 기본 문법 #2
원본 링크 : https://dawn-horse-972.notion.site/Week-2-982b50c01da04d2faebb13f39228784f
학습목표
- 기본 컬렌션 타입을 활용해 데이터 메모리에 저장할 수 있다
- 반복문 활용해 문제 해결
- 다양한 형태의 함수 이용, 응용
- 논리 연산자의 종류를 알고 코드에 활용
- 열거형을 통해 프로그래머에게 한정된 선택지 제공해보기
- 조건문을 활용해 상황에 따른 동작 제어
- Optional을 이해하고 안전하게 사용하기
01. 컬렉션 타입
- Array : 순서(인덱스)가 있는 리스트 컬렉션
- Dictionary : 키와 값의 쌍으로 이루어진 컬렌션 (like HaspMap)
- Set : 순서가 없고 멤버가 유일한 컬렉션 (like 집합)
Array
- Array : 순서(인덱스)가 있는 리스트 컬렉션
- Dictionary : 키와 값의 쌍으로 이루어진 컬렌션 (like HaspMap)
- Set : 순서가 없고 멤버가 유일한 컬렉션 (like 집합)
Array
선언과 축약 표현
//Int 타입의 빈 Array 생성
var integers: Array<Int> = Array<Int>()
//Array<Int> == [Int]
var integers: Array<Int> = [Int]()
var integers: [Int] = [Int]()
//[]는 새로운 빈 Array
var integers: [Int] = []
-
같은 표현
var integers: Array<Int> = Array<Int>() var integers: Array<Int> = [Int]() var integers: Array<Int> = [] var integers: [Int] = [] var integers = [Int]()
let을 사용해 Array를 선언하면 불변 Array가 생성된다
let immutableArray = [1, 2, 3]
//append나 remove같은 메소드 사용 불가
Array 관련 메소드
.append(1)
.contains(100)
.remove(at: 0)
.removeLast()
.removeAll()
.count
//없는 인덱스에 접근하려고 하면 프로그램 강제 종료
//integers[0], integers[99] = 99
Dictionary
딕셔너리는 순서나 정렬 없이 그저 키 - 값의 쌍으로 요소가 존재할 뿐
선언과 축약표현
//Key - String타입, Value - Any타입인 빈 Dictionary 생성
var anyDictionary: Dictionary<String, Any> = [String: Any]()
//[:]는 빈 딕셔너리를 나타낸다
var emptyDictionary: [String: Any] = [:]
anyDictionary["somekKey"] = "value" //딕셔너리에 "someKey": "value" 추가
anyDictionary["anotherKey" = 100 //딕셔너리에 "anotherKey": 100 추가
-
같은 표현
var anyDictionary: Dictionary<String, Any> = Dictionary<String, Any>() var anyDictionary: Dictionary<String, Any> = [:] var anyDictionary: [String: Any] = [String: Any]() var anyDictionary: [String: Any] = [:] var anyDictionary = [String: Any]()
let으로 선언하면 불변 Dictionary가 생성된다.
let initalizedDictionary: [String: String] = ["name": "sujilee",
"height": "169.2"]
Dictionary 관련 메소드
.removeValue(forkey: "anotherKey")
과제?! → 해보니까 옵셔널과 관련있는 듯
//Error!
let someValue: String = initializedDictionary["name"]
//이건 왜 안될까? someValue에 "sujilee"가 담겨야하는 것 아닌가?
//"name" 키에 해당하는 값이 없을 수도 있으므로 String 타입의 값이 나올거라 보장 못함
//nil이 나오면 어쩔건데? 컴파일 오류 발생
Set
순서가 없고, 멤버가 유일한 것을 보장하는 컬렉션 타입
선언. (Set는 축약 표현 X)
var integers: Set<Int> = Set<Int>()
Set 관련 메소드
integers.insert()
integers.contains()
integers.remove()
integers.removeFirst()
integers.count
Set의 응용
import Foundation
var anyDictionary: Dictionary<String, Any> = [String: Any]()
let setA: Set<Int> = [1, 2, 3, 4, 5]
let setB: Set<Int> = [3, 4, 5, 6, 7]
//union() 메소드로 합집합 구하기
let union: Set<Int> = setA.union(setB)
//sorted() 메소드로 집합 정렬시켜 오름차순 String 배열로 만들기
let sortedUnion: [Int] = union.sorted()
//intersection() 메소드로 교집합 구하기
let intersection: Set<Int> = setA.intersection(setB)
//subtracting() 메소드로 차집합 구하기 (setA - setB)
let subtracting: Set<Int> = setA.subtracting(setB)
생각해보기
- 각각 어떤 컬렉션 타입을, 상수/변수 중 어떤 것을 사용하면 유용할지
- 영어 알파벳 소문자를 모아두는 컬렉션 → 상수 Array
- 책의 제목과 저자 정리를 위한 컬렉션 → 상수 Dictionary
- 우리반 학생 명부 작성을 위한 컬렉션 → 상수 Set
02. 반복문
- for-in
- while
- repeat-while
컬렉션 타입과 잘 사용된다
for-in
import Foundation
// for item in items {
// code
// }
var integers = [1, 2, 3]
let people = ["sujilee": 1206, "kchoi": 1127, "pol": 1101]
for integer in integers {
print(integer);
}
//Dictionary의 item은 key와 value로 구성된 튜플 타입
for (name, age) in people {
print("\(name): \(age)")
}
while
condition에는 꼭 bool값이 들어와야한다 !
import Foundation
//while condition {
// code
//}
var integers = [1, 2, 3]
let people = ["sujilee": 1206, "kchoi": 1127, "pol": 1101]
//한개 남기고 뒤에서부터 반복 삭제
while integers.count > 1 {
integers.removeLast()
}
print (integers)
repeat - while
기존의 do while과 흡사하다
import Foundation
//repeat {
// code
//} while condition
var integers = [1, 2, 3]
let people = ["sujilee": 1206, "kchoi": 1127, "pol": 1101]
//일단 한 번 맨 뒤 요소를 제거하고, 전부 사라질때까지 반복하라.
repeat {
integers.removeLast()
} while integers.count > 0
print(integers)
(do란 키워드가 오류처리에서 쓰여서 do while 안쓰는거임)
💡 Swift Language - Control Flow : [https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html](https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html) 03. 함수 고급
매개변수 기본값
import Foundation
//기본값을 갖는 매개변수는 매개변수 목록 중 뒤쪽에 위치하는 것이 좋음
//매개변수 me를 기본값으로 갖는 함수
func greeting (friend: String, me: String = "sujilee") {
print("Hello \(friend) it's me, \(me)!")
}
//함수 호출 시 매개변수 생략 가능
greeting(friend: "kchoi")
//물론 원하는 인자도 넘길 수 있다
greeting(friend: "kchoi", me: "suji")
전달인자 레이블
import Foundation
//기본값을 갖는 매개변수는 매개변수 목록 중 뒤쪽에 위치하는 것이 좋음
//매개변수 me를 기본값으로 갖는 함수
func greeting (friend: String, me: String = "sujilee") {
print("Hello \(friend) it's me, \(me)!")
}
//함수 호출 시 매개변수 생략 가능
greeting(friend: "kchoi")
//물론 원하는 인자도 넘길 수 있다
greeting(friend: "kchoi", me: "suji")
함수 호출 시 매개변수의 역할을 더 명확하게 하거나, 함수 사용자의 입장에서 표현하고자 할때 사용
import Foundation
//매개변수 이름 앞에 전달인자 레이블을 표시한다
//함수 구현 시, 함수 내부에서는 매개변수 이름을 사용
func greeting(to friend: String, from me: String) {
print("Hello \(friend) it's me, \(me)!")
}
//함수 호출 시, 함수 외부에서는 전달인자 레이블 사용
greeting(to: "sean", from: "suji")
위 매개변수 기본값에서 쓰인 greeting 함수와 함수명이 같으나, 전달인자 레이블을 씀으로써 중복방어? 가 되어 다르게 취급된다 !
가변 매개변수
전달받을 매개변수의 개수를 알기 어려울 때 사용 - (5.4미만은 함수 당 하나만 가질 수 있다.)
import Foundation
func sayHelloToFriends(me: String, friends: String...) -> String {
return "Hello \(friends) it's \(me)!"
}
print(sayHelloToFriends(me: "suji", friends: "kcho", "sean", "joockim"))
//OUTPUT : Hello ["kcho", "sean", "joockim"] it's suji!
데이터 타입으로서의 함수
Swift는 함수형 프로그래밍 패러다임을 포함하는 다중 패러다임 언어
함수 : 일급 객체 → 변수, 상수 등에 저장 가능. 매개변수를 통해 전달 가능
스위프트의 함수는 하나의 데이터 타입으로도 표현, 사용 될 수 있음
import Foundation
func greeting(to friend: String, from me: String) {
print("Hello \(friend) it's me, \(me)!")
}
//변수 someFunction에, (Sting, Sting)을 매개변수로 가지고 Void를 반환하는 함수 할당
//조건에 일치하는 greeting 함수를 할당할 수 있다.
var someFunction: (String, String) -> Void = greeting(to:from:)
//매개변수의 타입이 같아야함
someFunction = greeting(to:from:)
someFunction("sujilee", "jseo")
//OUTPUT : Hello suji it's me, jseo!
//함수의 매개변수로, (String, String)을 매개변수로 가지고 Void를 반환하는 함수를 받음
func runAnother(function: (String, String) -> Void) {
function("suji", "lea")
}
//runAnother 함수의 매개변수로 조건에 부합하는 greeting함수 넘김.
//greeting함수의 인자는 이미 runAnother 함수 내부에서 지정해놓음
runAnother(function: greeting(to:from:))
//OUTPUT : Hello suji it's me, lea!
runAnother(function: someFunction)
//OUTPUT : Hello suji it's me, lea!
💡 Swift Language - Functions : [https://docs.swift.org/swift-book/LanguageGuide/Functions.html](https://docs.swift.org/swift-book/LanguageGuide/Functions.html)
04. 논리연산자
Bool → 참/거짓, 논리 연산
- 비교연산자 → 비교한 결과로 Bool값(참/거짓)을 만든다
- 논리 연산자
true && false == false
true && true == true
true || false == true
true || true == true
- 비트연산자(Bitwise operator)
수학적 연산보다는 비트검출이나 옵션전달의 목적으로 사용
//옵션 선택지 전달 예시
import Foundation
let apple: Int = 1
let orange: Int = 2
let banana: Int = 4
func printFavoriteFruits(_ selectedFruits: Int) {
print("사과를 좋아함 : \((selectedFruits & apple) != 0)")
print("오렌지를 좋아함 : \((selectedFruits & orange) != 0)")
print("바나나를 좋아함 : \((selectedFruits & banana) != 0)")
}
printFavoriteFruits(apple | orange)
//apple | orange == 0001 | 0010 == 0011
let 진동모드 = 1 // 0001
let 비행기모드 = 2 // 0010
let 와이파이 = 4 // 0100
let 현재모드 = 진동모드 | 비행기모드 // 0011
Swift에서는 OptionSet 이라는 프로토콜을 활용해 위와 같은 기능 구현
💡 OptionSet : [https://developer.apple.com/documentation/swift/optionset](https://developer.apple.com/documentation/swift/optionset) 05. 열거형 (Enumeration)
Int, Double, String처럼 스위프트 표준 라이브러리에서 제공하는 타입과 다르게 사용자가 필요에 의해 만들어 사용하는 타입 → Type(타입)의 일종 : 대문자로 시작
- (다른 프로그래머에게) 제한된 선택지를 주고 싶을 때
- (함수 등에서 다른 프로그래머에게) 정해진 값 외에는 입력받고 싶지 않을 때
import Foundation
//Dish라는 타입으로 dish 매개변수의 타입을 제한
enum Dish {
case rice, noodle, soup
}
//Dish에서 정의한 선택지 외에는 dish 매개변수의 인자로 전달할 수 없음
func choose(dish: Dish) {
print("\(dish)를 골랐군요!")
}
choose(dish: Dish.rice)
//dish에 전달하는 인자는 Dish 타입이 분명하므로 타입 이름 생략, .뒤에 케이스만 적어도 ok
//이런걸 타입추론이라고 하는데, 초보자는 쓰지마라!
choose(dish: .rice)
//아래와 같은 표현 모두 가능
enum Dish {
case rice
case noodle
case soup
}
enum Dish {
case rice, noodle
case soup
}
원시값(rawValue) 사용 예시
import Foundation
//원시값(rawValue) 사용 : 각 case별로 고유한 값 지정
enum Dish: String {
case rice = "밥", noodle = "면", soup = "스프"
}
func choose(dish: Dish) {
print("\(dish.rawValue)를 골랐군요!")
}
choose(dish: Dish.rice)
//OUTPUT : 밥을 골랐군요!
원시값(rawValue) 사용 예시 2
import Foundation
enum Bearings: String {
case east = "동"
case west = "서"
case south = "남"
case north = "북"
}
func navigateBearings(bearings: Bearings) {
print("\(bearings.rawValue)쪽으로 가십시오")
}
navigateBearings(bearings: Bearings.east)
06. 조건문
- if-else
- switch
Swift의 조건에는 항상 Bool 타입이 들어와야 함
if-else
let someInteger = 100
if someInteger < 100 {
print("100 미만")
} else if someInteger > 100 {
print("100 초과")
} else {
print("100")
}
switch
import Foundation
//switch value {
//case pattern:
// code
//default:
// code
//}
let someInteger = 100
switch someInteger {
case 0:
print("zero")
//1 이상 100 미만
case 1..<100:
print("1~99")
case 100:
print("100")
case 101...Int.max:
print("over 100")
default:
print("unknown")
}
switch "sujilee" {
case "kchoi", "sean":
print("kchoi or sean")
case "joockim"
print("joockim")
default:
print("unknown")
}
switch "sujilee" {
case "kchoi":
print("kchoi or sean")
fallthrough
case "jseo"
print("kchoi or sean")
case "joockim"
print("joockim")
default:
print("unknown")
}
07. Optional
옵셔널의 이해
Swift의 조건에는 항상 Bool 타입이 들어와야 함
let someInteger = 100
if someInteger < 100 {
print("100 미만")
} else if someInteger > 100 {
print("100 초과")
} else {
print("100")
}
import Foundation
//switch value {
//case pattern:
// code
//default:
// code
//}
let someInteger = 100
switch someInteger {
case 0:
print("zero")
//1 이상 100 미만
case 1..<100:
print("1~99")
case 100:
print("100")
case 101...Int.max:
print("over 100")
default:
print("unknown")
}
switch "sujilee" {
case "kchoi", "sean":
print("kchoi or sean")
case "joockim"
print("joockim")
default:
print("unknown")
}
switch "sujilee" {
case "kchoi":
print("kchoi or sean")
fallthrough
case "jseo"
print("kchoi or sean")
case "joockim"
print("joockim")
default:
print("unknown")
}
옵셔널의 이해
optional : 값이 있을 수도, 없을 수도
옵셔널이 아닌 상수에다 nil값을 할당하려고 하면 컴파일 에러 발생
옵셔널 : nil의 가능성을 명시 → 별도의 문서 작성, 닐 체크 필요없음, 예외사항 최소화
! (Implicity Unwrapped Optional) : 암시적 추출 옵셔널
- 암시적 추출 옵셔널 형식 예시
import Foundation
var optionalValue: Int! = 100
switch optionalValue {
case .none:
print("This Optional variable is nil")
case .some(let value):
print("Value is \(value)")
}
//기존 변수처럼 사용 가능
optionalValue = optionalValue + 1
//nil 할당 가능
optionalValue = nil
//잘못된 접근으로 인한 런타임 오류 -> nil에 어떻게 + 1을 하냔 말이야
optionalValue = optionalValue + 1
? (Optional)
기존 변수처럼 사용 불가 - 여타 타입과는 다른 타입임
옵셔널 값 추출(Optional Unwrapping)
-
Optional Binding(옵셔널 바인딩)
: 옵셔널의 값을 꺼내오는 방법 중 하나 → nil 체크 + 안전한 값 추출
-
Force Unwrapping(강제 추출)
:
Optional Binding
상자에 똑똑 - 값이 있습니까?
값이 있으면 꺼내오고, 없으면 지나치고
옵셔널 타입은 엄연한 타입이기 때문에 다른 타입에 할당할 수 없다
func printName(_ name: String) {
print(name)
}
var myName: String? = nil
//컴파일 에러 발생
printName(myName) //Error! : 전달되는 값의 타입이 다르기 때문에
그럼 어떻게 할까? if-let을 이용해 옵셔널 바인딩을 해줄 수 있다.
import Foundation
func printName(_ name: String) {
print(name)
}
var myName: String! = nil
if let name: String = myName {
printName(name)
} else {
print("myName == nil")
}
// name 상수는 if-let 구문 내에서만 사용 가능
//컴파일 오류 발생 - 상수 사용범위를 벗어남
printName(name) //Error!
import Foundation
var myName: String? = "sujilee"
var yourName: String? = nil
//name과 friend 모두 값이 있어야(nil이 아니어야) print가 실행됨
if let name = myName, let friend = yourName {
print("\(name) and \(friend)")
}
//yourName이 nil이라 실행되지 않음
yourName = "sean"
if let name = myName, let friend = yourName {
print("\(name) and \(friend)")
}
//sujilee and sean
옵셔널 강제 추출
정중하게 값을 꺼내오는 옵셔널 바인딩과 다르게 그냥 옵셔널 보호막을 강제로 깨부수고 값을 가지고 나온다
import Foundation
func printName(_ name: String) {
print(name)
}
var myName: String? = "suijlee"
//!를 붙이면 옵셔널타입인 myName의 값을 강제로 추출해낸 값이라는 뜻
printName(myName!) // 옵셔널 타입인 myName 안의 String 타입의 "sujilee"가 담김
//OUTPUT : sujilee
myName = nil
//런타임 오류 발생
print(myName!) //Error! : 강제추출 시 값이 없으므로 오류
//처음부터 강제추출되는 효과를 가짐 -> 위에 인자로 넘긴 myName!와 같은 의미
var yourName: String! = nil
//런타임 오류 발생
printName(yourName) //Error! : 강제추출 시 값이 없으므로 오류
옵셔널 강제 추출 방식은 그다지 추천되지 않음. 안전하게 옵셔널 바인딩 사용 권장
🐻 Swift Language - The Basicss : [https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html](https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html)딕셔너리 타입의 느낌표
import Foundation
var someDictionary: [String: String] = [:]
//day(of: today)는 예시를 위해 있다고 가정하자
let day: Int = day(of: today)
if day == 1 || day == 30 {
someDictionary["날씨"] = "맑음"
} else {
someDictionary["풍향"] = "남동풍"
}
//이 시점에 "날씨" 키에 해당하는 값이 항상 존재한다고 장담할 수 있을까?
컴파일러는 “날씨”키에 해당하는 값이 항상 있을 수 없다고 생각함. 더불어 딕셔너리 타입은 언제든 키와 값을 수정할 수 있기 때문에 컴파일하는 시점에 딕셔너리 내부의 키-값 쌍이 어떻게 변화할지 모름 → 따라서 딕셔너리에서 값을 꺼내올 때에는 항상 값이 없을 수 있음에 대비해야한다.
Author And Source
이 문제에 관하여(Swift 기본 문법 #2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@eelijus/Swift-기본-문법-2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)