Skip to content

iOS-Udemy-Study-Group/Swift-for-Intermediate-iOS-Developers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

25 Commits
ย 
ย 

Repository files navigation

Swift-for-Intermediate-iOS-Developers


์Šคํ„ฐ๋”” ๋ชฉ์ฐจ

์Šคํ„ฐ๋”” ๋ฐฉ์‹

  • Udemy ๊ฐ•์˜๋ฅผ ๊ตฌ๋งค ํ›„ ๊ฐœ๋ณ„ ์ธ์ฆ์„ ํ•ด์•ผ ์Šคํ„ฐ๋”” ์ฐธ์—ฌ ๊ฐ€๋Šฅ
  • ๊ฐ์ž ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ๊ณต์šฉ study git repository์— ๊ณต์œ ํ•˜๊ณ  ํ† ์˜ํ•˜๋ฉด์„œ ๋‚ด์šฉ ๋ณด์™„
    • ๊ฐœ์ธ์ ์œผ๋กœ ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ๊ฐœ์ธํด๋”์— ๊ธฐ๋ก (fork ํ›„, ๊ฐœ์ธ ์Šคํ„ฐ๋”” ๋‚ด์šฉ ๊ธฐ๋ก ํ–ˆ๋‹ค๊ฐ€ ๊ณต์šฉ repository์— PR)
      • ๊ฐ์ž ์˜๋ฌด๊ฐ์„ ๊ฐ–๊ณ  ์Šคํ„ฐ๋””ํ•˜๊ธฐ ์œ„ํ•จ
    • ๋งค์ฃผ ๋‹ค์ˆ˜๊ฒฐ๋กœ ์Šคํ„ฐ๋”” ๋‚ ์งœ ์ง€์ • ํ›„, 2์‹œ๊ฐ„์”ฉ ์Šคํ„ฐ๋”” ์ง„ํ–‰
  • ์Šคํ„ฐ๋”” ๊ธฐ๋ก ์ •๋ฆฌ ๋ฐฉ์‹์— ๋Œ€ํ•œ ์ข‹์€ ์˜๊ฒฌ ์ž์œ ๋กญ๊ฒŒ ๊ณต์œ 
  • ์Šคํ„ฐ๋”” ์ค‘์— ์ž์œ ๋กญ๊ฒŒ ์ดํ•ดํ•œ ๋‚ด์šฉ์„ ์–˜๊ธฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์€ ๋‚ด์šฉ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“ ์ง€ ๊ณต์œ 

1์ฃผ์ฐจ ์Šคํ„ฐ๋””

  • 1/28(ํ† ), ์˜คํ›„ 2์‹œ ~ 4์‹œ (์™„๋ฃŒ)
  • Section 2: Swift Collections ~ Section 3: Functions
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป applebuddy | AppleCEO | Jae-eun

2์ฃผ์ฐจ ์Šคํ„ฐ๋””

  • 2/4(ํ† ), ์˜คํ›„ 9์‹œ ~ 11์‹œ (์™„๋ฃŒ)
  • Section 4: Enumerations ~ Section 5: Properties, Lazy Stored Properties
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป applebuddy | AppleCEO | Jae-eun | Lim-YongKwan

3์ฃผ์ฐจ ์Šคํ„ฐ๋””

  • 2/12(์ผ), ์˜ค์ „ 10์‹œ ~ 12์‹œ (์™„๋ฃŒ)
  • Section 5: Computed Properties ~ Section 5: Error Handling, Example 1, Throwing Errors
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป applebuddy | AppleCEO | Jae-eun | Lim-YongKwan

4์ฃผ์ฐจ ์Šคํ„ฐ๋””

  • 2/19(์ผ), ์˜ค์ „ 10์‹œ ~ 12์‹œ
  • Section 5: Error Handling, Example 2, Throwing Errors ~ Section 9: Async and Await
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป applebuddy | AppleCEO | Jae-eun | Lim-YongKwan

5์ฃผ์ฐจ ์Šคํ„ฐ๋””

  • 3/5(์ผ), ์˜ค์ „ 9์‹œ ~ 11์‹œ
  • Section 9: Async and Await ~ Section 12: Handling Error for Async Architecture, Using Result Type
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป applebuddy | AppleCEO | Jae-eun

6์ฃผ์ฐจ ์Šคํ„ฐ๋””

  • 3/11(ํ† ), ์˜ค์ „ 10์‹œ ~ 12์‹œ
  • Section 12: Using Result Type ~ finished
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป applebuddy | AppleCEO | Lim-YongKwan

Section 2: Swift Collections

Sequence Protocol

  • 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 Protocol์„ ์ฑ„ํƒํ•œ struct ์‚ฌ์šฉ ์˜ˆ์‹œ

// 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)
}

Filter

  • ํŠน์ • ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜๋Š” 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"
}

ForEach, Enumeration

  • ๊ฐ๊ฐ 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)")
}

Lazy Sequence

  • ๋งŽ์€ 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))

Reduce

  • 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)

Zip

  • ๋‘ ๊ฐœ์˜ 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)
*/

Section 3: Functions

Nested function, ์ค‘์ฒฉ ํ•จ์ˆ˜

  • ํ•จ์ˆ˜ ๋‚ด์— ๋˜๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜์—ฌ ํ•จ์ˆ˜๋‚ด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•จ์ˆ˜ ๋‚ด์˜ ์ฝ”๋“œ๋ฅผ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„๋•Œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • ํ•˜์ง€๋งŒ, ์ ์‹œ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์˜คํžˆ๋ ค ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ฒŒ ๋  ์ˆ˜ ์žˆ๋‹ค.
// MARK: - Nested Functions

func makeApp() {
  // ํ•จ์ˆ˜์•ˆ์— ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์–ด ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  func design() {}
  func develop() {}
  func qa() {}
  func distribution() {}
  
  design()
  develop()
  qa()
  distribution()
}

makeApp()

Closure

  • 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)
}

Section 4: Enumerations

๊ฐ์ฒด๋ฅผ Struct ๋Œ€์‹  Enum์œผ๋กœ ์„ ์–ธํ•˜๋ฉด ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ 

  • Teacher, Student ๋“ฑ ๋‹ค์–‘ํ•œ ์ผ€์ด์Šค๋กœ ์ •์˜๊ฐ€ ๋˜์–ด์•ผ ํ• ๋•Œ enum์€ case์ •์˜๋ฅผ ํ†ตํ•ด ํƒ€์ž… ๋ถ„๊ธฐ๋ฅผ ํ• ๋•Œ switch๋ฌธ์„ ํ™œ์šฉํ•˜์—ฌ ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋‹ค์–‘ํ•œ ์ผ€์ด์Šค ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜์˜ ํƒ€์ž…์— ๋‹ด์•„์„œ switch ๋ฌธ๊ณผ ์‚ฌ์šฉํ• ๋•Œ default ๋ถ„๊ธฐ ์—†์ด ๋ณด๋‹ค ๊น”๋”ํ•œ ์ผ€์ด์Šค ๋ถ„๊ธฐ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
    • ๋˜ํ•œ ํƒ€์ž… ๋‚ด์˜ ๋‹ค์–‘ํ•œ ๊ฐ์ฒด๋ฅผ ์ฒ˜๋ฆฌํ• ๋•Œ ํƒ€์ž…์บ์ŠคํŒ…์„ ํ•  ํ•„์š”๊ฐ€ ์ค„์–ด๋“ ๋‹ค.
  • ํƒ€์ž… ํ•˜๋‚˜๋งŒ์œผ๋กœ ์ผ€์ด์Šค๋ฅผ ๋‚˜๋ˆ„์–ด ๋‹ค์–‘ํ•œ ๊ฐ์ฒด๋ฅผ ๋ถ„๊ธฐํ•˜์—ฌ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค. (enum์˜ ๋‹คํ˜•์„ฑ ํ™œ์šฉ)
    • ๊ฐ•ํƒ€์ž… ์–ธ์–ด์ธ swift ์ •์ฑ…์— ์–ด๊ธ‹๋‚˜๋Š” Anyํƒ€์ž… ์‚ฌ์šฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ํƒ€์ž… ํ•˜๋‚˜์— ๋Œ€ํ•œ ์ผ€์ด์Šค๊ฐ€ ์ถ”ํ›„ ํ™•์žฅ ๋˜์–ด๋„, ์†์‰ฝ๊ฒŒ ์ผ€์ด์Šค๋ฅผ ํ™•์žฅํ•˜์—ฌ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. (enum์˜ ํ™•์žฅ์„ฑ)

โš  enum์ด ํ•ญ์ƒ ์žฅ์ ๋งŒ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

  • ๋‚˜๋ˆ„์–ด์ง€๋Š” ๊ฐ๊ฐ์˜ ์ผ€์ด์Šค๊ฐ€ ๊ณตํ†ต์ ์ธ ๋ฉค๋ฒ„๋ฅผ ๋‹ค์ˆ˜ ๊ฐ–๊ณ  ์žˆ์„๋•Œ, class๋Š” ์„œ๋ธŒํด๋ž˜์‹ฑ์„ ํ†ตํ•ด ๊ณตํ†ต ๋ฉค๋ฒ„๋ฅผ ์ •์˜ํ•˜๊ณ , ์ค‘๋ณต ์ •์˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

  • ๋ฐ˜๋ฉด, enum์€ ๊ฐ๊ฐ ์ผ€์ด์Šค์˜ ์ค‘๋ณต ๋ฉค๋ฒ„๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ •์˜ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

  • ๊ณตํ†ต๋ฉค๋ฒ„๊ฐ€ ์ถ”ํ›„ ๋ณ€๋™๋˜์ง€ ์•Š๊ณ  ๊ณ ์ •๋จ์ด ๋ณด์žฅ๋œ๋‹ค๋ฉด, ์„œ๋ธŒํด๋ž˜์‹ฑ์ด ๊ฐ€๋Šฅํ•œ class๊ฐ€ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

    • ๋ฌผ๋ก , ๊ณตํ†ต ๋ฉค๋ฒ„๊ฐ€ ์ผ์ •ํ•˜์ง€ ์•Š๊ณ , ์–ธ์ œ๋“  ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๋”์šฑ ์‰ฝ๊ฒŒ ์ผ€์ด์Šค ๋ฉค๋ฒ„ ๋ณ€ํ˜•์ด ๊ฐ€๋Šฅํ•œ enum์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์„ ์ˆ˜ ์žˆ๋‹ค.
    • ํŠน์ • ํƒ€์ž…์ด ์ƒ๊ธฐ๊ฑฐ๋‚˜, ๊ณตํ†ต๋ฉค๋ฒ„๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ˆ˜์ • ์†Œ์š”๊ฐ€ enum์„ ์‚ฌ์šฉํ• ๋•Œ clsas subclassing ๋ฐฉ์‹์— ๋น„ํ•ด ์šฉ์ดํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

enum + failable initializer๋ฅผ ํ™œ์šฉํ•˜์—ฌ rawValue์— ๋”ฐ๋ฅธ ์„ธ๋ถ€ ํƒ€์ž… ์„ค์ • ์ •์˜ํ•˜๊ธฐ

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
    }
  }
}

Section 5: Properties

Lazy stored properties

  • ๋ฌธ์ œ๋ฅผ 5์ดˆ ํ›„์— ๋Œ๋ ค์ฃผ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“ค๊ณ  ํ˜ธ์ถœํ•˜๋ฉด ๋งค ๋ฌธ์ œ๋ฅผ ๋ฐ›์œผ๋ ค๋ฉด 5์ดˆ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค. ์ด๋ฏธ ์žˆ๋Š” ๋ฌธ์ œ์ธ๋ฐ๋„ 5์ดˆ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด ๋ถˆํ•„์š”ํ•  ๋•Œ lazy ๋ฅผ ๋ถ™์ด๊ณ  ๊ฐ€์žฅ ๋’ค์— () ๋ฅผ ๋ถ™์—ฌ์„œ lazy ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ๋‘๋ฒˆ์งธ ๋ฌธ์ œ๋ฅผ ๋ฐ›์„ ๋•Œ 5์ดˆ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

  • lazy ํ”„๋กœํผํ‹ฐ๋Š” ์ ‘๊ทผํ•˜๋Š” ์‹œ์ ์— ์ดˆ๊ธฐํ™”๋˜๋Š” ํŠน์„ฑ์ด ์žˆ๋‹ค.

computed properties

  • ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋ผ๊ณ ๋„ ๋ถˆ๋ฆฌ์šด๋‹ค.

  • ์‹œ์ž‘ ์‹œ๊ฐ„ ํ”„๋กœํผํ‹ฐ์™€ ๋๋‚œ ์‹œ๊ฐ„ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋”ฐ๋กœ ๋ถˆ๋Ÿฌ์™€์„œ ๋นผ์ค˜์„œ ๊ฑธ๋ฆฐ ์‹œ๊ฐ„์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์•„๋ž˜์™€ ๊ฐ™์ด ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•˜์—ฌ ์‹œ์ž‘ ์‹œ๊ฐ„๊ณผ ๋๋‚œ ์‹œ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

struct Workout {
  let startTime: Date
  let endTime: Date

  var timeElapsed: TimeInterval {
    endTime.timeIntervalSince(startTime)
  }
}

propertyObservers

  • 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
    }
}

Section 9: Async and Await

๋™๊ธฐ ์ฝ”๋“œ์—์„œ await ํ‚ค์›Œ๋“œ์™€ ํ•จ๊ป˜ ๋น„๋™๊ธฐ ๋™์ž‘ ์‹คํ–‰ํ•˜๊ธฐ

// 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")
}

Section 10: Protocol Oriented Design

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"]
*/

Protocol Composition, ํ”„๋กœํ† ์ฝœ ๊ตฌ์„ฑ

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) }
  }
}

About

Udemy Study with lecture, Swift for Intermediate iOS Developers

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors