- Udemy ๊ฐ์๋ฅผ ๊ตฌ๋งค ํ ๊ฐ๋ณ ์ธ์ฆ์ ํด์ผ ์คํฐ๋ ์ฐธ์ฌ ๊ฐ๋ฅ
- ๊ฐ์ ํ์ตํ ๋ด์ฉ์ ๊ณต์ฉ study git repository์ ๊ณต์ ํ๊ณ ํ ์ํ๋ฉด์ ๋ด์ฉ ๋ณด์
- ๊ฐ์ธ์ ์ผ๋ก ๊ณต๋ถํ ๋ด์ฉ์ ๊ฐ์ธํด๋์ ๊ธฐ๋ก (fork ํ, ๊ฐ์ธ ์คํฐ๋ ๋ด์ฉ ๊ธฐ๋ก ํ๋ค๊ฐ ๊ณต์ฉ repository์ PR)
- ๊ฐ์ ์๋ฌด๊ฐ์ ๊ฐ๊ณ ์คํฐ๋ํ๊ธฐ ์ํจ
- ๋งค์ฃผ ๋ค์๊ฒฐ๋ก ์คํฐ๋ ๋ ์ง ์ง์ ํ, 2์๊ฐ์ฉ ์คํฐ๋ ์งํ
- ๊ฐ์ธ์ ์ผ๋ก ๊ณต๋ถํ ๋ด์ฉ์ ๊ฐ์ธํด๋์ ๊ธฐ๋ก (fork ํ, ๊ฐ์ธ ์คํฐ๋ ๋ด์ฉ ๊ธฐ๋ก ํ๋ค๊ฐ ๊ณต์ฉ repository์ PR)
- ์คํฐ๋ ๊ธฐ๋ก ์ ๋ฆฌ ๋ฐฉ์์ ๋ํ ์ข์ ์๊ฒฌ ์์ ๋กญ๊ฒ ๊ณต์
- ์คํฐ๋ ์ค์ ์์ ๋กญ๊ฒ ์ดํดํ ๋ด์ฉ์ ์๊ธฐํ ์ ์์ผ๋ฉฐ, ์ดํด๊ฐ ๋์ง ์์ ๋ด์ฉ์ด ์๋ค๋ฉด ์ธ์ ๋ ์ง ๊ณต์
- 1/28(ํ ), ์คํ 2์ ~ 4์ (์๋ฃ)
- Section 2: Swift Collections ~ Section 3: Functions
- ๐ฉ๐ปโ๐ป applebuddy | AppleCEO | Jae-eun
- 2/4(ํ ), ์คํ 9์ ~ 11์ (์๋ฃ)
- Section 4: Enumerations ~ Section 5: Properties, Lazy Stored Properties
- ๐ฉ๐ปโ๐ป applebuddy | AppleCEO | Jae-eun | Lim-YongKwan
- 2/12(์ผ), ์ค์ 10์ ~ 12์ (์๋ฃ)
- Section 5: Computed Properties ~ Section 5: Error Handling, Example 1, Throwing Errors
- ๐ฉ๐ปโ๐ป applebuddy | AppleCEO | Jae-eun | Lim-YongKwan
- 2/19(์ผ), ์ค์ 10์ ~ 12์
- Section 5: Error Handling, Example 2, Throwing Errors ~ Section 9: Async and Await
- ๐ฉ๐ปโ๐ป applebuddy | AppleCEO | Jae-eun | Lim-YongKwan
- 3/5(์ผ), ์ค์ 9์ ~ 11์
- Section 9: Async and Await ~ Section 12: Handling Error for Async Architecture, Using Result Type
- ๐ฉ๐ปโ๐ป applebuddy | AppleCEO | Jae-eun
- 3/11(ํ ), ์ค์ 10์ ~ 12์
- Section 12: Using Result Type ~ finished
- ๐ฉ๐ปโ๐ป applebuddy | AppleCEO | Lim-YongKwan
-
swift๋ก ์ ์ธ๋๋ Array๋ ๊ธฐ๋ณธ์ ์ผ๋ก Sequence ํ๋กํ ์ฝ์ ์ค์ํ๊ณ ์์ต๋๋ค.
-
Sequence ํ๋กํ ์ฝ์ IteratorProtocol opaque type์ ๋ฐํํ๋ makeIterator()๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
- makeIterator()๋ IteratorProtocol์ ์ค์ํ๋ ํ์ ์ ๋ฐํํ ์ ์๋๋ฐ, IteratorProtocol์ ์ค์ํ๊ธฐ ์ํด์๋ next() ๋ฉ์๋๋ฅผ ์ ์ํด์ฃผ์ด์ผ ํฉ๋๋ค.
let names = ["Alex", "John", "Mary"]
// Sequenceํ๋กํ ์ฝ์ ์ค์ํ๋ ๊ฒฝ์ฐ, makeIterator()๋ฅผ ํตํด iterator๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
var nameIterator = names.makeIterator()
// iterator๋ next()๋ฅผ ํตํด ๋ค์ Element๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
while let name = nameIterator.next() {
print(name)
}
// Sequence ํ๋กํ ์ฝ์ ์ฑํํ ๋ฐฐ์ด์ for in loop๋ฅผ ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
for name in names {
print(name)
}/*
// IteratorProtocol์ ์ ์ ํํ, next()๋ฅผ ๊ตฌํํด์ฃผ์ด์ผ ํ๋ค.
protocol IteratorProtocol {
associatedtype Element
mutating func next() -> Element?
}
*/// Sequence ํ๋กํ ์ฝ์ ์ค์ํ๋ Countdown
// makeIterator()๋ฅผ ๊ตฌํํด์ผํ๋ค. IteratorProtocol์ ์ค์ํ๋ CountdownIterator๋ฅผ ๋ฐํํ๊ณ ์๋ค.
struct Countdown: Sequence {
let start: Int
func makeIterator() -> some IteratorProtocol {
return CountdownIterator(self)
}
}
// IteratorProtocol์ next()๋ฅผ ๊ตฌํํด์ฃผ์ด์ผ ํ๋ค.
struct CountdownIterator: IteratorProtocol {
typealias Element = Int
let countdown: Countdown
var currentValue = 0
init(_ countdown: Countdown) {
self.countdown = countdown
self.currentValue = countdown.start
}
mutating func next() -> Element? {
if currentValue > 0 {
let value = currentValue
currentValue -= 1
return value
} else {
return nil
}
}
}
// Countdown์ Element๋ฅผ for in loop๋ก ์ํ (
let countdown = Countdown(start: 10)
for count in countdown {
print(count)
}- ํน์ ์กฐ๊ฑด์ ์ถฉ์กฑํ๋ Element๋ง filteringํ๊ณ ์ถ์ ๋ ์ฌ์ฉ
let names = ["Apple", "Banana", "Car", "Elephant"]
let finalNames = names.filter { name in
// ์ด๋ฆ ๊ธธ์ด๊ฐ 5 ์ด์์ธ ๊ฒ๋ง ํํฐ๋ง ํ ๋
return name.count >= 5
}
print(finalNames)
struct Movie {
let title: String
let genre: String
}
let movies = [Movie(title: "A", genre: "asb"),
Movie(title: "fireMan", genre: "hero"),
Movie(title: "C", genre: "zesb")]
let heroMovies = movies.filter { movie in
// hero genre๋ง filtering
return movie.genre == "hero"
}- ๊ฐ๊ฐ Collection์ Element๋ฅผ ์ ์ฒด ์ํํ๊ฑฐ๋, (offset, element) ํํ๋ก ์ํํ ๋ ์ฌ์ฉ
// MARK: - ForEach
let movies = [Movie(title: "AS", genre: "asb"),
Movie(title: "fireMan", genre: "hero"),
Movie(title: "C", genre: "zesb")]
movies.forEach {
print($0)
}
// MARK: - Enumeration
movies.enumerated().forEach {
print("offset : \($0.offset), element : \($0.element)")
}- ๋ง์ Element Set ์ ์ฒ๋ฆฌํ๋๋ฐ, ์ต์ข ๊ฒฐ๊ณผ๊ฐ์ ๊ทธ ์ค ๊ทน ์์์ Element๊ฐ ๋๋ ๊ฒฝ์ฐ, Lazy Sequence๋ฅผ ํ์ฉํ๋ฉด ๋ถํ์ํ ์ฐ์ฐ์ ์ค์ผ ์ ์๋ค.
// MARK: Lazy Sequence
let indexes = 1..<5000
let images = indexes.lazy.filter { index -> Bool in
print("[Filter]")
// lazy sequence๋ฅผ ์ฌ์ฉํ์ง ์๋ ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ, filter๊ฐ 5000๊ฐ๋ ๊ฐ๋ ์คํ๋๋ค.
// lazy sequence๋ฅผ ์ฌ์ฉํ๋ฉด, ์ฐ์ฐ๋์ด ๋ํญ ์ค์ด๋ ๋ค.
return index % 2 == 0
}.map { index -> String in
print("[Map]")
return "index_\(index)"
}
// lazy itertion + suffix๋ฅผ ํ ๊ฒฐ๊ณผ๋ฌผ์ ์์์ ํ ๋นํ์๋ lazy ๋์์ด ๋จ
let lastThreeImages = images.prefix(3)
// ๊ทผ๋ฐ ์ฐ๋ฆฌ๋ ๋ง์ง๋ง ์ธ๊ฐ ์์๋ง ํ์ํ๋ฐ,,, ๋๋ฌด ๋ถํ์ํ ์์
์ด ๋ง์ ๊ฒ ๊ฐ๋ค.
for image in lastThreeImages {
print(image)
}
// ๋จ์ print๋ฌธ์ suffix๋ฅผ ์ฌ์ฉํ๋๊ฑด lazy ๋์์ด ๋์ง ์์์
print(images.suffix(3))- Collection์ Element๋ฅผ ํน์ ์ฐ์ฐ์ผ๋ก ํ๋๋ก ํฉ์น๊ณ ์ถ์๋ ์ฌ์ฉํ ์ ์๋ค. inout parameter๋ฅผ ์ฌ์ฉํ์ง ์๋ reduce(_:), inout parameter๋ฅผ ์ฌ์ฉํ๋ reduce(into:) ๊ฐ ์๋ค.
// MARK: - reduce
struct Item {
let name: String
let price: Double
}
struct Cart {
private(set) var items: [Item] = []
mutating func addItem(_ item: Item) {
items.append(item)
}
var total: Double {
items.reduce(0) { (value, item) -> Double in
value + item.price
}
}
}
var cart = Cart()
cart.addItem(Item(name: "Milk", price: 4.50))
cart.addItem(Item(name: "Bread", price: 2.50))
cart.addItem(Item(name: "Eggs", price: 12.50))
print(cart.total)
let totalExample = [1, 2, 3, 4, 5].reduce(0, +)
print(totalExample)
let ratings = [4, 0.5, 4.23, 3.64, 7.3, 0.1, 8.6]
// ๊ธฐ๋ณธ reduce๋ก๋ dictionary ๋ฑ์ ์ต์ข
๊ฒฐ๊ณผ๊ฐ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ํด๋ก์ ธ ๋ด๋ถ์ ์ง์ญ๋ณ์๋ฅผ ๋ง๋ค์ด์ ๊ฒฐ๊ณผ๋ฌผ์ ๋์ ์์ผ์ผํ๋ ๋ฒ๊ฑฐ๋ก์์ด ์๋ค.
// ์ด ๊ฒฝ์ฐ์๋ ๋ณต์ฌ๋ณธ์ ๋ง๋ค ํ์๊ฐ ์๋ reduce(into:)๋ฅผ ๋์ ์ฌ์ฉํ ์ ์๋ค.
let results = ratings.reduce(into: [:]) { (results: inout [String: Int], rating: Double) in
switch rating {
case 1..<4: results["very bad", default: 0] += 1
case 5..<7: results["medium", default: 0] += 1
case 7..<9: results["good", default: 0] += 1
default: break
}
}
print(results)- ๋ ๊ฐ์ Collection์ ๊ฐ Element ์์์ ๋ง๊ฒ ์์ ์ด๋ฃจ๋ ํํ ํํ๋ก ๋ฐํํ์ฌ ์ฒ๋ฆฌํ ์ ์๋ค.
// MARK: - Zip
// ๊ฐ๊ฐ์ Collection์ ๋์ผ index์ Element๋ฅผ ์ง์ง์ด ํํํํ๋ก ์ฒ๋ฆฌํ๊ณ ์ถ์๋ zip์ ์ฌ์ฉ ๊ฐ๋ฅ
let students = ["Alex", "Mary", "John", "Steven"]
let grades = [3.4, 2.8, 3.8, 4]
let pairs = zip(students, grades)
for pair in pairs {
print(pair)
}
/*
// == output ==
("Alex", 3.4)
("Mary", 2.8)
("John", 3.8)
("Steven", 4.0)
*/- ํจ์ ๋ด์ ๋๋ค๋ฅธ ํจ์๋ฅผ ์ ์ํ์ฌ ํจ์๋ด์์ ์ฌ์ฉํ ์ ์๋ค. ํจ์ ๋ด์ ์ฝ๋๋ฅผ ํจ์๋ก ๋ถ๋ฆฌํด์ ์ฌ์ฉํ๊ณ ์ถ์๋ ์ฌ์ฉ ๊ฐ๋ฅ
- ํ์ง๋ง, ์ ์์ ์ฌ์ฉํ์ง ์์ผ๋ฉด ์คํ๋ ค ์ฝ๋์ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๊ฒ ๋ ์ ์๋ค.
// MARK: - Nested Functions
func makeApp() {
// ํจ์์์ ํจ์๊ฐ ์ ์๋์ด ์ฌ์ฉ ๊ฐ๋ฅ
func design() {}
func develop() {}
func qa() {}
func distribution() {}
design()
develop()
qa()
distribution()
}
makeApp()- Closure๋ 1๊ธ๊ฐ์ฒด์ด์ ์ต๋ช
ํจ์์
๋๋ค. ํจ์, ์ฝ๋ฒกํจ์ ๋ฑ์ผ๋ก ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
- Closure๋ ํ ๋น๋ฐ์ ์ ์๊ณ , ์ธ์๋ก ์ ๋ฌ๋ ๋๋ฉฐ, ๋ฐํ๋ ๊ฐ๋ฅํฉ๋๋ค.
// ํ๋์ ์ธ์๋ฅผ ๋ฐ์ ๊ทธ ๊ฐ์ ์ถ๋ ฅํ๋ ํจ์์ ์ญํ ์ ํ๋ closure
let hello: (String) -> () = { name in
print("hello, \(name)!")
}
// ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ ๊ณฑ์ ๋ฐํํ๋ ํจ์์ ์ญํ ์ ํ๋ closure
let pow: (Int, Int) -> Int = {
$0 * $1
}
// closure ์ฌ์ฉ ์์
hello("John Doe")
let result = pow(5, 3)
print(result)
/* == output ==
hello, John Doe!
15
*/- Closure ๋ด์์ ์ฌ์ฉ๋๋ ๋ณ์, ์์๊ฐ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํด์ ๋์ง ์๊ณ , ์ธ๋ถ๋ก ์ ๋ฌ์ด ๋๋ ๊ฒฝ์ฐ, escaping closure์์ ๋ช
์ํด์ฃผ์ด์ผ ํ๋ค.
- escaping keyword๋ฅผ ๋ช ์ํ์ง ์์ผ๋ฉด Escaping closure captures non-escaping parameter 'completion' ์ปดํ์ผ ์๋ฌ ๋ฐ์
- escaping closure ๋ฐฉ์ ๋์ , async await ๋ฐฉ์์ผ๋ก ๊ฐ์ ํด์ ์ฌ์ฉํ ์๋ ์๋ค.
// escaping keyword ๋ช
์ ์ํ๋ฉด, Escaping closure captures non-escaping parameter 'completion' compile error ๋ฐ์
// ์ธ๋ถ์์ parameter๋ฅผ ์ ๊ทผํ๋ ๊ฒฝ์ฐ, escaping closure๊ฐ ๋์ด์ผ ํ๋ค.
func getPosts(completion: @escaping ([String]) -> ()) {
var posts: [String] = []
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
posts = ["Hello World", "Introduction to Closures"]
completion(posts)
}
}
getPosts { posts in
// ์ฝ 2์ด ๋ค, ["Hello World", "Introduction to Closures"] ๋ฅผ ๋ฐ๊ฒ ๋จ
print(posts)
}- Teacher, Student ๋ฑ ๋ค์ํ ์ผ์ด์ค๋ก ์ ์๊ฐ ๋์ด์ผ ํ ๋ enum์ case์ ์๋ฅผ ํตํด ํ์
๋ถ๊ธฐ๋ฅผ ํ ๋ switch๋ฌธ์ ํ์ฉํ์ฌ ๊น๋ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
- ๋ค์ํ ์ผ์ด์ค ๊ฐ์ฒด๋ฅผ ํ๋์ ํ์ ์ ๋ด์์ switch ๋ฌธ๊ณผ ์ฌ์ฉํ ๋ default ๋ถ๊ธฐ ์์ด ๋ณด๋ค ๊น๋ํ ์ผ์ด์ค ๋ถ๊ธฐ๋ฅผ ์ ์ํ ์ ์๊ฒ ๋๋ค.
- ๋ํ ํ์ ๋ด์ ๋ค์ํ ๊ฐ์ฒด๋ฅผ ์ฒ๋ฆฌํ ๋ ํ์ ์บ์คํ ์ ํ ํ์๊ฐ ์ค์ด๋ ๋ค.
- ํ์
ํ๋๋ง์ผ๋ก ์ผ์ด์ค๋ฅผ ๋๋์ด ๋ค์ํ ๊ฐ์ฒด๋ฅผ ๋ถ๊ธฐํ์ฌ ๋ค๋ฃฐ ์ ์๋ค. (enum์ ๋คํ์ฑ ํ์ฉ)
- ๊ฐํ์ ์ธ์ด์ธ swift ์ ์ฑ ์ ์ด๊ธ๋๋ Anyํ์ ์ฌ์ฉ์ ์ค์ผ ์ ์๋ค.
- ํ์ ํ๋์ ๋ํ ์ผ์ด์ค๊ฐ ์ถํ ํ์ฅ ๋์ด๋, ์์ฝ๊ฒ ์ผ์ด์ค๋ฅผ ํ์ฅํ์ฌ ์ ์ํ ์ ์๋ค. (enum์ ํ์ฅ์ฑ)
-
๋๋์ด์ง๋ ๊ฐ๊ฐ์ ์ผ์ด์ค๊ฐ ๊ณตํต์ ์ธ ๋ฉค๋ฒ๋ฅผ ๋ค์ ๊ฐ๊ณ ์์๋, class๋ ์๋ธํด๋์ฑ์ ํตํด ๊ณตํต ๋ฉค๋ฒ๋ฅผ ์ ์ํ๊ณ , ์ค๋ณต ์ ์๋ฅผ ์ค์ผ ์ ์๋ค.
-
๋ฐ๋ฉด, enum์ ๊ฐ๊ฐ ์ผ์ด์ค์ ์ค๋ณต ๋ฉค๋ฒ๋ฅผ ํ๋ํ๋ ์ ์ํด์ฃผ์ด์ผ ํ๋ค.
-
๊ณตํต๋ฉค๋ฒ๊ฐ ์ถํ ๋ณ๋๋์ง ์๊ณ ๊ณ ์ ๋จ์ด ๋ณด์ฅ๋๋ค๋ฉด, ์๋ธํด๋์ฑ์ด ๊ฐ๋ฅํ class๊ฐ ๋ ์ข์ ๋ฐฉ๋ฒ์ด ๋ ์๋ ์๋ค.
- ๋ฌผ๋ก , ๊ณตํต ๋ฉค๋ฒ๊ฐ ์ผ์ ํ์ง ์๊ณ , ์ธ์ ๋ ๋ฐ๋ ์ ์๋ค๋ฉด, ๋์ฑ ์ฝ๊ฒ ์ผ์ด์ค ๋ฉค๋ฒ ๋ณํ์ด ๊ฐ๋ฅํ enum์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ข์ ์ ์๋ค.
- ํน์ ํ์ ์ด ์๊ธฐ๊ฑฐ๋, ๊ณตํต๋ฉค๋ฒ๊ฐ ๋ฐ๋๋ ๊ฒฝ์ฐ์ ๋ํ ์์ ์์๊ฐ enum์ ์ฌ์ฉํ ๋ clsas subclassing ๋ฐฉ์์ ๋นํด ์ฉ์ดํ๊ธฐ ๋๋ฌธ์ด๋ค.
import UIKit
enum ImageType: String {
case jpg
case bmp
case png
// jpg, jpeg ๋ชจ๋ jpg ํ์
์ผ๋ก ๋ณด๊ณ ์ถ๋ค๋ฉด? init?(rawValue: String) {} ์์ฑ์๋ฅผ ํ์ฉํด๋ณผ ์ ์๋ค.
init?(rawValue: String) {
// ์์ฑ์์ ๋ค์ด๊ฐ rawValue๊ฐ jpg, jpeg์ผ ๊ฒฝ์ฐ์๋ .jpg ํ์
์ผ๋ก ์ค์ ๋๋๋ก ํ๋ค. ์๋ชป๋ rawValue๊ฐ ๋ค์ด๊ฐ๋ฉด nil์ ๋ฐํํ๋ failable initializer์ด๋ค.
switch rawValue.lowercased() {
case "jpg", "jpeg": self = .jpg
case "bmp": self = .bmp
case "png": self = .png
default: return nil
}
}
}-
๋ฌธ์ ๋ฅผ 5์ด ํ์ ๋๋ ค์ฃผ๋ ํ๋กํผํฐ๋ฅผ ๋ง๋ค๊ณ ํธ์ถํ๋ฉด ๋งค ๋ฌธ์ ๋ฅผ ๋ฐ์ผ๋ ค๋ฉด 5์ด๋ฅผ ๊ธฐ๋ค๋ ค์ผ ํ๋ค. ์ด๋ฏธ ์๋ ๋ฌธ์ ์ธ๋ฐ๋ 5์ด๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ด ๋ถํ์ํ ๋ lazy ๋ฅผ ๋ถ์ด๊ณ ๊ฐ์ฅ ๋ค์ () ๋ฅผ ๋ถ์ฌ์ lazy ํ๋กํผํฐ๋ฅผ ๋ง๋ค ์ ์๋ค. ์ด๋ ๊ฒ ๋๋ฉด ๋๋ฒ์งธ ๋ฌธ์ ๋ฅผ ๋ฐ์ ๋ 5์ด ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ฐ๋ก ๋ฐ์ ์ ์๋ค.
-
lazy ํ๋กํผํฐ๋ ์ ๊ทผํ๋ ์์ ์ ์ด๊ธฐํ๋๋ ํน์ฑ์ด ์๋ค.
-
์ฐ์ฐ ํ๋กํผํฐ๋ผ๊ณ ๋ ๋ถ๋ฆฌ์ด๋ค.
-
์์ ์๊ฐ ํ๋กํผํฐ์ ๋๋ ์๊ฐ ํ๋กํผํฐ๋ฅผ ๋ฐ๋ก ๋ถ๋ฌ์์ ๋นผ์ค์ ๊ฑธ๋ฆฐ ์๊ฐ์ ๊ณ์ฐํ ์ ์๋ค.
-
์๋์ ๊ฐ์ด ์ฐ์ฐ ํ๋กํผํฐ๋ฅผ ์ ์ธํ์ฌ ์์ ์๊ฐ๊ณผ ๋๋ ์๊ฐ์ ์ฐจ์ด๋ฅผ ๋ฐ๋ก ๊ฐ์ ธ์ฌ ์ ์๋ค.
struct Workout {
let startTime: Date
let endTime: Date
var timeElapsed: TimeInterval {
endTime.timeIntervalSince(startTime)
}
}-
didSet ๊ณผ willSet ์ ์ฌ์ฉํด ํ๋กํผํฐ๊ฐ ๋ณ๊ฒฝ๋๋ ๊ฒ์ ํ์งํ์ฌ ์ด๋ค ๋์์ ์ํํ ์ ์๋ค.
-
์ด๊ธฐํ ์์๋ didSet ์ด ํธ์ถ๋์ง ์๋๋ฐ ๊ทธ ๋๋ defer ๋ฅผ ์ฌ์ฉํด ์ฐํ์ ์ผ๋ก didSet์ ํธ์ถํ ์ ์๋ค.
-
์๋ ์ฝ๋์์๋ ์ด๊ธฐํ๋ถํฐ url์ด ๋ฐ๋ ๋๋ง๋ค ์ธ์ฝ๋ฉ์ ํด์ค์ url ํ๋กํผํฐ๊ฐ ํญ์ url ์ธ์ฝ๋ฉ๋ ๊ฒ์ ๋ณด์ฅํ๋ค.
struct Website {
init(url: String) {
defer { self.url = url }
self.url = url
}
var url: String {
didSet {
url = url.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? url
}
}
// MARK: 45. Performing Asynchronous Action from Synchronous Code
// task๋ฅผ ์ฌ์ฉํ๋ฉด ๋ธ๋ญ ๋ด์์ await ์์ฝ์ด๋ฅผ ์ฌ์ฉํ ๋น๋๊ธฐ ๋์์ ์ํํ์ฌ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆด ์ ์๋ค.
Button {
// iOS 13+
Task {
// .. do something
}
// iOS 15+
task {
// refresh the news
await newsSourceListViewModel.getSources()
}
} label: {
Text("Test Button")
}Protocol์ associatedtype๊ณผ generic type ์ฌ์ฉ๋ฐฉ๋ฒ, where ์ ์ ํ์ฉํ ํ์ ์ ์ฝ์ค์ ํ๊ธฐ
import Foundation
// MARK: ์ฐ๊ดํ์
(associatedtype), ์ ๋ค๋ฆญ(generic), where ์ associatedtype ์ ์ฝ ํ์ฉํ๊ธฐ
// Parser protocol์ Input, Output ๋๊ฐ์ ์ฐ๊ดํ์
(associatedtype)์ ๊ฐ์ต๋๋ค.
// Parser๋ฅผ ์ฑํํ๋ ๊ณณ์์ ์
๋ง์ ๋ฐ๋ผ Input, Output ํ์
์ typealias๋ก ์ง์ ํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
protocol Parser {
associatedtype Input
associatedtype Output
func parse(input: Input) -> Output
}
class NewParser: Parser {
// NewParser ํด๋์ค์์์ Input ํ์
์ String, Output ํ์
์ [String: String]์ผ๋ก ๊ฐ์ฃผ๊ฐ ๋ฉ๋๋ค.
typealias Input = String
typealias Output = [String: String]
func parse(input: Input) -> Output {
return [input: input]
}
}
// ์ ๋ค๋ฆญ ํ์
์ ์ฌ์ฉํด์ Parser protocol์ ์ฐ๊ดํ์
์ ๋ํ ์ ์ฝ์ ์ค ์ ์์ต๋๋ค.
// ๊ฐ๋ น ์๋ ๋ฉ์๋์ ๊ฒฝ์ฐ, parser๋ Parser protocol์ ์ค์ํด์ผ ํ๋ฉฐ, inputs์ elements๋ NewParser์ Inputํ์
์ธ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
func runParse<P: Parser>(parser: P, inputs: [P.Input]) where P.Input == NewParser.Input {
inputs.forEach {
let result = parser.parse(input: $0)
print(result)
}
}
func test() {
let newParser = NewParser()
runParse(parser: newParser, inputs: ["input", "input2"])
}
test()
// - Output
/*
["input": "input"]
["input2": "input2"]
*/import Foundation
// MARK: Protocol Composition (ํ๋กํ ์ฝ ๊ตฌ์ฑ)
struct Lecture {
let title: String
let time: Int
}
// Student, VerifiedStudent protocol์ ๊ฐ๊ธฐ ๋ค๋ฅธ ๋ฉค๋ฒ, ๋ฉ์๋๊ฐ ์ ์๋์ด ์์ต๋๋ค.
protocol Student {
var lectures: [Lecture] { get set }
mutating func enroll(_ lecture: Lecture)
}
protocol VerifiedStudent {
func verify() -> Bool
}
// ์๋ extension ๊ธฐ๋ฅ์ VerifiedStudent, Student ๋ ๋ค ์ค์ํ๋ ๊ฒฝ์ฐ์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
// protocol composition
extension VerifiedStudent where Self : Student {
/// protocol์ mutating func์ผ๋ก ์ง์ ๋์ด ์์ด๋, extension๋ถ์์ ์ผ๋ฐ func์ผ๋ก ์ ์ํ์ฌ ์ฌ์ฉํ ์ ์๋ค.
func enroll(_ lecture: Lecture) {
if verify() {
print("Verified and Enrolled")
}
}
func verify() -> Bool {
return true
}
}
// VerifiedStudent, Student ํ๋กํ ์ฝ์ ๋์์ ์ค์ํ๋ InternationalStudent๋ ์์ ๊ตฌํํ extension ๊ธฐ๋ฅ์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
// protocol์์ ์ง์ ํ ๋ฉค๋ฒ, ๋ฉ์๋๋ฅผ ๋ณ๋๋ก ๊ตฌํํ์ง ์์ผ๋ฉด extension์์ ๊ตฌํํ default ๊ธฐ๋ฅ์ด ์ ์ฉ๋๋ค.
// Student, VerifiedStudent๋ฅผ ์ค์ํ๋ ์๋ ๊ตฌ์กฐ์ฒด๋ ๋ณ๋ ๊ตฌํํ์ง ์์ enroll, verify ๋ฉ์๋๊ฐ extension์์ ์ ์ํ default ๊ตฌํ์ผ๋ก ์ ์ฉ๋๋ค.
struct InternationalStudent: Student, VerifiedStudent {
var lectures: [Lecture] = []
}
let student = InternationalStudent()
print(student.verify())
student.enroll(Lecture(title: "myLecture", time: 3))
// - Output
/*
true
Verified and Enrolled
*/์ ๋ค๋ฆญํ์ ์ ์ฌ์ฉํ ๊ฐ์ฒด vs ์ ๋ค๋ฆญํ์ ์ ์ ๊ฑฐ ํ, ํํ ํ ์ฝ ํ์ ๋ง ์ ์ฉํ ๊ฐ์ฒด์ ์ฐจ์ด
// AirlineTicket ํ๋กํ ์ฝ์ ์ค์ํ๋ ์ ๋ค๋ฆญ ํ์
์ ๊ฐ๋ ํด๋์ค
class CheckoutServiceWithGeneric<Ticket: AirlineTicket> {
var tickets: [Ticket]
init(tickets: [Ticket]) {
self.tickets = tickets
}
// AirlineTicket์ ์ค์ํ๋ ์ฌ๋ฌ๊ฐ์ ํ์
์ addTicket์์ ์ทจ๊ธํ ์ ์๋ค..
// AirlineTicket์ ์ฑํํ EconomyTicket์ ๊ธฐ์ค์ผ๋ก ์ด๊ธฐํ๊ฐ ๋์์ผ๋ฉด, EconomyTicketํ์
๋ง ์ทจ๊ธ ๊ฐ๋ฅ...
func addTicket(_ ticket: Ticket) {
self.tickets.append(ticket)
}
}
// -> ํ์ค ์ธ๊ณ์์ economy, business, first ticket ๋ชจ๋ ์ทจ๊ธ์ ํ ์ ์์ด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ง๋ง, ์ ๊ฐ์ฒด๋ ๊ทธ๊ฒ ์๋จ ๐ข// ์ ๋ค๋ฆญ ํ์
์ ์ ๊ฑฐํ๊ณ , ๋์ protocol ํ์
์ ์ ์ฉํ๋ค.
class CheckoutServiceWithoutGeneric {
var tickets: [AirlineTicket]
init(tickets: [AirlineTicket]) {
self.tickets = tickets
}
// AirlineTicket์ ์ค์ํ๋ ์ฌ๋ฌ๊ฐ์ ํ์
์ addTicket์์ ์ทจ๊ธํ ์ ์๊ฒ ๋์๋ค.
func addTicket(_ ticket: AirlineTicket) {
self.tickets.append(ticket)
}
// AirlineTicket์ ์ฑํํ ๋ค์ํ ํ์
์ ์ทจ๊ธ ๊ฐ๋ฅ
func processTickets() {
tickets.forEach { print($0) }
}
}