GithubHelp home page GithubHelp logo

learnmoreswiftinudemy's Introduction

Hi, I'm Yang seunghyun

KakaoTalk_Photo_2023-07-08-05-20-34

Typing SVG

Me_

struct AboutMe {
  typealias Keywords = [String]
  let me๐Ÿ˜† = ["senior in university", "ENTP", "study swift for developing iOS app"]
  
  func myMind๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป() -> Keywords {
    return ["Clean code", "Share my thoughts", "Technology that can make anything I imagine"]
  }
  func like๐Ÿซ () -> Keywords {
    return ["Plan", "Develop", "iPhone"]
  }
}

Todo List_

extension AboutMe {
  func toDo๐Ÿ“š() -> Keywords {
    return [
      "UIKit", "Swinject", "FireBase",
      "Algorithm", "ComputerScience",
      "LLDB", "GoF design pattern",
      "SwiftUI",
    ]
  }
}

knowledge_

extension AboutMe {
  func know๐Ÿ”ฅ() -> Keywords {
    return [
      "Asynchronous. GCD, async/await, actor, Thread, Combine etc...",
      "Caching. disk cache, filemanager, NSCache etc...",
      "Networking. RESTFul, TCP/UDP Socket, Alamofire, URLSession", "URLSession protocols etc...",
      "Animation", "CoreAnimation", "UIKit", "Combine", "Unit Test", "AutoLayout", DIP+DI, "Protocol any, some, coposition..?"
      "Core data", "Firebase", "ImageIO",
      "MVC, MVVM, VIPER, Coordinator, MVVM+Clean Architecture etc...",
      "Computer science. OS, Algorithm, Data structure, Network etc...",
      "OOP", "POP", "SOLID etc...."
      "Kodeco code convention", "swift style guilde"
    ]
  }
}
extension AboutMe {
  func booksToStudy๐Ÿ“–() -> Keywords {
    return [
      "์˜ค๋ธŒ์ ํŠธ-์œ„ํ‚ค๋ถ์Šค",
      "์ผ„ํŠธ ๋ฒก์˜ ๊ตฌํ˜„ ํŒจํ„ด-์—์ด์ฝ˜์ถœํŒ์‚ฌ",
      "CleanArchitecture"
    ]
  }
}

Baekjoon Tier_

Solved.ac Profile

Tech_

๐Ÿš€ ย Strong Tools I Have Used and Learned

C SWIFT GHTHUB

๐Ÿš€ ย Knowledgable Tools I Have Used and Learned

C++ HTML CSS JAVA

My info_

Tistory

shcommit

footer

learnmoreswiftinudemy's People

Contributors

shcommit avatar

Watchers

 avatar

learnmoreswiftinudemy's Issues

[Clone/Instagram] Profile Scene ๊ธฐ๋Šฅ ๊ฐœ์„ , MVVMํŒจํ„ด ์ ์šฉ | ์ƒ‰๋‹ค๋ฅธ ์‹œ๋„ & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋… & ๊ฐœ์„ ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ #8

Profile Scene ๊ธฐ๋Šฅ ๊ฐœ์„ , MVVMํŒจํ„ด ์ ์šฉ

๊ตฌํ˜„ ์˜์ƒ

๊ฐ•์˜์™€ ๋‹ค๋ฅธ ์ƒ‰๋‹ค๋ฅธ ์‹œ๋„

Navigation.title in ProfileVC

  • ๊ฐ•์˜์—์„œ๋Š” ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๊ณผ์ •์ด ์•ˆ๋‚˜์™”๋‹ค. ๊ทธ๋ž˜์„œ ์—ฌ์ „ํžˆ ์ œ์ž๋ฆฌ ๊ฑธ์Œ์ด์—ˆ๋‹ค. ์ด์ „ ๊ตฌํ˜„๊ณผ ๊ฐ™์ด ์—ฌ์ „ํžˆ ProfileVC๋กœ ์ด์ „ํ–ˆ์„ ๋•Œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์ž‘์—…์ด ๋„ˆ๋ฌด๋งŽ์•„ navigation.title ๋„ ์—…๋ฐ์ดํŠธ ๋˜์ง€ ์•Š์•˜๋‹ค. ์—ฌ๊ธฐ์„œ ๊ถ๊ธˆํ–ˆ๋˜ ๊ฒƒ์ด ์ปค์Šคํ…€ ๋ทฐ๋ฅผ navigation.titleView๋กœ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์— Scene๊ฐ€ ์ง„ํ–‰์ค‘์— ์‰ฝ๊ฒŒ ๊ฐ’์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋Š”๋ฐ ๊ธฐ๋ณธ์ ์ธ navigation.title์˜ reloadํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„ ๋ดค์ง€๋งŒ ์•Œ ์ˆ˜ ์—†์—ˆ๋‹ค. ๋ฌผ๋ก  ๋‹ต์€ ์•Œ๊ณ  ์žˆ์—ˆ๋‹ค. profileVC๊ฐ€ ๋กœ๋”ฉ๋˜๊ธฐ ์ด์ „์— ๋ฏธ๋ฆฌ ๊ฐ’์„ ์ฃผ๋ฉด ๋˜๋Š”๋ฐ ์ด๊ฒŒ ์‹ซ์—ˆ์ง€๋งŒ ๋ฐฉ๋ฒ•์„ ๋ชฐ๋ผ์„œ ๊ฒฐ๊ตญ ์•ฑ์˜ ์ดˆ๊ธฐ ์ง„์ž… ํ™”๋ฉด์˜ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ profileVC์˜ title์— ๋“ค์–ด๊ฐˆ ๊ฐ’์„ ๋ฏธ๋ฆฌ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ๋ฐ›์•„์™”๋‹ค.

tabBar๋กœ profileVC ์ดˆ๊ธฐ ํด๋ฆญ์‹œ FireStore, Storage์—์„œ ๋‹ค์šด๋ฐ›์€ ์‚ฌ์ง„, ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ 2~3์ดˆ ๋’ค์— ๋‚˜ํƒ€๋‚˜๋Š” ์˜ค๋ฅ˜(๋งํฌ ๋‚ด์šฉ ์ค‘ ๊ฐœ์„ ํ•ด์•ผํ•  ๊ธฐ๋Šฅ์˜ gif์— ํ•ด๋‹น)

  • profileVC์˜ profileHeader์—์„œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„, ํ”„๋กœํ•„ ์‚ฌ์ง„์ด ํ•„์š”ํ•œ๋ฐ ์ด๋Š” Firebase์˜ Storage, Firestore์— ์ €์žฅ๋˜์žˆ์—ˆ๋‹ค. ์ด๋ฅผ ํŒŒ์‹ฑํ•˜๋ ค๋ฉด ํŒŒ์ด์–ด๋ฒ ์ด์Šค ๊ด€๋ จ ํ•จ์ˆ˜๋ฅผ ๊ผญ ์จ์•ผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ ์ง„์งœ ๋Š๋ฆฌ๋‹ค.. ํ”„๋กœํ•„ ์‚ฌ์ง„ ๋ฐ์ดํ„ฐ๊ฐ€ ์ •๋ง ์ž‘์„ ํ…๋ฐ ์ฑ„๊ฐ์ƒ 23์ดˆ ๊ฑธ๋ฆฌ๋‹ค๋‹ˆ ใ… ใ… ,,, ์„ฑ๊ณต์ ์œผ๋กœ profieVC๋Š” ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ๋Š๋ฆฐ ํŒŒ์ด์–ด๋ฒ ์ด์Šค ๋•์— ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๋ฏผ์„ ๋งŽ์ด ํ–ˆ๋‹ค. ์–ด๋–ค ๋ฐฉ๋ฒ•์„ ์“ฐ๊ณ  ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ, QoS ์ฒ˜๋ฆฌ??(๋” ์ž์„ธํžˆ ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค.)๋“ฑ์„ ํ•ด๋„ ๋Š๋ฆฌ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ์•˜๋‹ค.
    ๊ทธ๋ž˜์„œ ์ƒ๊ฐํ•œ ๊ฒƒ์ด ๊ทธ๋ƒฅ ์ดˆ๊ธฐ ๋ฉ”์ธ ํ™ˆ๋ทฐ๋กœ ์ง„์ž…ํ•  ๋•Œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋กœ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ํ”„๋กœํ•„ ์‚ฌ์ง„๊ณผ ์‚ฌ์šฉ์ž์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„๋™๊ธฐ๋กœ ๋ฐ›์•„ ๋ฒ„๋ ธ๋‹ค. ์ดˆ๊ธฐ์— ๋ฉ”์ธ ํ™ˆ ๋ทฐ๋กœ ์ง„์ž…ํ•˜๋Š”๊ฒŒ 1
    2์ดˆ ๋”œ๋ ˆ์ด๊ฐ€ ์žˆ์ง€๋งŒ ํฐ์ƒ‰ ๋ฐฐ๊ฒฝ์ด์—ˆ๋‹ค๊ฐ€ ํ™”๋ฉด์ด ๋ณด์—ฌ์ ธ์„œ ์ž์—ฐ์Šค๋Ÿฌ์› ๊ณ  profileVC๋กœ ์ด๋™์‹œ์—๋„ ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ๋œ ์‚ฌ์ง„๊ณผ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฉ”์ธ ํ™ˆ ํƒญ์ปจํŠธ๋กค๋Ÿฌ๋กœ๋ถ€ํ„ฐ nil์ด ์•„๋‹Œ ๋ฐ”์ธ๋”ฉ(didSet)๋œ ์‹ค์ œ ๊ฐ’์„ ํ†ตํ•ด ์ •๋ณด๋ฅผ ํ™”๋ฉด์— ๋ณด์—ฌ์คŒ์œผ๋กœ ์ด์ „๋ณด๋‹ค ์ •๋ง ๋นจ๋ผ๋ณด์˜€๋‹ค,, ํ˜ธํ˜ธํ˜ธ

MVVMํŒจํ„ด ์ ์šฉ

  • ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด ๊ณ ๋ฏผ์„ ๋„ˆ๋ฌดํ•ด์„œ MVVMํŒจํ„ด์„ ์žŠ๊ณ  ์žˆ์—ˆ์ง€๋งŒ HomeVC, ProfileVC๋“ฑ์— ViewModel์„ ํ†ตํ•ด View๋“ค์„ ์ˆ˜์ •ํ•˜๋„๋ก ์ ์šฉํ–ˆ๋‹ค. ์ด๋•Œ HomeVC, ProfileVC์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋„๋ก ViewModel์„ ์„ ์–ธํ–ˆ๋‹ค. ๋‘˜ ์ค‘ ํ•˜๋‚˜๋Š” image ํ”„๋กœํผํ‹ฐ๋ฅผ ์•ˆ์“ฐ๋Š”๋ฐ ๊ทธ๋ƒฅ nil์ฒ˜๋ฆฌํ•˜๋ฉด ๋ฌ๋‹ค.

  • ์™„๋ฒฝํ•˜์ง„ ์•Š๋‹ค. ์•„์ง Controller์˜ ์˜์กด์„ฑ์„ ๊ฐ–๊ณ  ์žˆ๋‹ค.. ์˜ต์ €๋ฒ„๋“ฑ ๊ณต๋ถ€ํ•ด์„œ ์™„๋ฒฝํ•˜๊ฒŒ VM๊ณผ View์˜ ๋™์ž‘์„ ๋งŒ๋“ค์–ด๋ณด๊ณ  ์‹ถ๋‹ค.

์ƒˆ๋กœ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…

  • Firestore.firestore() ์ˆ˜์‹์–ด๊ฐ€ ๊ธธ์–ด์„œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ fetch ํ•  ๋•Œ ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ๋กœ ์ฐธ์กฐํ•ด์„œ ์‚ฌ์šฉํ–ˆ์—ˆ๋‹ค. ์ด์™€ ๋‹ฌ๋ฆฌ Firestore.firestore(), Auth.auth(), Storage.storage() ๋“ฑ์„ ์ „์—ญ๋ณ€์ˆ˜์˜ constant ๋ณ€์ˆ˜๋กœ ํ•˜๋Š” ํŒŒ์ผ์„ ์ƒˆ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค๋Š”๊ฒŒ ์‹ ์„ ํ–ˆ๋‹ค. ์›๋ž˜ C++์—์„œ๋Š” ์ž์ฃผ ์‚ฌ์šฉํ•˜๊ณ  ์„ ์–ธ ํ–ˆ์—ˆ์ง€๋งŒ swift์—์„œ๋Š” ์ „์—ญ constant๋ณ€์ˆ˜๋ฅผ ๋งŽ์ด ์„ ์–ธํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ ์ด ๊ธฐํšŒ๋ฅผ ํ† ๋Œ€๋กœ ๋งŽ์ด ์‚ฌ์šฉํ•ด์•ผ ๊ฒ ๋‹ค. ๋ฐ”๋กœ ๋ฆฌํŽ™ํ„ฐ๋ง ํ–ˆ๋‹ค.

ํƒญ๋ฐ” ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํŠน์ • VC ์ธ์Šคํ„ด์Šค ์–ป๋Š” ๋ฐฉ๋ฒ•

tabBarController์˜ ํŠน์ • VC ์ธ์Šคํ„ด์Šค๋Š” tabBarController as? ํŠน์ •VCํด๋ž˜์Šค๋กœ ์บ์ŠคํŒ…ํ•œ ์ธ์Šคํ„ด์Šค๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํŒจํ„ด์— ๊ด€ํ•ด ***

๋‚ด๊ฐ€ ์ƒ๊ฐํ–ˆ๋˜ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋Š” ํŠน์ • a VC์—์„œ ๋‹ค๋ฅธ b VC๋กœ 1๋Œ€1 ๊ด€๊ณ„๋กœ ์ƒ๊ฐํ–ˆ์—ˆ๋Š”๋ฐ c VC์—์„œ b vc๋กœ ํ˜ธ์ถœํ•  ๋•Œ a vc์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋„ฃ์–ด์คŒ์œผ๋กœ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

์ž˜๋ชป git addํ•œ staged์— ์žˆ๋Š” ํŒŒ์ผ์„ ๋‹ค์‹œ Unstage๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ช…๋ น์–ด

  • git reset HEAD [file] ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด git add๋ฅผ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐœ์„ ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ

  • ํšŒ์›๊ฐ€์ž… ์‹คํŒจ ์‹œ ๋ฒ„ํผ๋ง ๋Š๊ธฐ

  • ๋’ค๋Šฆ๊ฒŒ ํ™•์ธํ–ˆ๋Š”๋ฐ ProfileVC์ง„์ž…์‹œ์— ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ™ˆ๋ทฐ ์ง„์ž…์‹œ์ ์œผ๋กœ ๋ฐ”๊ฟจ๋Š”๋ฐ ๋กœ๊ทธ์ธ -> ํ™ˆ๋ทฐ๋กœ ๊ฐˆ ๋•Œ 2์ดˆ์˜ ๋นˆ ์ƒํƒœ๊ฐ€ ์žˆ๋Š”๋ฐ ๋‹ค์‹œ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

  • ProfileController์—์„œ grid, list bookmark ๋ฒ„ํŠผ์ด์žˆ๋Š”๋ฐ ์ด๋ฅผ stackview+pageViewController๋กœ ์ถ”๊ฐ€ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ

  • ์‚ฌ์šฉ์ž ๋กœ๊ทธ์•„์›ƒ ํ›„ ๋กœ๊ทธ์ธ ํ•˜๊ณ  ํ”„๋กœํ•„ VC๋“ค์–ด๊ฐ€๋ฉด ์ด์ „ ์‚ฌ์šฉ์ž ๊ธฐ๋ก์ด ์žˆ๋‹ค. (์™œ์ด๋Ÿฌ์ง€,, currentUser์˜ uid๋กœ ์ดˆ๊ธฐํ™” ํ•ญ์ƒ ๋˜๋Š”๋ฐ,, ๋‹ค์‹œ ์ˆ˜์ • ํ•ด์•ผํ•œ๋‹ค.)

๊ณต๋ถ€ํ•ด์•ผ ํ•  ๊ฒƒ

  • super.init(collectionVIewLayotu:) ์‹œ์ ์— UICollectionViewFlowLayout() ๊ณผ UICollectionViewLayout() ์ฐจ์ด
  • QoS์ฒ˜๋ฆฌ

๋Š๋‚€์ 

  • ์ €๋ฒˆ ProfileHeader ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•  ๋•Œ Firestore๊ณผ storage๋ฅผ ํ†ตํ•ด ์ตœ๊ทผ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด์™€ ์ด๋ฏธ์ง€ ๋ถˆ๋Ÿฌ์™€ ProfireHeader์˜ ์ •๋ณด๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ํ˜ผ์ž ์งœ๋ดค๋Š”๋ฐ ์ด๋ฒˆ ๊ฐ•์˜์—๋„ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋“ค๋กœ ProfileHeader๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ๊ฐ•์˜๊ฐ€ ์žˆ์—ˆ๋‹ค.

[Clone/Instagram] ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ ๊ธฐ๋Šฅ ๊ฐœ์„ , Feed ๊ฒŒ์‹œ๋ฌผ ๊ตฌํ˜„ | ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋… & ๋Š๋‚€์  #11

๊ตฌํ˜„์˜์ƒ

  • ์ด๋ฒˆ์—๋Š” ์•ฑ์˜ ์ „๋ฐ˜์ ์ธ ์ค‘๋ณต ํ•จ์ˆ˜ ์ œ๊ฑฐ, async ์ฒ˜๋ฆฌ ๊ฐ€ ์ฃผ๋ฅผ ์ด๋ค˜๋‹ค. ์ถ”๊ฐ€๋กœ UplaodPostController์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒŒ์‹œ๊ธ€์„ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ FeedVC์—์„œ ๊ธ€์„ ๋ณด์—ฌ์ฃผ๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

๊ฐ•์˜์™€ ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ

  • Async/Await. Concurrency

Concurrency ์ฒ˜๋ฆฌ๋Š” ํ˜„์žฌ ์•ฑ์˜ ํŠน์„ฑ์ƒ ์ ์šฉํ• ๊ฒŒ ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์ถ”ํ›„์— Feed VC ๊ฒŒ์‹œ๋ฌผ์ด๋‚˜ SearchController์˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž ํ”„๋กœํ•„์— ๋Œ€ํ•ด์„œ ๋ถ€๋ถ„์ ์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ํ•ด๋ณผ ๊ณ„ํš์ด๋‹ค.

๊ณ„์†ํ•ด์„œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์šด๋ฐ›๊ณ  ์ด๋ฏธ์ง€๋„ ๋‹ค์šด๋ฐ›๋Š” ์ž‘์—…์ด ์–ด๋–ป๊ฒŒํ•˜๋ฉด ํšจ์œจ์ ์œผ๋กœ ๊ฐœ์„ ๋  ์ˆ˜ ์žˆ์„์ง€ ๊ณ ๋ฏผํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. @escaping ์„ ํ†ตํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ›์€ ํŒŒ์ด์–ด๋ฒ ์ด์Šค ํ•จ์ˆ˜๋“ค์˜ completionHandler์˜ ๊ฐ’์„ ๋˜ @escaping completion์œผ๋กœ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  ์žˆ๋‹ค.

๊ทผ๋ฐ ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž์˜ uid๋ฅผ ์–ป๊ณ  ๊ทธ ํ›„์— ๋˜ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„, ๋‹‰๋„ค์ž„ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ์ค‘์ฒฉ์œผ๋กœ ํด๋กœ์ € ์•ˆ์— ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ทธ ๊ฐ’์„ ๋˜ ๋ฐ›๋Š” ๊ณณ์• ์„œ ํด๋กœ์ €๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ ์—ฐ๋‹ฌ์•„ ํด๋กœ์ €๋ฅผ ํ˜ธ์ถœ ํ–ˆ์—ˆ๋Š”๋ฐ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์˜ค๋ฅ˜ ๋ฉ”์„ธ์ง€๊ฐ€ ๋–ด๋‹ค "๋„ˆ๋ฌด ํด๋กœ์ €๋ฅผ ๋‚จ๋ฐœํ•˜์ง€ ๋งˆ์„ธ์š”..." ( ๋„ˆ๋ฌด completion์— ์˜์กดํ•œ๊ฒƒ ๊ฐ™๊ธฐ๋„ ํ•˜๊ณ ..)

แ„‹แ…ฆแ„…แ…ฅ2

ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋œ ํ›„์—๋„ ๋ฉ”๋ชจ๋ฆฌ์— ์ง€์›Œ์ง€์ง€ ์•Š๊ณ  ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๊ฐ€ ํ˜ธ์ถœ ๋œ ํ›„์—์•ผ ์—†์–ด์ง€๋Š”?(๊ฐ•๋ ฅ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฐœ์ƒ์‹œ ์•ˆ ์‚ฌ๋ผ์งˆ ์ˆ˜๋„?) @escaping ํด๋กœ์ €๋ฅผ ๊ณ„์†ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ์‰ฌ์› ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์•ฝ๊ฐ„์”ฉ ์ฝ”๋“œ๊ฐ€ ๊ผฌ์ด๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ด๋ฏธ์ง€๋„ ๋‚˜๋ฆ„๋Œ€๋กœ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋‹ค์šด๋ฐ›๊ณ  ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋กœ ํ˜ธ์ถœ์„ ํ–ˆ๋Š”๋ฐ

แ„‹แ…ขแ„…แ…ฅ1

์ด๋Ÿฐ ์—๋Ÿฌ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ๋‹ค. (์•„ํ‘ ์šด์˜์ฒด์ œ ๋•Œ ๋ฐฐ์› ๋˜ ์„ธ๋งˆํฌ์–ด๊ฐ€ ์—ฌ๊ธฐ์„œ๋„ ์‚ฌ์šฉ ๋˜๋Š”๊ตฌ๋‚˜,,)

์ด์ฐธ์— ํด๋ก ์„ ์ž ์‹œ ๋ฉˆ์ถ”๊ณ  ์•ฑ์˜ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ ์‹œํ‚ค๊ธฐ ์œ„ํ•ด, ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด Async, Await ๊ทธ๋ฆฌ๊ณ  thread์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€๋ฅผ ํ–ˆ๋‹ค.

์ง€๊ธˆ ์ผ๋ถ€ APIํ˜ธ์ถœ์„ async, await๋ฅผ ์ ์šฉํ–ˆ๋Š”๋ฐ ์„ฑ๊ณตํ–ˆ๋‹ค.+_+ (30๋ถ„์งœ๋ฆฌ ๊ฐ•์˜๋ฅผ ์‹œ์ฒญํ•˜๋Š”๋ฐ 5์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ ๊ฒฐ๊ณผ์ธ๊ฐ€..,....) ๊ฑฐ์˜ ์ ˆ๋ฐ˜ ๊ฐ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ ํ•จ์ˆ˜๋“ค์„ Async, Await๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

  • try catch๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

  • ํ…์ŠคํŠธ ํ•„๋“œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ตฌํ˜„ํ›„ count์— ๋”ฐ๋ผ ํ˜„์žฌ ๋ช‡ ๊ธ€์ž์ธ์ง€ ๊ฐฑ์‹ ํ•˜๋Š” ๊ฒƒ๊ณผ ์ผ์ • ํฌ๊ธฐ๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ ํ–ˆ๋‹ค. ๊ทผ๋ฐ ์•Œ๊ณ ๋ณด๋‹ˆ textViewDelegate์—๋„ ํ…์ŠคํŠธ ์ฒด์ธ์ง€ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ ๋‚œ ์ƒˆ๋กœ ๊ตฌํ˜„ํ•ด๋ฒ„๋ ธ๋‹ค.

  • ์ฝ”๋“œ๋ฅผ ๋ฆฌํŽ™ํ„ฐ๋งํ•  ๋•Œ Clean Code์˜ ๋Š๋‚Œ์„ ์‚ด๋ ค์„œ ์ฝ”๋“œํ™” ํ•ด๋ดค๋‹ค.
    แ„แ…ณแ†ฏแ„…แ…ตแ†ซแ„แ…ฉแ„ƒแ…ณ

์ถ”๊ฐ€๋กœ ๊ณต๋ถ€ํ•œ ๊ฒƒ

  • ์—๋Ÿฌ์ฒ˜๋ฆฌ EmilY๋‹˜ ๋งํฌ

  • ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ณต์‹ ๋ฌธ์„œ ๋งํฌ

  • Async/await WWDC 2021 ๋งํฌ (์™ธ๊ตญ ์˜์ƒ์ด๋ผ ๊ทธ๋Ÿฐ์ง€ ๋ชจ์กฐ๋ฆฌ ์“ฐ๋ฉด์„œ.. ์˜์ƒ์— ๋‚˜์˜ค๋Š” ๊ฐœ๋ฐœ์ž๋ถ„์˜ ๋ง ํ•˜๋‚˜ํ•˜๋‚˜ ์“ฐ๊ณ  ์ •๋ฆฌํ•˜๋ฉด์„œ ๊ณต๋ถ€๋ฅผ ํ–ˆ๋Š”๋ฐ 30๋ถ„์งœ๋ฆฌ ์˜์ƒ์„ 5์‹œ๊ฐ„์ด๋‚˜ ๊ณต๋ถ€ํ–ˆ๋‹ค;;; )

  • task WWDC 2021 ๋งํฌ

  • @escaping ๊ฐœ๋… ๊ณต๋ถ€์™€ ์ •๋ฆฌ


์ƒˆ๋กœ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…

  • ์ง€๊ธˆ async. await์„ ๊ฑฐ์˜ ์ ์šฉํ•ด๊ฐ„๋‹ค. ์—ด์‹ฌํžˆ ๋–ฑ๋–ฑ๋””์‹œ์—์„œ ๊ณต๋ถ€ํ–ˆ๋‹ค.
    ๊ทธ๋ฆฌ๊ณ  ์ ์šฉํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ ์ถ”๊ฐ€๋กœ ์˜ˆ์™ธ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ–ˆ๋‹ค.

  • selectedIndex

์ด ์ธ๋ฑ์Šค ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด ํ•ด๋‹น vc๋กœ ์ด๋™ํ•œ๋‹ค.

  • tabBarControllerDelegate์˜
    tabBarController(_:shouldSelect:)

ํ˜„์žฌ VC์˜ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๋“ฑ๋กํ•˜๊ณ 
์ด๋ฅผ ํ†ตํ•ด ํŠน์ • ํƒญ๋ฐ” ๋ฒ„ํŠผ์œผ๋กœ vc๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „์— tabBarController(:shouldSelect:) ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์˜ค์ž‰?? ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ์˜ viewWillAppear(:) ์™€ ๋‹ค๋ฅธ์ ์€ ๋ฌด์—‡์ด์ง€??

  • ์ธ๋””์ผ€์ดํ„ฐ์˜ start, end ํ•จ์ˆ˜๋Š” extension์—์„œ ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ ํ”„๋กœํผํ‹ฐ๋Š” ์„ ์–ธ์ด ์•ˆ ๋˜์„œ ๋ชป ๋งŒ๋“œ๋Š” ์ค„ ์•Œ์•˜๋Š”๋ฐ static ๋ณ€์ˆ˜๋Š” ์„ ์–ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

  • ํ…์ŠคํŠธ์˜ ์ผ์ • ํฌ๊ธฐ๊ฐ€ ๋„˜์„ ๊ฒฝ์šฐ

deleteBackward() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ž.

func checkMaxLine(_ textView: UITextView, maxLength: Int) {
   if textView.text.count > maxLength {
   	textView.deleteBackward()
   }
}

๊ถ๊ธˆํ•œ ๊ฒƒ

1
2

- ์ง€๊ธˆ ๊ถ๊ธˆํ•œ ๊ฒƒ์€ ํŠน์ • ํ”„๋ ˆ์ž„์›Œํฌ ํ•จ์ˆ˜๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด ์—๋Ÿฌ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ enum์œผ๋กœ ์ •์˜ํ•ด์„œ ํŠน์ • case๋กœ catchํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์„์ง€๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค..

๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ๋‚ด๊ฐ€ ์ •์˜ํ•˜๊ฑฐ๋‚˜ gaurd else๊ตฌ๋ฌธ์„ ํ†ตํ•ด์„œ ๋‚ด๊ฐ€ ๋˜์ง„ ์—๋Ÿฌ๋Š” ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ํ”„๋ ˆ์ž„์›Œํฌ ํ•จ์ˆ˜์—์„œ ๋˜์ ธ์ง€๋Š”,, ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑํ•˜๋‹ค๊ฐ€ ์‹คํŒจํ–ˆ์„ ๋•Œ ๋ฐœ์ƒ๋˜๋Š” error๋Š” ์–ด๋–ป๊ฒŒ ๋‚ด ์ปค์Šคํ…€ enum : Error์—์„œ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š”์ง€ ๊ถ๊ธˆํ•˜๋‹ค.

์Œ ์ž„์‹œ์ ์œผ๋กœ ๋– ์˜ค๋ฅธ ๋ฐฉ๋ฒ•์€ try? gaurd๋ฅผ ์‚ฌ์šฉํ•ด์„œ throwํ•ด๋ฒ„๋ฆฌ๋Š”๊ฑฐ

tryแ„‹แ…ตแ†ทแ„‰แ…ตแ„Œแ…ฅแ†จแ„Žแ…ฅแ„…แ…ต

์ด๊ฒŒ ๋งž๋Š”์ง€๋Š” ๋ชจ๋ฅด๊ฒ ๋‹ค. ํ•˜์ง€๋งŒ ๋‚ด ์ƒ๊ฐ์œผ๋กœ try?์ฒ˜๋ฆฌ๋ฅผํ•œ ํ›„์— ๋‹ค์Œ ํ•จ์ˆ˜๊ฐ€ ์—๋Ÿฌ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ nil์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด? ๊ทธ๊ฑธ guard๋กœ ๋ฐ”์ธ๋”ฉํ•ด์„œ ๋ฐ”์ธ๋”ฉ ์‹คํŒจ๋˜๋ฉด throw ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. -> ๋งž๋Š” ๊ฒƒ ๊ฐ™๋‹ค. try? ์ฒ˜๋ฆฌ์˜ ๊ฒฝ์šฐ ์˜ต์…”๋„ ํƒ€์ž…์˜ value or nil์„ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ nil์ผ ๊ฒฝ์šฐ ํŠน์ • ํ•จ์ˆ˜๊ฐ€ throw๋กœ ์—๋Ÿฌ๋ฅผ ๋˜์ง„ ๊ฒƒ์ด๋‹ค. ์•„๋‹์ˆ˜๋„... ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์„ ๊ณ„์†ํ•ด์„œ ์ฐพ์„ ๊ฒƒ์ด๋‹ค.

๊ฐœ์„ ํ•ด์•ผ ํ•  ๊ฒƒ

  • ์ธ๋””์ผ€์ดํ„ฐ static์œผ๋กœ ์„ ์–ธํ•˜๊ณ  ๊ฐ๊ฐ์˜ vc๋กœ ์„ ์–ธ๋œ ์ธ๋””์ผ€์ดํ„ฐ ๋ณ€์ˆ˜ ์—†์• ๊ธฐ.

  • searchList์˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ cache๋กœ ํ™œ์šฉํ•˜๊ธฐ (ํ•„์ˆ˜..)

  • ๋ช‡๋ช‡๊ฐœ์˜ source ์ฝ”๋“œ ๋ณด๋ฉด controller์— helper๊ฐ€ ์žˆ๋Š”๋ฐ VM์œผ๋กœ ๋ถ„๋ฆฌ ์‹œ์ผœ์•ผํ•œ๋‹ค. ์ถ”ํ›„์—

  • 11์›” 14~ 20์ผ๊นŒ์ง€ ์•ฝ ์ผ์ฃผ์ผ๋™์•ˆ ์ปด๋ฐ”์ธ๊ณผ task, Actor์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•ด์„œ ๋กœ์ง์„ ์—…๋ฐ์ดํŠธํ•  ๊ฒƒ์ด๋‹ค. ์ปด๋ฐ”์ธ์œผ๋กœ ์™„๋ฒฝํ•˜๊ฒŒ Controller๋กœ๋ถ€ํ„ฐ ๋ถ„๋ฆฌ๋ฅผ ์‹œํ‚ฌ ์˜ˆ์ •์ด๋‹ค.. ํ—คํ—ฟ

[Clone/Instagram] ํŒ”๋กœ์šฐ, ์–ธํŒ” ๊ธฐ๋Šฅ ์ถ”๊ฐ€. ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๊ฐœ์„  | ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋… & ๋Š๋‚€์  #10

์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…

  • UISearchController

๊ฒ€์ƒ‰์„ ํ•˜๋ฉด ํŠน์ • ๋‹จ์–ด๋งŒ tableView cell์— ๋‚˜์˜ค๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•.

UISearchResultsUpdating ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด์„œ updateSearchResults(for:)
๋ฉ”์„œ๋“œ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒ€์ƒ‰์„ ํ•  ๋•Œ๋งˆ๋‹ค ๋งค๊ฐœ๋ณ€์ˆ˜.searchBar.text๋ฅผ ํ†ตํ•ด ๋ฐ›์•„์ง€๋Š” ๋ฐ”์ธ๋”ฉ ๋œ ์‚ฌ์šฉ์ž์˜ ๊ฒ€์ƒ‰ ๋‹จ์–ด๋ฅผ ์–ป์–ด์„œ db์˜ ํŠน์ • ํ‚ค์›Œ๋“œ์—์„œ ํ•ญ๋ชฉ๋“ค์„ ์ฐพ์•„๋‚ธ๋‹ค.

๊ทธ ์˜ˆ๋กœ ๊ฒ€์ƒ‰ ์ฐฝ์—์„œ ํƒ€ ์‚ฌ์šฉ์ž์˜ ์•„์ด๋””๋ฅผ ์ฐพ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ filter ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์กฐ๊ฑด์— ๋งž๋Š” ์›ํ•˜๋Š” ํŠน์ • index๋งŒ [Element]๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฒŒ filterํ•จ์ˆ˜์ด๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํŠน์ • ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ˜ํ™˜๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋”ฐ๋กœ ํ”„๋กœํผํ‹ฐ์— ์ €์žฅํ•ด์„œ TableView cell์„ ํŠน์ • ์กฐ๊ฑด์— ๋งž๊ฒŒ ๊ฐฑ์‹ ํ•˜๋ฉด ๋œ๋‹ค. filter์— ์˜ํ•ด searchBar์˜ ๋ฐ”์ธ๋”ฉ ๋œ ๊ฐ’์€ ๊ณง ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒ€์ƒ‰์„ ํ–ˆ์Œ์„ ์˜๋ฏธํ•จ์œผ๋กœ ๋ฐ”์ธ๋”ฉ ๋  ๋•Œ๋งˆ๋‹ค tableView.reloadData()๋ฅผ ํ†ตํ•ด์„œ tableView์˜ numberOfRowsInSection, cellForRowAt๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.

  • ์‚ฌ์šฉ์ž๋ผ๋ฆฌ์˜ ํŒ”๋กœ์šฐ ๊ด€๊ณ„๋Š” ์–ด๋–ป๊ฒŒ ์ƒ์„ฑ๋ ์ง€์— ๋Œ€ํ•ด์„œ ๋งŽ์ด ๊ถ๊ธˆํ–ˆ๋‹ค.

ํ•œ ํœด๋Œ€ํฐ์—์„œ A๊ฐ€ ๋กœ๊ทธ์ธ ํ–ˆ๋‹ค๋ฉด ๋‚˜๋ฅผ ์ œ์™ธํ•œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“คํ•œํ…Œ ํŒ”๋กœ์šฐ๋ฅผ ๊ฑธ ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ํŒ”๋กœ์šฐ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ๊ทธ ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ db์˜ ํŠน์ • ์œ„์น˜์— ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋ฉด ๋œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๋งจ ์ฒ˜์Œ์— ํšŒ์›๊ฐ€์ž…์„ ํ•  ๋•Œ ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ†ตํ•ด ์œ ์ผํ•œ ์‚ฌ์š”์ž ๊ตฌ๋ณ„ ํ‚ค ๊ฐ’์ธ uid๋ฅผ ๋ฐ›๋Š”๋ฐ ์ด๋ฅผ ํ™œ์šฉํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์ธ์ ์‚ฌํ•ญ์„ ํฌํ•จํ•œ ๋„ํ๋จผํŠธ๋ฅผ uid๋กœ ์ €์žฅํ•˜๊ณ  ํŒ”๋กœ์šฐ๋‚˜ ์–ธํŒ”๋„ ๊ฐ๊ฐ์˜ uid์— ๋Œ€ํ•ด์„œ ๋ช‡๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ํŒ”๋กœ์šฐ ํ–ˆ๋Š”์ง€ uid๋ฅผ ํ†ตํ•ด ์ €์žฅ, ์ค‘๋ณต์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๋ฅผ ํŒ”๋กœ์šฐ ํ•  ๋•Œ๋Š” followers. following ๋‘˜ ๋‹ค ์—…๋ฐ์ดํŠธ ํ•ด์•ผํ•œ๋‹ค.

แ„‚แ…ขแ„€แ…ก แ„แ…ก แ„‹แ…ฒแ„Œแ…ฅแ„‹แ…ฆแ„€แ…ฆ แ„‘แ…กแ†ฏแ„…แ…ฉแ„‹แ…ฎ แ„’แ…กแ†ฏ แ„„แ…ข

์•ฑ์„ ์‚ฌ์šฉ์ค‘์ธ ํ˜„์žฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ํŒ”๋กœ์šฐ ํ•œ๋‹ค๋ฉด ํŒ”๋กœ์šฐ ๋‹นํ•œ ํƒ€ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„ ์•„์ด๋””๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๊ทธ ํ•ด๋‹น ์‹๋ณ„์ž์˜ ํŒ”๋กœ์›Œ ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋ ค๊ณ  ๋“ฑ๋กํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋‚ด๊ฐ€ ํŒ”๋กœ์šฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ๋Š” ๋‚ด๊ฐ€ ํŒ”๋กœ์šฐ ์ค‘์ธ db์— ํƒ€ ์‚ฌ์šฉ์ž๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๊ณ  ํƒ€ ์‚ฌ์šฉ์ž์˜ ํŒ”๋กœ์›Œ ์ˆซ์ž์— ๋‚ด ๊ณ„์ •์„ ๋“ฑ๋ก์‹œ์ผœ์•ผ ํ•œ๋‹ค. ์—ฌ๊ฒŒ์„œ ํƒ€ ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•  ๊นŒ? x ์ตœ์†Œํ•œ์œผ๋กœ ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ex) uid์™€ ๊ฐ™์€ ์ •๋ณด๋งŒ ๋“ฑ๋กํ•˜๋ฉด ๋œ๋‹ค.

๋Š๋‚€์ 

  • ํด๋ฆฐ ์ฝ”๋“œ๋ฅผ ์ฝ์€ ํ›„์— ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ์—†์— ์ตœ์†Œํ•œ, ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ์‹ถ์–ด์„œ ViewModel์ด ๋‹ค๋ฅธ controller์—์„œ ์‹คํ–‰๋˜๋Š”๋ฐ ์„ฑ๋Šฅ์ด ๊ฑฐ~์˜ ๊ฐ™์•„์„œ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋‹ค๋ฅด์ง€๋งŒ VM์„ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋‹ค๋ณด๋‹ˆ ์ ์  ๋‘ ์ปจํŠธ๋กค๋Ÿฌ์˜ VM์ฐจ์ด๊ฐ€ ๋‚˜์„œ ๊ฒฐ๊ตญ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•˜๊ฒŒ ๋ฌ๋‹ค. ๋”ฐ๋ผ์„œ ์ผ๋‹จ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ๋‹ค ๊ตฌํ˜„ํ–ˆ์„ ๋•Œ ๊ฐ™์€ ๊ฑฐ๋ฅผ ๋ฌถ๋Š” ์‹์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์„ ํ–ˆ๋‹ค.

  • ๊ฐ•์˜์—์„œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ Storge์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์šด ๋ฐ›์•„์˜ฌ ๋•Œ SDWebImage ์˜คํ”ˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ•จ์ˆ˜๋ฅผ ์“ฐ๋ฉด ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„์™€ ImaeView์— ์ €์žฅํ•˜๊ณ  ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์™€ ๋™์‹œ์— ์บ์‹ฑ ์ฒ˜๋ฆฌ๊นŒ์ง€ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๊ทผ๋ฐ ์‹ค๋ ฅํ–ฅ์ƒํ• ๊ฒธ ๊ทธ๋ƒฅ ๋‚ด๊ฐ€ ์Šค์Šค๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋Š”๋ฐ ์ด๋ฏธ์ง€ ํ•œ๊ฐœ ๋ฐ›์„ ๋•Œ๋Š” ๊ทธ๋ƒฅ ๋ถˆ๋Ÿฌ์˜ค๋ฉด ๋ฌ์—ˆ๋‹ค. ๊ทผ๋ฐ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” cell์„ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” dequeue๊ด€๋ จ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ cell์„ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ์ƒ๋‹นํžˆ ๋Š๋ ธ๋‹ค. ๊ทธ๋ž˜์„œ ์ฐพ์•„๋ณธ ๊ฒฐ๊ณผ NSCache๋ฅผ ๊ณต๋ถ€ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ…Œ์ด๋ธ” ๋ทฐ๋ฅผ ์˜ˆ๋กœ๋“ค ๋•Œ ์œ„์— ์Šค์ฝ”๋กค ํ•˜๋ฉด ์ด๋ฏธ ์žˆ๋˜ ์ด์ „ ์ด๋ฏธ์ง€๊ฐ€ ๋‚˜์˜จ ํ›„์— ์Šคํฌ๋กค์ด ๋๋‚˜๊ณ  ํ•ด๋‹น cell์˜ ์ด๋ฏธ์ง€๋กœ ๋กœ๋“œ๋œ๋‹ค. ์ผ๋‹จ ์ž„์‹œ๋กœ ์ด๋ฏธ์ง€๊ฐ€ ์ด์ „ ์ด์ƒํ•œ ์ด๋ฏธ์ง€์—์„œ ํ˜„์žฌcell์˜ ์ด๋ฏธ์ง€๋กœ ๋กœ๋”ฉ๋˜๋Š” ๊ฒƒ๋ณด๋‹จ ํฐ์ƒ‰ -> ์ด๋ฏธ์ง€๋กœ๋“œ๋กœ ๋ฐ”๊พธ์—ˆ๋‹ค. ์ถ”ํ›„์— ๋ฐ”๋กœ NSCache๋“ฑ์„ ํ†ตํ•ด์„œ ํšจ์œจ์ ์œผ๋กœ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด๋ด์•ผ๊ฒ ๋‹ค.

//์ขŒ ์ด์ „ ์ด๋ฏธ์ง€ , ์šฐ ์ž„์‹œ๋กœ ๊ฐœ์„ ํ•œ ์ด๋ฏธ์ง€

๋งˆ์ฃผํ•œ ์—๋Ÿฌ

  • Auth.auth().currentUser ๊ฐ’์ด ๋™๊ธฐ์ ์œผ๋กœ ๊ฐฑ์‹ ๋˜์ง€ ์•Š๋Š” ์—๋Ÿฌ

Auth.auth().currentUser๋ฅผ ํ†ตํ•ด์„œ ํ˜„์žฌ ํ•ธ๋“œํฐ์— ๋กœ๊ทธ์ธ ํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ํ† ๋Œ€๋กœ ํŒ”๋กœ์šฐ, ์–ธํŒ”, ์ •๋ณด๋“ฑ์„ ๊ธฐ๋กํ•˜๊ณ  ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค. ์ง€๊ธˆ ํ˜„์žฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒ ํ›„ ๋‹ค๋ฅธ ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ํ–ˆ์„ ๋•Œ๋Š” ์ฆ‰๊ฐ์ ์œผ๋กœ Auth.auth().currentUser์˜ ๊ฐ’์ด Auth.auth().signIn(withEmail:password:)๋ฅผ ํ†ตํ•ด synchronousํ•˜๊ฒŒ ๊ฐฑ์‹ ๋˜์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ๊ทธ๋ ‡์ง€ ์•Š์•˜๋‹ค. (์ฐธ๊ณ  ๊ธ€) ์Œ.. Auth.auth().currentUser์— ์ƒ๋‹นํžˆ ์˜์กด์ ์ด์—ˆ๋‹ค. ํ”„๋กœํ•„ ์ƒ์„ธ์ •๋ณด, ์ด ์ •๋ณด๋ฅผ ํ† ๋Œ€๋กœ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ํŒ”๋กœ์šฐ ์–ธํŒ” ๋“ฑ์„ ๋‹ค Auth.auth().currentUser์˜ ํŠน์ • ๊ฐ’์„ ํ†ตํ•ด์„œ ํŒŒ์‹ฑ ๋ฐ›๊ณ  ์ฒ˜๋ฆฌํ–ˆ๋Š”๋ฐ.... ์•ฑ์„ ์™„์ „ํžˆ ์ข…๋ฃŒ ํ›„ ์žฌ ์‹œ์ž‘ํ•ด์•ผ ๋น„๋กœ์†Œ ์ด ๊ฐ’์ด ์ตœ์‹  ์ƒํƒœ๋กœ ๋ฐ”๋€Œ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๋Œ€์•ˆ์ด ํ•„์š”ํ–ˆ๋‹ค.

// AUTH.updateCurrentUser(user:) ์ด ํ•จ์ˆ˜๋„ ์ ์šฉx

์˜๊ตฌ ์ €์žฅ์†Œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ˜„์žฌ ๋กœ๊ทธ์ธ ์ค‘์ธ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ํŒŒ์‹ฑ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ํ‚ค ๊ฐ’๋งŒ ๋”ฐ๋กœ ์ €์žฅํ•˜๊ณ  ํ˜„์žฌ ์ •๋ณด๋ฅผ ํŒŒ์‹ฑ๋ฐ›๋Š” ๊ด€๋ จ ํ•จ์ˆ˜์„ ์ „๋ถ€ ๊ณ ์น˜๋‹ˆ ์ •์ƒ์ ์œผ๋กœ ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๊ฐ€ ์ฆ‰๊ฐ ๊ฐฑ์‹ ๋ฌ๋‹ค.

// currentUser๋Œ€์‹  ์˜๊ตฌ์ €์žฅ์†Œ์— ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์ด๋ฅผ ํ† ๋Œ€๋กœ currentUser ์ •๋ณด๋ฅผ fetchํ•œ ์ดํ›„์— Auth.auth().currentUser์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์•„๋ž˜ ์˜์ƒ์€ ์ •์ƒ์ ์œผ๋กœ ํŒ”๋กœ์šฐ, ์–ธํŒ”์ด ๋˜๋Š” ์˜์ƒ์ด๋‹ค.

๊ตฌํ˜„ํ•˜๋ฉด ์„œ ์–ด๋ ค์šด ์ 

  • ์ง€๊ธˆ๊นŒ์ง€ ์ œ์ผ ๊นŒ๋‹ค๋กœ์šด ๊ฒƒ์€ ๋‹ค๋Ÿ‰์˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์ œ์ผ ์–ด๋ ต๊ณ  ์ง€๊ธˆ๋„ ๊ณ ๋ฏผ์ค‘์ด๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-11-05 แ„‹แ…ฉแ„’แ…ฎ 12 29 18

  • ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์ด๋ฏธ์ง€ ๋‹ค์šด์„ ๋„ˆ๋ฌดํ•ด์„œ ํ• ๋‹น๋Ÿ‰์„ ์ดˆ๊ณผํ–ˆ์—ˆ๋Š”๋ฐ ์Œ? ๋ช‡๋ฒˆ ํ•˜์ง€๋„ ์•Š์€๊ฒƒ ๊ฐ™์€๋ฐ ํ• ๋‹น๋Ÿ‰์„ ์ดˆ๊ณผํ•ด์„œ ๊ธฐ๋Šฅ์„ ์ด๋ฏธ์ง€ ํŒŒ์‹ฑ์ด ์ž˜ ๋ฌ๋Š”์ง€, ํƒ€ VC์—์„œ ์ด๋ฏธ์ง€ ๋กœ๋“œ๊ฐ€ ์ž˜ ๋ฌ๋Š”์ง€.. ์ค‘๋ณต๋œ ์ฝ”๋“œ, ์ค‘๋ณต ํŒŒ์‹ฑ ํ•˜๋ ค๋Š” ์ฝ”๋“œ๋ฅผ ์—†์• ๋Š”๋ฐ ํ• ๋‹น๋Ÿ‰ ์ดˆ๊ณผ๊ฐ€ ๋˜๋ฒ„๋ฆฌ๋‹ˆ๊นŒ ํ™•์ธ์„ ๋ชปํ•ด ๋‹ต๋‹ตํ–ˆ๋‹ค. ํŒŒ๋ฒ  ์“ธ ๋•Œ ์ด์  ์กฐ์‹ฌํ•ด์•ผ๊ฒ ๋‹ค.

์ƒ‰๋‹ค๋ฅธ ์‹œ๋„

  • ๊ฒ€์ƒ‰์ฐฝ์—์„œ ํŠน์ • cell์„ ํ„ฐ์น˜ํ•  ๋•Œ ์ด์ „์— ์ €์žฅ๋œ dequeue์˜ cell์˜ ์ •๋ณด๋ฅผ ํ† ๋Œ€๋กœ ์‚ฌ์šฉ์ž์˜ ๋””ํ…Œ์ผํ•œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ ์คฌ๋‹ค.

  • ์ถ”ํ›„์— ๋˜ ๊ฐœ์„ ํ•  ๊ฑด๋ฐ.. ์ผ๋‹จ ์ž„์‹œ์ ์œผ๋กœ ์ •ํ™•ํ•œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์žฌ์‚ฌ์šฉํ์—์„œ ๊บผ๋‚ด์˜ฌ ๋•Œ ํฐ์ƒ‰์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

  • Auth.auth().currentUser๊ฐ€ ๊ผญ ์•ฑ์„ ์ข…๋ฃŒํ–ˆ๋‹ค ๋‹ค์‹œ ์‹คํ–‰ํ•ด์•ผ ๋ฐ”๋€Œ๊ธฐ์— ์˜๊ตฌ ์ €์žฅ์†Œ๋ฅผ ํ™œ์šฉํ–ˆ๋‹ค.

[Clone/Instagram] Notification ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ ๋Š๋‚€์ , ๊ณ ๋ฏผ๊ฑฐ๋ฆฌ, Coordinator ํŒจํ„ด ์ ์šฉ #15

๋ชฉํ‘œ: ๋ˆ„๊ตฐ๊ฐ€ ํ”ผ๋“œ์—์„œ ํŒ”๋กœ์šฐ๋‚˜ ์ปค๋งจํŠธ, ์ข‹์•„์š” ํ–ˆ์„ ๋•Œ
Notificaiton Controller์—์„œ ์•Œ๋ฆผ์„ ๋œจ๊ฒŒ ํ•˜๋Š” ๊ฒƒ!

ํŠน์ • ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ์„ ์—…๋กœ๋“œ ํ•ด์•ผํ•œ๋‹ค.

A ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ํ–ˆ์„ ๋•Œ B์˜ ํฌ์ŠคํŠธ์— ํ•˜ํŠธ ๋ˆ„๋ฅด๋ฉด B์˜ notificaiton์„ ํ•ด์„œ ์•Œ๋ฆผ ๋ชฉ๋ก ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ ํ•ด์•ผํ•œ๋‹ค.

B๋Š” ์•ฑ์„ ์—ด๊ณ  ์•Œ๋ฆผ์ฐฝ์„ ์‚ดํŽด๋ดค์„ ๋•Œ A์˜ ์•Œ๋ฆผ์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

  1. ํŠน์ • ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ ํƒ€์ž…์„ ์—…๋กœ๋“œ ํ•ด์•ผํ•œ๋‹ค.
  • ์ฝ”๋””๋„ค์ดํ„ฐ ์ ์šฉ!

๊ตฌํ˜„ ์˜์ƒ

์ถ”๊ฐ€์ ์œผ๋กœ,, ์„œ๋ฒ„์— ์˜ฌ๋ฆด ๋•Œ Timestamp์— seconds๋กœ ์ €์žฅํ–ˆ๋Š”๋ฐ ๋‹ค์‹œ ์‹œ ๋ถ„ ์ดˆ๋กœ ๋ฐ”๊ฟ”์„œ ์‹œ๊ฐ„์„ ์—…๋ฐ์ดํŠธ ํ•ด์•ผํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ๋‚˜๊ฐ€์žˆ์„ ๋•Œ๋„ ์•Œ๋ฆผ์„ fcmํ‘ธ์‹œ๋ฅผ ๊ตฌํ˜„ํ•ด๋ด์•ผ๊ฒ ๋‹ค.

์ƒˆ๋กœ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…

  • ์ธ๋””์ผ€์ดํ„ฐ

๋‹จ์ˆœํžˆ ํ˜ธ์ถœ๋งŒํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ธ๋””์ผ€์ดํ„ฐ ๋ทฐ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋ฉด ์‹คํ–‰์ค‘์ธ ๋™์•ˆ์—๋Š” ๋‹ค๋ฅธ ๋ทฐ๋“ค์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ์ฐจ๋‹จํ•ด์•ผ ์ข‹๋‹ค.

๊ทธ๋ž˜์„œ ์ธ๋””์ผ€์ดํ„ฐ ์‹œ์ž‘ ํ•  ๋•Œ view.isUserInteractionEnalbled = false

-> ์ธ๋””์ผ€์ดํ„ฐ ๋ ์‹œ view.isUserInteractionEnabled = true ๋กœ ๋Œ€์ฒ˜ํ–ˆ๋‹ค.

  • tableView.separatorStyle

separator๋Š” cell ๊ณผ cell์‚ฌ์ด์˜ ์„ ์„ ๋งํ•จ. separator inset ๋Š” leadingAnchor์— ๋Œ€ํ•œ ์—ฌ๋ฐฑ

  • ํ”„๋กœํ•„ ๋ฐ›๋Š” string์˜ ์ฃผ์†Œ๊ฐ€ ์žˆ๋‹ค.

notification #1

Data(contentsOf:)๋ณด๋‹ค URLSession์™€ ๊ฐ™์€ async network api๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ•œ๋‹ค.

URLSession.shared.dataTask(with: url) { (data, response, err)
...
}.resume()

๋งˆ์ฃผํ•œ ์˜ค๋ฅ˜

modern concurrency + combine์„ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜์‚ฌํ•ญ..

ViewController์˜ state์— ๋”ฐ๋ฅธ Input์„ ViewModel์˜ transform(_:)-> Output์œผ๋กœ ๋กœ์ง ์ฒ˜๋ฆฌ ํ›„ ๋‹ค์‹œ ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ์œผ State๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐฑ์‹ ํ•ด ์ฃผ๋Š” ์ฝ”๋“œ์—์„œ refresh๋ผ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋˜๋ฉด vm์˜ input์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

แ„‹แ…งแ„€แ…ตแ„‹แ…ฉแ„…แ…ฒ1

์ด๋•Œ ๊ธฐ์กด ์ €์žฅ๋œ posts ๋ฐฐ์—ด์— ๋‹ด๊ฒจ์žˆ๋Š” ํฌ์ŠคํŠธ ์ •๋ณด๋ฅผ ๋ชจ๋‘ ์‚ญ์ œํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  fetchPosts๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ ๊ฐฑ์‹ ๋œ ํฌ์ŠคํŠธ ์ •๋ณด๋“ค์„ ๋ฐ›์•„์˜จ๋‹ค. ๊ทธ ํ›„ .reloadData๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์–ผํ• ๋ณด๋ฉด ์ •์ƒ์ ์ธ ์ฝ”๋“œ ๊ฐ™์ง€๋งŒ... fetchPosts๋ฅผ ๋ณด๋ฉด

แ„‹แ…งแ„€แ…ตแ„‹แ…ฆ แ„†แ…ฎแ†ซแ„Œแ…ฆแ„€แ…ก แ„‹แ…ตแ†ปแ„‹แ…ณแ†ท Task

Task๋ฅผ ํ†ตํ•ด asyncํ•จ์ˆ˜์ธ apiClient.postCase.fetchPosts()๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋‹ค์šด๋ฐ›๋Š”๋‹ค. fetchPosts() ํ•จ์ˆ˜๋Š” ์ข…๋ฃŒ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  .reloadData state๋กœ ๋ฐ˜ํ™˜๋˜์–ด ViewController์˜ State์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฆฌ ๋กœ๋“œํ•˜๋ผ๊ณ  ๊ณง๋ฐ”๋กœ ์ „๋‹ฌํ•œ๋‹ค. ํ•˜์ง€๋งŒ async ํ•จ์ˆ˜๋Š” await๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ๋ฒˆ ์‹คํ–‰, ์ค‘์ง€ ์ž‘์—…์„ ํ†ตํ•ด ํฌ์ŠคํŠธ๋ฅผ ๋ฐ›์•„์˜ด์œผ๋กœ ์ƒˆ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐฑ์‹ ํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ด๋ธ” ๋ทฐ.reloadData๋ฅผ ์‹คํ–‰ํ•ด๋„ async apiClient.postCase.fetchPosts()๋Š” ์‹คํ–‰์ด ์™„๋ฃŒ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ด ์ ์„ ์กฐ์‹ฌํ•ด์•ผ ํ•œ๋‹ค.

๋ฐ”์ธ๋”ฉ ์ค‘์ฒฉ.

cell์•ˆ์—์„œ ๋ฐ”์ธ๋”ฉ์„ ํ•  ๊ฒฝ์šฐ ๋ฐ”์ธ๋”ฉ์ด ์ค‘์ฒฉ๋œ๋‹ค. prepareforReuse๋ฅผ ํ†ตํ•ด
์žฌ์‚ฌ์šฉ ํ์— ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ํŠน์ • cell์ด ํ™”๋ฉด์— ๋…ธ์ถœ๋œ๋‹ค๋ฉด ๋‹ค์‹œ ๊บผ๋‚ด ์“ฐ๋Š”๋ฐ ๊บผ๋‚ผ๋•Œ๋งˆ๋‹ค ๋ฐ”์ธ๋”ฉ ๋œ๋‹ค.

notiแ„‹แ…ฆแ„…แ…ฅ3
81e029b10819107)

๊ทธ๋Ÿผ

NotificationCellViewModel์˜ transform(with:)๊ฐ€ ์žฌ์‚ฌ์šฉ์œผ๋กœ ๊บผ๋‚ด์งˆ ๋•Œ๋งˆ๋‹ค ๋ฐ”์ธ๋”ฉ์ด ๋˜์„œ ๋ˆ„์  ๋ฐ”์ธ๋“œ ๋œ ๋งŒํผ์˜ ๊ฐ™์€ value๋ฅผ emitํ•œ๋‹ค.

๊ทธ๋ž˜์„œ cell์˜ ๊ฒฝ์šฐ prepareForReuse()์—์„œ subscription๋“ค์„ ์ „๋ถ€ cancelํ•œ ํ›„์— ๋‹ค์‹œ ๋ฐ”์ธ๋”ฉ์„ ํ•ด์ฃผ์—ˆ๋‹ค.

subscriptions์„ holdingํ•œ๋‹ค๊ณ  ํ•ด๋„ dismiss๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ฉด ์ค‘์ฒฉํ•ด์„œ ์Œ“์ผ ์ˆ˜ ์žˆ์–ด์„œ ์ž„์˜์ ์œผ๋กœ cancel๊ณผ ์žฌ ํ• ๋‹น ๋“ฑ์„ ํ†ตํ•ด ๊ด€๋ฆฌํ•˜๋Š”๊ฒŒ ์ค‘์š”ํ•˜๋‹จ๋Š ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

์ตœ์†Œํ•œ์œผ๋กœ ๋ฐ”์ธ๋”ฉ ๋˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์ค„์˜€์Œ์—๋„ ๊ทธ๋ž˜๋„ ๋‘ ๋ฒˆ์”ฉ ์‹คํ–‰์ด ๋œ๋‹ค. ์ค‘๋ณต ํ˜ธ์ถœํ•ด์ฃผ๋Š” ๊ตฌ๊ฐ„์ด ์—†์–ด์„œ ๊ทธ๋Ÿฐ๋ฐ ์ด์ „์— ์žˆ๋˜ cell์˜ ์œ„์น˜์™€ ์žฌ์‚ฌ์šฉํ์—์„œ ๋ฐ”๋กœ ๊บผ๋‚ด์˜ค๊ธฐ ๋•Œ๋ฌธ์— transform(with:)๊ฐ€ ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค. ์ •๋ง ์ตœ์†Œํ•œ์˜ ํ˜ธ์ถœ์ธ ๊ฒƒ ๊ฐ™๋‹ค. ์—ฌ๊ธฐ์„œ operator๋ฅผ ์‚ฌ์šฉํ•˜ ๋‹จ ํ•œ๋ฒˆ๋งŒ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋‚˜์ค‘์— ๋ฌธ์ œ ๋ฐœ์ƒ์‹œ first()๋ฅผ ์‚ญ์ œํ•ด์•ผ๊ฒ ๋‹ค.


  • TableView cell's UIImageView, UIButton object action event ์‹คํ–‰ ์•ˆ๋˜๋Š” ์ด์œ 

https://dev-with-precious-dreams.tistory.com/168


passthroughSubject๋ฅผ ํ†ตํ•ด delegate๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ ํ•œ๋ฒˆ์˜ action event์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋‘๊ฐœ์”ฉ published๋˜๋Š” ์ด์œ  NotificationController.swift ๊ด€๋ จ

๊ฒฐ๋ก ์ ์œผ๋กœ ๋‘ ๋ฒˆ send -> sink๋œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค...

์ €๋ฒˆ์—๋„ ํ•œ๋ฒˆ ์ปด๋ฐ”์ธ์œผ๋กœ delegate ์“ธ ๋•Œ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ๋ฅผ ์ตœ์†Œํ•œ์œผ๋กœ ์ค„์˜€๋Š”๋ฐ๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋‘ ๋ฒˆ์”ฉ ํ˜ธ์ถœ ๋๋‹ค. ๊ณ„์†ํ•ด์„œ ๊ฑด๋“œ๋ ค๋ด๋„ ์•ˆ๋˜์„œ ์–ด์ฉ” ์ˆ˜ ์—†์ด first() operator๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋„˜๊ฒผ๋Š”๋ฐ ์ด๋ฒˆ์—๋„ ๋˜ ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒ๋ฌ๋‹ค. ๊ณ ์น˜๊ธฐ ์œ„ํ•ด ์•ˆ๊ฐ„ํž˜์„ ์ผ๋Š”๋ฐ๋„ ๊ณ„์† ๋‘ ๊ฐœ์”ฉ ํ˜ธ์ถœ๋ฌ๋‹ค.

์ƒํ™ฉ // Date: 1.13

  1. cell์˜ object ํ„ฐ์น˜ -> addTarget ๋ฉ”์†Œ๋“œ ํ•œ๋ฒˆ ํ˜ธ์ถœ. ์—ฌ๊ธฐ์„œ send๋กœ currentValueSubject์—๊ฒŒ ๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๋Š”๋ฐ ๋‘ ๋ฒˆ ์ „๋‹ฌํ•˜๊ฒŒ ๋œ๋‹ค.

แ„‹แ…ฆ6

์ผ๋‹จ cell์•ˆ์— ๋ฒ„ํŠผ๊ณผ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋ทฐ, ํฌ์ŠคํŠธ ์ด๋ฏธ์ง€ ๋ทฐ ์„ธ ๊ฐœ๊ฐ€ ์žˆ๊ณ  ๊ทธ ์ค‘ ๋‘ ๊ฐœ์˜ ์•ก์…˜ ๋ฉ”์„œ๋“œ๋‹ค.

์ค‘์š”ํ•œ ๊ฑด ๋ฒ„ํŠผ, ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ํ•œ ๋ฒˆ ํด๋ฆญํ•˜๋ฉด ๋ถ„๋ช… ์•ก์…˜ ๋ฉ”์„œ๋“œ๋Š” ํ•œ๋ฒˆ ๋™์ž‘ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ subject์˜ sink๋ฅผ ๋‘ ๋ฒˆ ๋ฐ›๋Š”๋‹ค. ํ™•์ธํ•ด๋ณธ ๊ฒฐ๊ณผ send๋ฅผ ๋‘ ๋ฒˆ ํ•œ๋‹ค. ๋ฐ”์ธ๋”ฉ์ด ๋‘ ๋ฒˆ ๋ฌ๋‹ค๋Š” ๊ฒฝ์šฐ๋‹ค.

แ„‹แ…ฆ7

์ด๊ฑด delegate๋ฅผ ๋ฐ›๋Š”์ชฝ

cell์—๋„ vm์„ ์ •์˜ํ–ˆ๋‹ค. ์ถ”ํ›„ Advanced architecure๋กœ VM์˜ ์˜ˆ๋ฅผ ์ •ํ™•ํžˆ ๋ด์•ผ๊ฒ ๋‹ค.. ( Cell ๋˜ํ•œ view์ธ๋ฐ viewModel์„ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์€์ง€.. ๊ถ๊ธˆํ•˜๋‹ค)

์›์ธ์„ ์ฐพ์ง€ ๋ชปํ•ด iOS๊ฐœ๋ฐœ ๋‹จํ†ก๋ฐฉ์— ๋„์›€์„ ์š”์ฒญํ–ˆ๋Š”๋ฐ ๋‹คํ–‰ํžˆ ํ•œ๋ถ„์ด ๋‹ตํ•ด ์ฃผ์…จ๋‹ค.. "์žฌ์‚ฌ์šฉ ํ์—์„œ ๊บผ๋ƒˆ์„๋•Œ๋„ subscriptions ์ดˆ๊ธฐํ™”๋ฅผ ํ–ˆ๋Š”์ง€??!!?"

แ„‹แ…ฆ9

๋ฌผ๋ก  ํ–ˆ์—ˆ๋‹ค... ๊ทธ๋Ÿผ์—๋„ ๋‘ ๋ฒˆ์”ฉ ํ˜ธ์ถœ๋ฌ๋‹ค. ๊ฒฐ๋ก ์ ์œผ๋กœ ์–ด์จŒ๋“  ๋‘๋ฒˆ์”ฉ sink๋ฅผ ํ•œ ๊ฒƒ์€ ๋ฐ”์ธ๋”ฉ์„ ๋‘ ๋ฒˆ ํ–ˆ๋‹ค๋Š” ์˜๋ฏธ๋กœ ๊ฒฐ๋ก ์„ ๋‚ด๋ ธ๋‹ค. cell<-> cellVM , ViewController<->vm ์ฝ”๋“œ ์—ฌ๊ธฐ์ €๊ธฐ์„œ subscriptions๋ฅผ ์œ ์ง€ํ•˜๋Š๋ผ ๋ฐ”์˜๋‹ค...

NotificationsController์—๋„ vm๊ณผ์˜ ๋ฐ”์ธ๋”ฉ, NotificationCell ๋„ cellVM๊ณผ์˜ ๋ฐ”์ธ๋”ฉ, ๊ฒŒ๋‹ค๊ฐ€ cell๊ณผ notificationController์˜ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ฐ„ ๋ฐ”์ธ๋”ฉ ์ฆ‰ subscriptions๊ฐ€ ๋‘ ๊ฐœ ์ •๋„ ์žˆ์—ˆ๋Š”๋ฐ ์ด์ค‘์—์„œ delegate๋ฐ”์ธ๋”ฉ์— ๊ด€ํ•œ subscriptions๋ฅผ notificationController์˜ subscriptions ๋ณ€์ˆ˜์—์„œ ์ฐพ๊ธฐ ํž˜๋“ค์—ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด Set์œผ๋กœ ์ €์žฅํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ƒํ™ฉ ์„ค๋ช…์„ ๊ธ€๋กœ ๋‚จ๊ธฐ๊ธฐ ์• ๋งคํ•œ๋ฐ ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋‚ด๊ฐ€ ์ž˜๋ชปํ•œ ์ ์€ ๋‹จํ†ก๋ฐฉ์—์„œ ๊ฐœ๋ฐœ์ž ๋ถ„์ด ํ•ด์ค€ ๋ง์ด ๋งž๋‹ค. ์žฌ์‚ฌ์šฉํ์—์„œ ๊บผ๋‚ด์˜ฌ ๋•Œ cell์˜ cellVM์€ ์ดˆ๊ธฐํ™”๋ฅผ ํ–ˆ์ง€๋งŒ NotificationController์˜ subscriptions๋Š” ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜์ง€ ์•Š์•˜๋‹ค. ๊ฒฐ๋ก ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉ ํ์—์„œ ๊บผ๋‚ผ ๋•Œ ์ดˆ๊ธฐํ™”๋ฅผ ์™„์ „ํžˆ ํ•˜์ง€ ๋ชปํ•œ ๊ฒƒ์ด ๋œ๋‹ค.(cell์˜ subscriptions๋Š” ์ดˆ๊ธฐํ™” ํ–ˆ์—ˆ๋Š”๋ฐ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ด€๋ จ subscription์„ NotificationCeneter์—์„œ ํ•ด์ฃผ์ง€ ๋ชปํ•œ ๋‚ด ์ž˜๋ชป..ใ… )

์žฌ์‚ฌ์šฉํ -> setupNotificationCellDelegate(_:)๋Š” ๋งค๋ฒˆ sink๋ฅผ ํ†ตํ•ด ๋ฐ”์ธ๋”ฉ ๋˜๋Š”๋ฐ ์ด๋•Œ subscriptions๋ฅผ ์ดˆ๊ธฐํ™” ํ•ด์ฃผ์ง€ ์•Š์€ ๊ฒƒ์ด๋‹ค.

แ„‹แ…ฆ10

๋ฐ”์ธ๋”ฉ์„ ์ด๊ณณ ์ €๊ณณ์—์„œ ํ•˜๋‹ค ๋ณด๋‹ˆ๊นŒ prepare๋ฅผ ํ†ตํ•ด cell์€ ์ง„์ž‘์— subscriptions ์ดˆ๊ธฐํ™” ํ–ˆ์ง€๋งŒ delegate๊ด€๋ จ์€ ํ•ด์ฃผ์ง€ ๋ชปํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค. ใ…‹ใ…‹,, ๊ทผ๋ฐ ์‹ฌ์ง€์–ด cancellables๋Š” Set์— ์ €์žฅ์‹œ์ผœ์„œ delegate๊ด€๋ จ publihser์˜ cancellable๋Š” ์ฐพ๊ธฐ ํž˜๋“ค์—ˆ๋‹ค.

แ„‹แ…ฆ11

๊ทธ๋ž˜์„œ ๋Œ€์•ˆ์ฑ…์œผ๋กœ ํ”„๋กœํผํ‹ฐ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ณ€์ˆ˜ ๋ช…์„ ๋ถ„๋ช…ํ•˜๊ฒŒ ํ–ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ฃ„๋‹ค subsciriptions์—ฌ์„œ ์ •๋ง ํ–ˆ๊ฐˆ๋ฆฐ๋‹ค. ์ข‹์€ ๊ฒฝํ—˜์„ ํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

แ„‹แ…ฆ12

๊ทธ๋ฆฌ๊ณ  ์žฌ์‚ฌ์šฉํ์—์„œ setupNotificationCellDelegateํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค delegateSubscription์„ ์ƒˆ๋กœ์šด send๋กœ๋ถ€ํ„ฐ holdingํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ฐ”๊ฟ”์„œ ์ƒˆ๋กœ delegate๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ๋‹ค์‹œ delegateSubscription์ด ์ƒˆ๋กœ์šด ๊ฑฐ๋กœ ๋ฎ์–ด์ง€๋„๋ก ํ•จ์œผ๋กœ ์—๋Ÿฌ๋ฅผ ๊ณ ์ณค๋‹ค.

แ„‹แ…ฆ13

๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ ํ™”๋ฉด ๋‚˜ํƒ€๋‚ ๋•Œ, reloadTableView๋กœ ํ…Œ์ด๋ธ” ๋ทฐ ๋ฐ์ดํ„ฐ๋“ค ๋‹ค์‹œ ๊ฐฑ์‹ ๋  ๋•Œ๋„ ํ•ด์ฃผ์—ˆ๋‹ค ๊ฑฐ์˜ ๋ชจ๋“  ์ƒํ™ฉ์— ๋Œ€๋น„๋ฅผ ํ–ˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค!! ํ›„..

๊ณ ๋ฏผ๊ฑฐ๋ฆฌ..

์ดˆ๊ธฐํ™” ๊ด€๋ จ..

ํด๋กœ๋Š” capture ์„ฑ๊ฒฉ์ด๋‹ค. ํŠนํžˆ lazy var ๋ฅผ ๋‚จ์šฉํ•  ๊ฒฝ์šฐ ์ข‹์ง€ ์•Š์ง€๋งŒ viewController์‹œ์ ์—์„  view๊ฐ€ load๋˜๊ธฐ ์ด์ „์— addTarget์„ ํ†ตํ•ด ๋ฉ”์„œ๋“œ๋ฅผ ๋“ฑ๋กํ•  ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ์ ์šฉ์ด ์•ˆ๋˜์„œ lazy var ํ‚ค์›Œ๋“ค๋ฅด ์‚ฌ์šฉํ•œ๋‹ค.

๋ฐ˜๋ฉด ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ ๋˜์–ด์•ผ ์‚ฌ์šฉ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ข…๋ฃŒ์‹œ์ ์ด ๋ถ„๋ช…ํ•˜๋‹ค(async๋ฅผ ์“ฐ์ง€์•Š๋Š”ํ•œ)

์ข€ ๋” ์—ฐ๊ตฌํ•ด๋ด์•ผํ•œ๋‹ค.

swift ๊ณต์‹๋ฌธ์„œ์—๋Š” ํด๋กœ์ €๋กœ ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™”๊ฐ€ ์—†๋‹ค. ๋‹ค ์„ ์–ธ ํ›„ init๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์œ ๋ช…ํ•œ ์ฑ…์—์„œ๋„ ํด๋กœ์ €๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™”๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

แ„Žแ…ฉแ„€แ…ตแ„’แ…ช

์›๋ž˜์˜ ๊ฒฝ์šฐ ํด๋ž˜์Šค์˜ ์ƒ๋‹จ๋ถ€์— ๋ณ€์ˆ˜ ์„ ์–ธ + ์ดˆ๊ธฐํ™”, init๋ฉ”์„œ๋“œ ์•ˆ ์ดˆ๊ธฐํ™”. ํด๋ž˜์Šค ์ƒ๋‹จ๋ถ€์— ์„ ์–ธํ•˜์ž๋งˆ์ž ๋ฐ”๋กœ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•จ์œผ๋กœ ํด๋ž˜์Šค ์ƒ๋‹จ๋ถ€๋ฅผ ๊ฐ„๋žตํ•˜๊ฒŒ ํ•ด์„œ ๋ณ€์ˆ˜๋“ค์„ ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค.๊ทธ๋Ÿฐ๋ฐ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด init() ๋ฉ”์„œ๋“œ๊ฐ€ ์‹œ์ž‘์ด ์•ˆ๋œ, ์ดˆ๊ธฐํ™”๊ฐ€ ๋˜์ง€ ์•Š์€ ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์กฐ๊ฑด์ด ์žˆ๋‹ค.

์ „์—ญ ํ•จ์ˆ˜์ธ๊ฐ€? or ํ•ด๋‹น ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜์ธ๊ฐ€? ์ด๋•Œ ํ•ด๋‹น ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜์ธ ๊ฒฝ์šฐ init()๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜๊ธฐ ์ด์ „ ์ด๋ผ๋ฉด ํด๋ž˜์Šค ๋‚ด ๊ตฌํ˜„ํ–ˆ๋˜ ํ•จ์ˆ˜๋“ค์€ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค.(ํด๋ž˜์Šค๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ,.,.)

์™œ?

A ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ๋ณ€์ˆ˜๋“ค์„ ์ดˆ๊ธฐํ™” ํ•˜๊ธฐ ์œ„ํ•ด A ํด๋ž˜์Šค ๋‚ด๋ถ€์— ํŠน์ • ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ์ด ์ดˆ๊ธฐํ™” ์ „์šฉ ํ•จ์ˆ˜๋“ค์€ A ๊ฐ์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น ๋˜์–ด์•ผ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋ž˜์„œ ๋‚œ static ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ–ˆ๋‹ค. Static์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด A ํ”„๋กœํผํ‹ฐ์˜ ์ดˆ๊ธฐํ™”๊ฐ€ ์—†์–ด๋„ ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. Staticํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด object's ๋ฉ”๋ชจ๋ฆฌ์— ๊ณง๋ฐ”๋กœ ํ• ๋‹น๋˜๊ณ  A ์ธ์Šคํ„ด์Šค ์—†์ด๋„ ๋ฐ”๋กœ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Static ํ‚ค์›Œ๋“œ๋Š” ๋„คํŠธ์›Œํฌ ํŒŒ์‹ฑ์— ํ•„์š”ํ•œ ํ•จ์ˆ˜ ๋“ฑ์„ ํด๋ž˜์Šค ์•ˆ์— ๊ตฌ์กฐํ™” ํ•ด์„œ ์„ ์–ธํ•  ๋•Œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๋„๋ก Static ํ‚ค์›Œ๋“œ๋ฅผ ์„ ์–ธํ•ด์„œ ์‚ฌ์šฉํ–ˆ๋‹ค. (Like singleton pattren) ? ์—ฐ์†์ ์œผ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ๊ทธ๋งŒ ํผ ๊ฐ™์€ ํ”„๋กœํผํ‹ฐ, ํ•จ์ˆ˜๋“ค์ด ๋ฉ”๋ชจ๋ฆฌ์— ์Œ“์ด๋Š”๋ฐ static์„ ์‚ฌ์šฉํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  static์œผ๋กœ ์ง€์ •๋œ ํ•จ์ˆ˜๋“ค๋งŒ ๋ฉ”๋ชจ๋ฆฌ์— allocate๋˜๊ธฐ์— ๋ฉ”๋ชจ๋ฆฌ ๋ฆญ์„ ์ค„์ผ ์ˆ˜์žˆ์ง€ ์•Š์„๊นŒ..์ƒ๊ฐํ•œ๋‹ค.

แ„Žแ…ฉแ„€แ…ตแ„’แ…ช2

๊ทธ๋•Œ๋ฌธ์— ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ–ˆ๋‹ค. ) ์œ„ ๊ทธ๋ฆผ์—์„œ ๋ณ€์ˆ˜๋“ค์„ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์„ ์–ธ๋œ initProfileImageView()... ๋“ฑ์˜ ํ•จ์ˆ˜๋“ค ๋˜ํ•œ static์œผ๋กœ ๊ตฌํ˜„๋ฌ๋‹ค. ์ด ์ด๋ฏธ์ง€ ๋ทฐ, username, fullname label๋“ฑ์„ ๊ฐ–๋Š” UIView๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ์„ ์–ธํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ๋•Œ static ํ‚ค์›Œ๋“œ๋กœ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๋ฉด (์–ด์ฐจํ”ผ ์ดˆ๊ธฐํ™” ๋•Œ ํ•œ๋ฒˆ ์“ฐ์ด๋Š” ํ•จ์ˆ˜๋“ค,,) ๋ฉ”๋ชจ๋ฆฌ์— ์—ฐ์†์ ์œผ๋กœ ํ•จ์ˆ˜๊นŒ์ง€ allocate๋˜์ง€ ์•Š๊ณ  ๋‹จ ํ•œ๋ฒˆ ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํด๋กœ์ €๋ฅผ ํ†ตํ•ด ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™” ํ•  ๋•Œ๋Š” ์„ ์–ธํ•œ { } ํ˜•ํƒœ์˜ ํด๋กœ์ €๋ฅผ "( )"๋ฅผ ํ†ตํ•ด ํด๋กœ์ € ์‹คํ–‰ ์‹œ์ผœ์•ผํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  init()๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ด์ „ return์„ ํ†ตํ•ด ํŠน์ • ํƒ€์ž…์˜ object๋ฅผ ์ •ํ•˜๋Š” ํด๋กœ์ €์™€ ()๋Š” init๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „ ์‹œ์ ์— ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทผ๋ฐ ํด๋กœ์ €๋Š” ์ผ๊ธ‰ ๊ฐ์ฒด ํ•จ์ˆ˜์ด๋‹ค. ์–ด๋–ค ๊ฐœ์ฒด์™€๋„ ์ƒํ˜ธ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. return์„ ํ†ตํ•ด ๋ฐ˜ํ™˜๋œ ๊ฐ’์˜ ํƒ€์ž… ์ถ”๋ก ์„ ํ†ตํ•ด ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.

ํด๋กœ์ €๋Š” ํŠน์ • ๋ฒ”์œ„ ๋‚ด ๋ณ€์ˆ˜๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  capture์˜ ํŠน์ง•์ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์บก์ณ๋Š” ์™ธ๋ถ€์˜ ๋ณ€์ˆ˜์— ๊ฐ’์„ ์‚ฌ์šฉํ•  ๋•Œ๋งŒ ์บก์ณ๋ฅผ ํ•œ๋‹ค. ARC ๋Š” reference type์ผ ๋•Œ ์ž‘๋™ํ•˜๋Š”๋ฐ ์ค‘์š”ํ•œ ๊ฒƒ์€ ํด๋กœ์ €๋Š” reference type์ด๋‹ค.

์ผ๊ธ‰ ๊ฐ์ฒด๋ฅผ ์ง€์›ํ•˜๋Š” Swift ์Šคํƒ€์ผ์ด ํด๋ž˜์Šค ๋‚ด ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™” ์‹œ์ ์—๋„ ์„ ํ˜ธํ• ๊นŒ? ์ดˆ๊ธฐํ™” ๊ณต์‹๋ฌธ์„œ์—๋Š” ํด๋กœ์ €๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๋Š” ๊ตฌ๋ฌธ์ด ์—†๋‹ค.. .... ๋‚ด ์Šคํƒ€์ผ์€ ๋ณ€์ˆ˜๋“ค์„ ํ™•์ธํ•˜๊ณ  ๊ด€๋ จ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ€์ˆ˜๋“ค์„ ํ•œ ๋ˆˆ์— ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ํ•ด์•ผํ•œ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ํด๋กœ์ €๋ฅผ ํ†ตํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•  ๋• ํด๋กœ์ €์˜ ๋‚ด๋ถ€์— ํŠน์ • ํ”„๋กœํผํ‹ฐ๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ๋“ค์ด ๊ธธ๊ฒŒ ๋Š˜์–ด์งˆ ์ˆ˜ ์žˆ๋‹จ์ ์ด๊ณ  ํ”„๋กœํผํ‹ฐ๋ฅผ ์•Œ๊ธฐ ์ƒ๋Œ€์ ์œผ๋กœ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ถ€๋ถ„๋งŒ ๋”ฐ๋กœ ๋บ€๋‹ค๋ฉด ๋“ค์‘ฅ ๋‚ ์‘ฅํ•ด์งˆ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿผ์—๋„ ์„ ์–ธ๊ณผ ๋™์‹œ์— ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๋Š” ํด๋กœ์ €๋Š” ๋งค๋ ฅ์ ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๋‚ด๊ฐ€ ํ–ˆ๋˜ static์„ ์“ฐ๋Š” ๋ฐฉ๋ฒ•์€ ์ข‹์€ ๋ฐฉ๋ฒ•์ผ๊นŒ ์ƒ๊ฐ์„ ํ•ด๋ดค๋‹ค. ์ผ๋‹จ ๋‹ค๋ฅธ ํด๋ž˜์Šค์—๋„ ๊ฐ™์€ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ static ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด? ๋ฌผ๋ก  ํ•ด๋‹น static ํ•จ์ˆ˜๊ฐ€ ์ด๋ฆ„์ด ๊ฐ™์•„๋„ ํด๋ž˜์Šค ์•ˆ์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹๋ณ„์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•˜์ง€๋งŒ ํŠน์ • ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ static func ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๊ณ  ํ˜ผ๋ž€์Šค๋Ÿฌ์› ๋‹ค... ๋ฌผ๋ก  static์˜ ์žฅ์ ์€ ๊ทธ๋Ÿผ์—๋„ ํ•œ๋ฒˆ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ ๋œ ์ด์ƒ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ 4๊ฐœ ๋งŒ๋“ ๋‹ค๊ณ  ํ–ˆ์„๋•Œ๋„ static type์€ ์ค‘์ฒฉ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค.

๊ทธ๋ž˜๋„ ๊ณ„์†ํ•ด์„œ ์ฐพ์•„๋ดค๋Š”๋ฐ ์ข‹์€ ๋ฐฉ์•ˆ์„ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ๋‹ค,, ๊ณ„์†ํ•ด์„œ ์ฐพ์•„๋ณด๋‹ค๊ฐ€ ํด๋กœ์ €๋ฅผ ํ†ตํ•œ lazy var๋Š” thread unsafetyํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ UIButton์„ ์ดˆ๊ธฐํ™” ํ•  ๋•Œ ํด๋กœ์ €๋ฅผ ํ†ตํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด, init()๋ฉ”์„œ๋“œ ์ด์ „์— ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ๋‹ค๋Š” ๋ง์ด๋‹ค. ์•„์ง self ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. init() ํ˜ธ์ถœ ์‹œ์  ์ „ ์ด๋‹ˆ๊นŒ,, ๊ทธ๋ ‡๋‹ค๋Š” ๊ฒƒ์€ func, @objc action method๋„ ์‚ฌ์šฉ์ด ๋‹น์—ฐํžˆ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ทธ๋Ÿผ ํด๋กœ์ €๋ฅผ ํ†ตํ•œ ๋ณ€์ˆ˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ์—์„œ ํด๋กœ์ € ์•ˆ์— ๋ฒ„ํŠผ์— addTarget์„ ํ†ตํ•ด ํด๋ž˜์Šค ๋‚ด์— ์žˆ๋Š” ์•ก์…˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ง€์ •ํ•˜๋ฉด init()์‹œ์ ์ด ์•„๋‹ˆ๊ธฐ์— ๋ฉ”๋ชจ๋ฆฌ์— ํด๋ž˜์Šค์˜ func, @objc func ๊ฐ€ ํ• ๋‹น๋˜์ง€ ์•Š์•˜์Œ์œผ๋กœ ์•ก์…˜๋ฉ”์†Œ๋“œ๊ฐ€ ๋“ฑ๋ก๋˜์ง€ ์•Š์•„ lazy๋ฅผ ์„ ์–ธํ•จ์œผ๋กœ init()์ดํ›„์— @objc func๋ฅผ addTarget์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด์„œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ๋‹ค.

์ด๋Ÿฐ lazy๋ฅผ ์“ฐ๋ฉด ์ข‹์ง€ ์•Š๋‹ค๋‹ˆ?! ๊ทธ๋ž˜์„œ ๊ณ„์†ํ•ด์„œ ์ฐพ์•„๋ณด์•˜๋‹ค. ใ… ;
์Šคํ† ๋ฆฌ๋ณด๋“œ ์‚ฌ์šฉํ•  ๋•Œ UI object๋ฅผ ํด๋ž˜์Šค์— ๋“œ๋ž˜๊ทธํ•˜๋ฉด ์•„์šธ๋ › ๋ณ€์ˆ˜๊ฐ€ ์„ ์–ธ๋˜๋Š”๋ฐ ๊ฐ•์ œ ์˜ต์…”๋„ ํƒ€์ž…์ด๋‹ค. weak var๊ฐ€ ์•„๋‹Œ ์ด์ƒ,, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ๊ธ€์„ ๋ดค๋Š”๋ฐ UIViewController์—์„œ ์‚ฌ์šฉ๋˜๋Š” UIํ”„๋กœํผํ‹ฐ๋“ค์€ ๊ฑฐ์˜ ์‚ฌ์šฉ๋œ๋‹ค. ๊ทธ๋ž˜์„œ "!"๋ฅผ ์“ฐ๋Š”๋ฐ ์ด๋Š” init()์ดํ›„์— ์ดˆ๊ธฐํ™”๊ฐ€ ๋จ์œผ๋กœ lazy๋ฅผ ์“ฐ์ง€ ์•Š์•„๋„ ์œ„์™€๊ฐ™์€ lazy var ํด๋กœ์ € ๊ตฌ๋ฌธ or ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค๊ณ  ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์ผ๋‹จ ์š” ๋ฐฉ์‹์œผ๋กœ ์„ ํƒํ–ˆ๋‹ค.

แ„Žแ…ฉแ„€แ…ตแ„’แ…ช9

๋ณ€์ˆ˜๋“ค์„ ๋ฐ”๋กœ ํ™•์ธ ํ•  ์ˆ˜์žˆ์–ด ์ข‹๋‹ค.
init๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๊น”๋”ํ•˜๊ฒŒ ์ดˆ๊ธฐํ™” ํ•  ์ˆ˜ ์žˆ๋”ฐ.

์ผ๋‹จ let, var, ํด๋กœ์ €, ARC, retain ๋“ฑ ์ดˆ๊ธฐํ™”์— ๊ด€ํ•œ ๊ณต๋ถ€๋ฅผ ๋” ํ•œ ํ›„ ์ •๋ฆฌ ํ•ด์•ผ๊ฒ ๋‹ค...


แ„แ…ฅแ„‰แ…ณแ„แ…ฅแ†ท แ„†แ…กแ†ซแ„ƒแ…ณแ†ฏแ„€แ…ตแ„Œแ…ฅแ†ซ แ„‡แ…กแ†ฏแ„ƒแ…กแ†ซ

lazy var ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ๋•Œ ์„ ์–ธ๋œ ๋ณ€์ˆ˜์˜ ๊ธฐ๋Šฅ์„ ์ง€์ •ํ•˜๋Š” ํ•จ์ˆ˜๋‹ค. ๊ทผ๋ฐ followButton์„ ๋„ˆ๋ฌด ๊ณ„์† ์จ์„œ ํด๋กœ์ €๋ฅผ ํ†ตํ•ด ์บก์ณ๋˜๋Š” ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉด ์ข‹์ง€ ์•Š์„๊นŒ ์ƒ๊ฐํ–ˆ๊ณ 

แ„แ…ฅแ„‰แ…ณแ„แ…ฅแ†ท แ„’แ…ฎ

UtilsUI ์•ˆ์— setupLayout์ด๋ผ๋Š” ์ปค์Šคํ…€ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํด๋กœ์ €๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค. ์‰ฝ๊ฒŒ $0์œผ๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ํ–ˆ๋‹ค

[Clone/Instagram] ์ดˆ๊ธฐ tabBar์™€ ViewControllers ์„ธํŒ… | ๋ณต์Šต & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋… #1

์ดˆ๊ธฐ ์„ธํŒ…


  • ๊ฐ•์˜์—๋Š” ์ž๋™์œผ๋กœ navigation์ด๋ž‘ tabBar ์ƒ‰์ด ์ž๋™ ์ ์šฉ ๋˜์—ˆ๋Š”๋ฐ ๋‚œ ํฐ์ƒ‰์œผ๋กœ ์ ์šฉ์ด ์•ˆ๋˜์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ appearance๋กœ white์ƒ‰์„ ์ •ํ–ˆ๋‹ค.

  • ํƒญ๋ฐ”์˜ viewControllers๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค.


๋ณต์Šตํ•œ ๋‚ด์šฉ

  • navigationController ์ธ์Šคํ„ด์Šค์˜ .tabBarItem์€ ํƒญ๋ฐ”๊ฐ€ ๋“ฑ๋ก๋˜์—ˆ์„ ๊ฒฝ์šฐ์— ํ•œํ•ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ƒˆ๋กญ๊ฒŒ ๊ณต๋ถ€ํ•œ ๊ฐœ๋…

  • TintColor : ํ„ฐ์น˜ํ–ˆ์„ ๋•Œ ์ž ๊น(ํ„ฐ์น˜ ๋˜์—ˆ์Œ์„ ํ‘œ์‹œํ•˜๊ฑฐ๋‚˜) or ํ„ฐ์น˜์‹œ์— ํ™”๋ฉด์— ์ง€์†์ ์œผ๋กœ (๋‚˜ ํ„ฐ์น˜์ค‘์ด๋‹ค?) ๋ณด์—ฌ์ง€๊ฒŒ ๋  ์ƒ‰์ƒ์„ ์ •ํ•œ๋‹ค. UIView๋ฅผ ์ƒ์†๋ฐ›๋Š” ๋ญ๋“  ์ •ํ•  ์ˆ˜ ์žˆ๊ณ  ์ด๋ฏธ์ง€์˜ ๊ฒฝ์šฐ renderMode ์˜ต์…˜์„ .alwaysTemplate๋กœ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค.

[Clone/Instagram] CommentController ์ฑ„ํŒ… ๊ธฐ๋Šฅ ์ถ”๊ฐ€ & ๊ฐœ๋… ์ •๋ฆฌ(UIResponder) #14 - 2

์ฑ„ํŒ… ๊ธฐ๋Šฅ ๊ตฌํ˜„

  • ๊ตฌํ˜„ ํ˜•์ƒ

์ฑ„ํŒ… ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๊ณผ์ • ๋ฆฌ๋ทฐ

TODO: ์ƒ๋Œ€๋ฐฉ ํฌ์ŠคํŠธ์˜ ํ•˜๋‹จ comment ํด๋ฆญ์‹œ ํŠน์ • ํฌ์ŠคํŠธ์— ๋Œ€ํ•œ ์ฑ„ํŒ… ๊ธฐ๋Šฅ ๊ตฌํ˜„

  • CommentService //Global
  • CommentController //Controller
  • CommentModel //Model
  • CommentViewModelProtocols //ViewModel
  • CommentViewModel //ViewModel
  • InputTextView //VIew
  • CommentInputAccessoryView //View
  • CommentCell //View

1. ์ฑ„ํŒ… UI

์œ„ ์‚ฌ์ง„์€ CommentController์˜ Scene์ด๋‹ค.

CommentController๋ฅผ ํ™”๋ฉด์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉด tabBar๋ฅผ ์ˆจ๊ธฐ๊ณ  ์ปค์Šคํ…€ view์ธ CommentInputAccessoryView๊ฐ€ ํ™”๋ฉด์˜ ํ•˜๋‹จ์— ๋‚˜์˜จ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž์˜ ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ, Post ์ „์†ก ๋‘ ๊ฐœ์˜ ๊ฐ์ฒด๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ…์ŠคํŠธ๋Š” CollectionViewFlowLayout์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.๊ทผ๋ฐ TableView๋กœ ์ถ”ํ›„ ๋ฆฌํŽ™ํ„ฐ๋งํ•  ๊ฒƒ์ด๋‹ค. cell์˜ width๋ฅผ ๋ทฐ์˜ ํฌ๊ธฐ์— ๋งž์ถฐ์„œ ๋ ˆ์ด์•„์›ƒ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

2. upload comment, fetch comment

์‚ฌ์šฉ์ž๊ฐ€ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•œ ํ›„์— Post๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฒŒ ๋˜๋ฉด CommentInputAccessoryView์˜ ๋‚ด๋ถ€ post ํ”„๋กœํผํ‹ฐ์˜ ์ด๋ฒคํŠธ ํ—จ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด handlingํ–ˆ๋‹ค. ์ž…๋ ฅํ•œ comment๋Š” ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ์—…๋กœ๋“œ ํ›„ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ํŠน์ • post์˜ comment ์ปฌ๋ž™์…˜์˜ ๋ฌธ์„œ ์ถ”๊ฐ€ ํ›„ fetchํ•  ๋•Œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค ์˜ต์ €๋ฒ„ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ ์ž๋™์œผ๋กœ ์ปฌ๋ž™์…˜ ๋ทฐ ์…€์„ ๊ฐฑ์‹ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ CommentInputAccessoryView๊ฐ€ UIView์ธ ๊ฒƒ์ด๋‹ค. CommentController์˜ navigation์„ ์ธ์Šคํ„ด์Šค๋กœ ๊ฐ–๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋กœ CommentController์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

แ„แ…ณ3

(Firebase data model relation)

แ„แ…ณ5

ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์—ฌ๋Ÿฌ ์ปฌ๋ž™์…˜ ์ค‘ posts data model entiry๋Š” ๋ชจ๋“  ์œ ์ €๊ฐ€ ์˜ฌ๋ฆฐ post๋ฅผ ์ €์žฅํ•œ๋‹ค. posts ์ปฌ๋ž™์…˜์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฌธ์„œ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ด๋•Œ ๊ฐ๊ฐ์˜ ๋ฌธ์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์˜ฌ๋ฆฐ post์ •๋ณด๊ฐ€ ๋œ๋‹ค.

แ„แ…ณ6

ํŠน์ • ๋ฌธ์„œ๋ฅผ ํด๋ฆญํ•˜๋ฉด ํ•„๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ํ•„๋“œ์— post ์ •๋ณด๊ฐ€ ๋‹ด๊ธด๋‹ค. ์ด ๋ฟ ์•„๋‹ˆ๋ผ comemnts ์ปฌ๋ž™์…˜์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. comments ์ปฌ๋ž™์…˜์—์„œ๋Š” ํŠน์ • post์— ๋Œ€ํ•ด comment๋ฅผ ๋‚ ๋ฆฐ user์˜ ๋ฌธ์ž์™€ ํŠน์ • ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋‹ค.

แ„แ…ณ4

๋งจ ์ฒ˜์Œ CommentController๊ฐ€ ์ดˆ๊ธฐํ™” ๋  ๋•Œ viewModel์—์„  fetchComments() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ํŠน์ • ํฌ์ŠคํŠธ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ž‘์—…์„ observeํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ ํŠน์ • post-> comments์—์„œ ์‚ฌ์šฉ์ž์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ addSnapshotListener ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด fetch๋ฅผ ๋ฐ”๋กœ๋ฐ”๋กœ ํ•  ์ˆ˜ ์žˆ๋‹ค. ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์ง€์›ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ธ๋ฐ ์ •๋ง ์ง„์งœ ์‹ ๊ธฐํ–ˆ๋‹ค.

แ„แ…ณ7

์ดˆ๊ธฐ viewModel init์—์„œ fetchComments()๋ฅผ ํ†ตํ•ด comment ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ›์•„์˜ด๊ณผ ๋™์‹œ์— ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ addSnapshotListener๋ฅผ ํ†ตํ•ด new comment ๊ฐ€ ๊ฐ์ง€ ๋˜๋ฉด viewModel์˜ comments ๋ฆฌ์ŠคํŠธ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•จ๊ณผ ๋™์‹œ์— newComment publisher์—๊ฒŒ input stream์„ ์ „์†กํ•˜๊ณ  transform(input:) ๋ฅผ ํ†ตํ•ด CommentController์˜ state ์ค‘ cell์„ ๊ฐฑ์‹ ํ•œ๋‹ค.

  1. ๋‹ค์ด๋‚˜๋ฏน ์…€

CommentCell์˜ label์— ๋Œ€ํ•ด commentLabel.numberOfLines = 0์œผ๋กœ ํ•จ์œผ๋กœ์จ ๋‹ค์ด๋‚ด๋ฏนํ•œ height๋ฅผ ์„ค์ •ํ–ˆ๋‹ค.


์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ์ 

UIViewํƒ€์ž…์˜ view๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  auto layout์„ ์ง€์ •ํ•œ ๊ฒฝ์šฐ ์ด๋ฅผ Controller์—์„œ ์‚ฌ์šฉํ•  ๋•Œ ๋ทฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

์ƒˆ๋กœ ๊ณต๋ถ€ํ•œ ๊ฐœ๋…

NSMutableAttributedString vs NSAttributedString

์ด์ „์—๋„ ๊ณต๋ถ€ํ–ˆ๋Š”๋ฐ ๊นŒ๋จน์–ด์„œ ํ™•์‹คํ•˜๊ฒŒ ๋ณต์Šตํ–ˆ๋‹ค.

[Clone/Instagram] Login Scene ๊ตฌํ˜„ | ๋ณต์Šต & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋… #3

Login Scene ๊ตฌํ˜„

๊ฐ•์˜๋ฅผ ๋ณด๊ธฐ์ „์— ํ˜ผ์ž ๊ตฌํ˜„ํ•ด๋ดค๋‹ค. ๋‚œ ๊ทธ๋ƒฅ anchor๋กœ ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ ๊ฐ•์˜์—์„  email, password, login๋ฒ„ํŠผ ๋‹คstackview๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค. ๋‚œ ๊ทธ ์•„๋ž˜ ์ž‘์€ ๊ธ€์”จ๋“ค๋งŒ stackView๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๋กœ๊ทธ์ธ ํ•  ๋•Œ ์ดˆ๊ธฐ์— navigationBar๋ฅผ ์ˆจ๊ธฐ๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ƒˆ๋กญ๊ฒŒ ์•Œ์•˜๋‹ค.. ๊ทธ๋ผ๋””์–ธํŠธ๋Š” ๋‚ด๊ฐ€ ๋ง˜์— ๋“œ๋Š” ์ƒ‰์œผ๋กœ ์ •ํ–ˆ๋‹ค!!

๊นŒ๋‹ค๋กœ์› ๋˜ ์ 

  • UITextField์˜ margin์€ ์–ด๋–ป๊ฒŒ ์ค˜์•ผํ•˜๋Š”๊ฐ€?

์›๋ž˜ view์— ๋งˆ์ง„์„ ์ค„ ๋•Œ๋Š” layoutMargins์˜ ๊ฐ’์œผ๋กœ UIEdgeInsets()๋ฅผ ์ ์šฉํ–ˆ๋Š”๋ฐ textField๋Š” ๋˜์ง€ ์•Š์•˜๋‹ค. ๊ทธํ›„๋กœ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์‚ดํŽด๋ณด๋‹ˆ editing ์–‘ ์˜†์— overlay view๋กœ leftView, rightView๊ฐ€ ์กด์žฌํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. ์ •๋ฆฌ ์ฐจ์›์—์„œ ๊ธ€์„ ์ž‘์„ฑํ–ˆ๋‹ค.

๋ณต์Šตํ•œ ๊ฐœ๋…

  • lazyํ‚ค์›Œ๋“œ๋Š” ์–ธ์ œ ์จ์•ผํ•˜๋Š”๊ฐ€?

lazyํ‚ค์›Œ๋“œ๋Š” ์ธ์Šคํ„ด์Šค์˜ ์ดˆ๊ธฐํ™”๋ฅผ ๋Šฆ์ถœ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๊ธฐ์— ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ›จ์”ฌ ์ ˆ์•ฝํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. lazy๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜๋Š” ์‹œ์ ์€ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์‹œ์ ์ด๋‹ค. ํด๋กœ์ €๋ฅผ ํ†ตํ•ด์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š๊ณ  @NoEscape๊ฐ€ ์ ์šฉ๋œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๋ฅผ lazyํ‚ค์›Œ๋“œ๋กœ ์จ์•ผํ• ๊นŒ?

์Œ.. ์›๋ž˜ ํด๋ž˜์Šค ๋˜๋Š” ๊ตฌ์กฐ์ฒด์˜ ์ดˆ๊ธฐํ™”๋Š” ๋ณ€์ˆ˜๋“ค์„ ํ›“์€ ๋‹ด์—( ๋ณ€์ˆ˜ ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ์ดˆ๊ธฐํ™” ๋˜๋Š” ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š”์ง€?) init() ์ƒ์„ฑ์ž ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด thread๋Š” ๋ณ€์ˆ˜๋“ค์˜ ์ดˆ๊ธฐํ™”๋ฅผ ์ง„ํ–‰ํ•˜๋Š”๋ฐ lazy์˜ ๊ฒฝ์šฐ ๋ณ€์ˆ˜๋Š” ์ดˆ๊ธฐ์— ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ thread safety๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ staticํƒ€์ž…์ธ ์ •์ ์œผ๋กœ ์„ ์–ธํ•ด์•ผ ๋ณ€์ˆ˜์˜ ์ดˆ๊ธฐํ™”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•˜์ง€๋งŒ lazy์˜ ๊ฒฝ์šฐ ํด๋ž˜์Šค ๋‚ด ๋ณ€์ˆ˜๋“ค์˜ ์ดˆ๊ธฐํ™” ์‹œ์ ์— ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š๊ธฐ์— static ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋™์‹œ์„ฑ์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ƒํ™ฉ์—์„œ๋Š” lazy var ๋ณ€์ˆ˜์„ ์–ธ์ด ์˜ณ์€๊ฐ€? ์‹œ๊ฐ„ ๋‚ด์„œ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ •๋…ํ•ด๋ด์•ผ๊ฒ ๋‹ค..

๊ทธ๋ ‡๋‹ค๋ฉด ์ง„์งœ๋กœ ์–ธ์ œ ์จ์•ผํ•˜๋Š”๊ฐ€?

์ด ๊ฐ•์˜๋ฅผ ๋ณด๋ฉด์„œ ์•Œ๊ฒŒ ๋ฌ๋Š”๋ฐ ๋ฒ„ํŠผ์˜ ๊ฒฝ์šฐ addTarget์‹œ์— self ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. ๊ทผ๋ฐ ์ด๊ฒƒ์€ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ์™„์ „ํžˆ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋ฒ„ํŠผ ๋ณ€์ˆ˜์˜ ์„ ์–ธ๊ณผ ๋™์‹œ์— ์ดˆ๊ธฐํ™”๋ฅผ ํ•  ๋•Œ addTarget์˜ self๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค lazyํ‚ค์›Œ๋“œ๋ฅผ ์„ ์–ธํ•ด ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ์™„์ „ํžˆ ์ดˆ๊ธฐํ™” ๋œ ์ดํ›„์— ๋ฒ„ํŠผ์— ๋Œ€ํ•œ ์ดˆ๊ธฐํ™”์—์„œ addTarget(self...)๊ฐ€ ๋“ค์–ด๊ฐ€๋Š”๊ฒŒ ๋ฐ”๋žŒ์งํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

์ด ๋ง๊ณ ๋„ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ์ผ์–ด๋‚  ์ƒํ™ฉ์˜ ํด๋ž˜์Šค์˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•ด์„œ๋„ lazyํ‚ค์›Œ๋“œ๋ฅผ ์„ ์–ธํ•ด๋„ ์ข‹๋‹ค. ๋˜ํ•œ ์„œ๋ฒ„์—์„œ ๋‹ค๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€์•ผํ•  ๊ฒฝ์šฐ์—๋„ ๋ทฐ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— ๋ฐ”๋กœ ๋‹ค๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ๋ณด๋‹ค ์‚ฌ์šฉ์ž์˜ ์•ก์…˜์— ์˜ํ•ด ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก lazy ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋…

  • CAGradientLayer

์•ˆ๋“œ๋กœ์ด๋“œ์—์„  ์ดˆ๋ฐ˜์— ๋ฐฐ์› ์—ˆ๋Š”๋ฐ ๊ทธ๋ผ๋””์–ธํŠธ ๋„ฃ๋Š” ๋ฐฉ๋ฒ•์„ ios๊ณต๋ถ€ํ•œ์ง€ ์•ฝ 7๊ฐœ์›”๋งŒ์— ์ ‘ํ•˜๊ฒŒ ๋๋‹คใ„ทใ„ท...

  • .backgroundColor = .init(white: 1, alpha: 0.1)

UIView์˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋ฅผ ์œ„์™€๊ฐ™์ด ์ •ํ•˜๋ฉด superView์˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒ‰๊ณผ ์ž˜ ์–ด์šธ๋ฆฌ๋„๋ก ๋œ๋‹ค.

[Clone/Instagram] โญ์ „์ฒด์ ์ธ MVVM Architecture Pattern ๋ฆฌํŽ™ํ„ฐ๋ง with combine. | ๋งˆ์ฃผํ•œ ์—๋Ÿฌ, ๋ฌธ์ œ & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋… & ๊ฐœ์„ ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ & ๋Š๋‚€์  #12

TODO : adopt MVVM with combine

์ด๋ฒˆ์— ํ•ด๋ณผ ๊ฒƒ์€ Combine์„ ํ†ตํ•ด MVVM์„ ๋ถ„๋ฆฌ with DI. ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด adoptCombineWithMVVMBranch ์ด ๋ธŒ๋žœ์น˜์—์„œ ๋ฆฌํŽ™ํ† ๋ง์„ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋‹ค.

ํด๋ฆฐ์ฝ”๋“œ, ๊ฐ€๋…์„ฑ, DI ๋ฅผ ๊ณ ๋ คํ•œ ์ฝ”๋“œ๋ฅผ ์งœ๋„๋ก ๊ณ ๋ฏผ์„ ๋งŽ์ด ํ•˜๋ฉด์„œ ๋ฆฌํŽ™ํ„ฐ๋ง์„ ํ–ˆ๋‹ค.

์ƒˆ๋กœ ๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ, ๊ธฐ๋Šฅ ๊ฐœ์„ 

  • ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ Combine, MVVM ์ ์šฉ

RegistrationViewModel RegistrationController commit log etc..

  • ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ Combine, MVVM ์ ์šฉ

LoginController, LoginViewModel commit log etc...

  • ํ”„๋กœํ•„ ๊ด€๋ จ Combine, MVVM ์ ์šฉ

ProfileController, ProfileHeader, ProfileHeaderViewMdoel commit log etc...

SearchViewModelProtocols

SearchViewModel

๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๋ฆฌํŽ™ํ„ฐ๋ง ์ค‘ ๋งˆ์ฃผํ•œ ๋ฌธ์ œ 1

TextField.publiser(for:)๋ฅผ ์‚ฌ์šฉํ–ˆ์œผ๋‚˜ ํ…์ŠคํŠธ ์˜์—ญ์„ ๋ฒ—์–ด๋‚˜์•ผ๋งŒ publish ๋˜๋Š” ๊ฒฝ์šฐ

แ„…แ…ฉแ„€แ…ณแ„‹แ…ตแ†ซ แ„€แ…ฎแ„’แ…งแ†ซ แ„‹แ…ฆแ„…แ…ฅ 1

email, password textfield๊ฐ€ ์ ์–ด๋„ ํ•œ๊ฐœ์”ฉ ์ž…๋ ฅ ๋˜์–ด์•ผ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ปด๋ฐ”์ธ์„ ํ†ตํ•ด ๋ฆฌํŽ™ํ„ฐ๋ง ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ์œ„ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ–ˆ๋‹ค. viewModel.passwd์˜ ๊ฒฝ์šฐ @published๋กœ ์„ ์–ธํ–ˆ๋‹ค. checkIsValidTextFields(withLogin:) ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•˜๋Š” ์‹ค์‹œ๊ฐ„ ํƒ€์ดํ•‘์— ๋Œ€ํ•ด ๋ฐ˜์‘ ํ•˜๋ ค๊ณ  ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

TextFiled publisher๋Š” ์„ ์–ธ์ด ๋ฌ๋‹ค. Combine์€ ์•„์ง๊นŒ์ง„ UIKit์— ๋Œ€ํ•œ UIControl์˜ ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€ ํ•ด์ฃผ์ง€ ์•Š์•˜๊ธฐ์— TextField ํฌ์ปค์‹ฑ์—์„œ ๋ฒ—์–ด๋‚˜์•ผ๋งŒ ํ…์ŠคํŠธ๊ฐ€ ๋ณ€ํ–ˆ๋‹ค๋Š” published๋ฅผ ํ•ด์ค€๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ํƒ€์ดํ•‘ํ•˜๋Š” ํ•œ ๊ธ€์ž๋งˆ๋‹ค publish๋ฅผ ์›ํ–ˆ๊ธฐ์— publisher(for:) ์‚ฌ์šฉ์€ ์ด๋ฒˆ ๊ตฌํ˜„ ๋ชฉํ‘œ์™€ ๋งž์ง€ ์•Š์•˜๋‹ค. ๋”ฐ๋ผ์„œ NoticifationCenter๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›๋˜๋Š” notification์„ ์ด์šฉํ–ˆ๋‹ค.

แ„…แ…ฉแ„€แ…ณแ„‹แ…ตแ†ซ แ„€แ…ฎแ„’แ…งแ†ซ แ„‹แ…ฆแ„…แ…ฅ แ„‰แ…ฎแ„Œแ…ฅแ†ผ1

์—ฌ๋Ÿฌ๋ฒˆ ์ž‘์„ฑ๋  ๊ฒƒ ๊ฐ™์•„์„œ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค์—ˆ๋‹ค :)

์ฐธ๊ณ ํ•œ ๊ธ€

๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๋ฆฌํŽ™ํ„ฐ๋ง ์ค‘ ๋งˆ์ฃผํ•œ ์ž ์žฌ์  ์—๋Ÿฌ

แ„‹แ…ฆแ„…แ…ฅ3

๋ง ๊ทธ๋Œ€๋กœ ์ž ์žฌ์  ์—๋Ÿฌ๋‹ค.. ์–ด๋–ค ํŠน์ • ๋ฌธ์ž์—ด์„ ์ž…๋ ฅํ•  ๊ฒฝ์šฐ์—๋งŒ ํ•ญ์ƒ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ๋‹ค๊ณ ํ–ˆ๋‹ค. ์‹ฌ์ง€์–ด ๊ทธ ๋‹จ์–ด๊ฐ€ ํ•œ๊ฐœ ์ผ ์ง€๋ผ๋„ ์ž˜ ํ•„ํ„ฐ๋ง ๋ฌ๋Š”๋ฐ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ์˜ˆ์ „์—๋Š” ์™œ ๊ทธ๋Ÿฐ์ง€ ์›์ธ์„ ๊ณ„์† ์ฐพ์ง€ ๋ชปํ•ด์„œ ์ปดํŒŒ์ผ๋Ÿฌ ๊ธฐ๋ถ„๋”ฐ๋ผ ๊ทธ๋Ÿฌ๋Š”๊ฐ€๋ณด๋‹ค ํ•˜๊ณ  ๋„˜์–ด๊ฐ”๋‹ค๊ฐ€ ์˜ค๋Š˜์—์„œ์•ผ ์ด์ƒํ•จ์„ ๋Š๊ผˆ๋‹ค. ์ปด๋ฐ”์ธ์„ ์‚ฌ์šฉํ–ˆ์Œ์—๋„ (๋ฌผ๋ก  ๋กœ์ง์€ ๋™์ผ) ์—๋Ÿฌ๊ฐ€ ๋‚˜์„œ ๊ณ„์†ํ•ด์„œ ์›์ธ์„ ํƒ์ƒ‰ํ•˜๋‹ค๊ฐ€ ๋“œ๋””์–ด ์ด์œ ๋ฅผ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค....

แ„‹แ…ฆแ„…แ…ฅ 3 -1

ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ ์—„์ฒญ ์†Œ๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ช‡์‹ญ๋ฒˆ๋งŒ fetchํ•˜๋ฉด ๋ฐ”๋กœ ๋ˆ ๋‚ด๋ผ๊ณ ํ•ด์„œ ๊ทธ๋•์— ๊ฐœ๋ฐœ์„ ๋ชปํ•œ ๊ฒฝํ—˜์ด 3๋ฒˆ(3์ผ์ •๋„) ์žˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ searchController์˜ tableView(numberOfRowsInSection:) ๋ชฉ๋ก ํฌ๊ธฐ๋ฅผ ๋Œ€ํญ ๋‚ฎ์ถฐ์„œ Constant์ธ 3์œผ๋กœ ํ•ด๋ฒ„๋ ค์„œ ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค.

  • filteredUsers(๊ฒ€์ƒ‰์—์˜ํ•ด ํ•„ํ„ฐ๋ง ๋œ ๋ฐ์ดํ„ฐ๋“ค ) PassthroughSubject ํƒ€์ž…์œผ๋กœ ์ดˆ๊ธฐ์— ์„ค์ •ํ–ˆ๋‹ค๊ฐ€ @publishedํƒ€์ž…์œผ๋กœ ๋ฐ”๊ฟจ๋Š”๋ฐ ์ด๋•Œ ๊ด€๋ จ ๋กœ์ง์„ ๊นœ๋นกํ•˜๊ณ  ์ˆ˜์ •ํ•˜์ง€ ์•Š์•„์„œ ์ด์ƒํ•œ indexPath.row๊ฐ€ ๋‚˜์™”๋˜ ๊ฒƒ,,,

๋˜ ํ•˜๋‚˜ ๋ฐœ๊ฒฌํ•œ ์—๋Ÿฌ๋Š” string.contains()๋Š” ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ณ„ํ•œ๋‹ค. ๊ทผ๋ฐ ๋‚˜์˜ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž์˜ ์ฒซ ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ ์ž…๋ ฅํ•˜๋„๋ก ์„ค์ •ํ•ด์„œ ๊ฒ€์ƒ‰์ด ์ž˜ ์•ˆ๋ฌ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฐ์ดํ„ฐ๋ฅผ filterํ•  ๋•Œ lowercase()๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค.


๊ฐœ๋… ์ •๋ฆฌ

์ปด๋ฐ”์ธ์„ ๊ณต๋ถ€ํ•˜๋ฉด์„œ Notification์„ ๊ณต๋ถ€ํ–ˆ์—ˆ์ง€๋งŒ ์ด์ฐธ์— ๊ฐ„๋žตํ•˜๊ฒŒ ๋‹ค์‹œ ์ •๋ฆฌํ•œ๋‹ค.

Notificaiton

Swift์—์„œ notification์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ "์•Œ๋ฆผ์„ ๋ฐฉ์†ก"ํ•˜๋Š” ์—ญํ• ์„ ๊ฐ–๋Š”๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋ฐฉ์†ก์„ ํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋””๋กœ ์†ก์‹ , ์–ด๋Š ์ฒด๋„๋กœ ์ฃผํŒŒ์ˆ˜๋ฅผ ๋งž์ถฐ์•ผ ๋ฐฉ์†ก์„ ๋“ค์„ ์ˆ˜ ์žˆ๋Š”์ง€ ์ •ํ•ด์•ผ ํ•œ๋‹ค. Notification์„ ์ „๋‹ฌํ•˜๋Š” ์ค‘์‹ฌ์€ NotificationCenter์ด๋‹ค.

NotificationCenter

๋“ฑ๋ก๋œ observer๋“ค์—๊ฒŒ ์ •๋ณด์˜ BroadCast๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” Notification Dispatch ๋งค์ปค๋‹ˆ์ฆ˜ ํ†ตํ•ด ๋™์ž‘.

DispatchQueue, NotificationCenter๋“ฑ์„ ํ†ตํ•ด ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” system ๊ธฐ๋Šฅ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. NotificationCenter๋ฅผ ํ†ตํ•ด notification์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” observer(or subscriber), publisher๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ฆ‰ publisher๊ฐ€ publishedํ•œ notification์€ NotificationCenter๋ฅผ ํ†ตํ•ด subscriber, observer๋“ฑ์—๊ฒŒ๋กœ ์ „๋‹ฌ๋œ๋‹ค. .default๋ฅผ ํ†ตํ•ด ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์—ˆ๋Š”๋ฐ ์‹ฑ๊ธ€ํ†ค์˜ ๊ฐœ๋…๊ณผ ๋‹ฌ๋ฆฌ ์ปค์Šคํ…€์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•œ๋‹ค!! ( ๋ฐฉํ•™๋•Œ ๋” ๊ณต๋ถ€ํ•ด ๋ด์•ผ๊ฒ ๋‹ค..)

๊ทธ๋ฆฌ๊ณ  UIControl ๊ด€๋ จ ๊ธฐ๋Šฅ์„ ์•„์ง.. ์ง€์›ํ•˜์ง€ ์•Š์ง€๋งŒ NotificationCenter.default.publisher(for:object:) default๋กœ ์ •์˜๋œ UIControl๊ด€๋ จ notification๊ธฐ๋Šฅ์„ publish ํ•  ์ˆ˜ ์žˆ๋Š” publisher๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค :) CombineUtils.setupBindings()์„ ํ†ตํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

์™œ ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ์งฐ์„๊นŒ?

แ„€แ…ฉแ„Žแ…กแ†ฏ

SearchController์—์„œ ๊ฒ€์ƒ‰์— ์˜ํ•œ tableView cell ์—…๋ฐ์ดํŠธ ๊ด€๋ จ ์ฝ”๋“œ

updateSearchResults(for:) -> searchResult.send(text) -> viewModel.transform -> searchResult subscriber ์‹คํ–‰ -> ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋ง ํ›„ ํ…Œ์ด๋ธ” ๋ฆฌ๋กœ๋“œ .

์ด์ œ cell ์—…๋ฐ์ดํŠธ๊ฐ€ ์‹œ์ž‘๋œ๋‹ค.

์›๋ž˜ ๋‚ด ๊ณ„ํš์€ viewModel์˜ searchResult์—์„œ ํ•„ํ„ฐ๋ง ๊ณผ์ • ํ›„ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ PassthroughSubject<[userInfoModel],Never> ํƒ€์ž…์˜ filteredUsers(ํ•„ํ„ฐ๋ง ๋œ ํŠน์ • ๋ฐ์ดํ„ฐ ๋ฐฐ์—ด)์— sendํ•˜๋ ค๊ณ ํ–ˆ๋‹ค. ๊ทผ๋ฐ filteredUsers๋ฅผ PassthroughSubjectํƒ€์ž…์œผ๋กœ ํ•˜์ž๋‹ˆ ํ•„ํ„ฐ๋ง ๋œ ์ „์ฒด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ sink๋ฅผ ํ†ตํ•ด ๋ฐ˜ํ™˜ํ•ด์•ผํ•˜๋Š”๋ฐ ์ด๋•Œ ๋˜ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— PassthroughSubject๊ฐ€ ์•„๋‹Œ @published๋กœ ํƒ€์ž…์„ ๋ฐ”๊พธ์—ˆ๋‹ค. ์ด๋•Œ @published์— ๋งž๊ฒŒ ๋ฐ”๊ฟ”์•ผํ–ˆ์—ˆ๋Š”๋ฐ ๊นœ๋นกํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋‚œ ๋ถ€๋ถ„๋งŒ ์ˆ˜์ •ํ•ด์„œ wrong code๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ณ„์†ํ•ด์„œ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด๊ฐ”๋‹ค. ๊ทธ๋ž˜์„œ sink๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์•„๋„ ๊ณ„์†ํ•ด์„œ publised๋œ ๊ฐ’์„ ๋ฐ›์•„์„œ indexPath.row๊ฐ€ filteredUsers์˜ ๋ฒ”์œ„๋ฅผ ์ดˆ๊ณผํ–ˆ๋‹ค๋Š” ์˜ค๋ฅ˜๋ฅผ ๊ณ„์† ๋ฐœ์ƒ์‹œํ‚จ ๊ฒƒ์ด๋‹ค. ์ฝ”๋“œ๋ฅผ ๋” ๊น”๋”ํ•˜๊ฒŒ ๋ถ„์‚ฐ์‹œ์ผœ์•ผ๊ฒ ๋‹ค.. ์ฝ”๋“œ ์งœ๋Š” ๋‚ด๋‚ด ์ด๋ฆฌ๊ฐ”๋‹ค ์ €๋ฆฌ๊ฐ”๋‹ค ํ•ด์„œ ์ž˜๋ชป๋œ ๋กœ์ง์„ ํŒŒ์•…ํ•˜์ง€ ๋ชป ํ–ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.

์ถ”๊ฐ€, ๊ฐœ์„  ํ•ด์•ผํ•  ๊ธฐ๋Šฅ

  • ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ์„œ์น˜๋ฐ”๋ฅผ ํด๋ฆญํ•  ๋•Œ tableView reloadData๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์ด๊ฒƒ์„ ์—†์• ์•ผํ•œ๋‹ค.

  • ProfileVC ๊ด€๋ จ tableView delegate๋“ค input/outputํŒจํ„ด์œผ๋กœ VM์œผ๋กœ ๋ฆฌํŽ™ํ„ฐ๋ง ํ•ด์•ผ ํ•œ๋‹ค.

  • Login ๊ด€๋ จ ๊ธฐ๋Šฅ

์ถ”ํ›„ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ตœ์†Œ ์ž…๋ ฅ ๊ฐœ์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ณ  ์•Œ๋ฆผ์ฐฝ์„ ๋„์šฐ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด๋‹ค. ๋˜ํ•œ ํ† ์Šค์˜ ํšŒ์›๊ฐ€์ž… ์ ˆ์ฐจ์ฒ˜๋Ÿผ ๋งŒ๋“ค์–ด ๋ณผ ๊ฒƒ์ด๋‹ค.

๊ณ ๋ฏผ๊ฑฐ๋ฆฌ..

์•ฝ๊ฐ„ ๊ณ ๋ฏผ์ธ๊ฒŒ structํƒ€์ž…์˜ ๋ชจ๋ธ์— @published, PassthroughSubject ๊ฐ™์€ publisher ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด๋„ ๋˜๋Š”์ง€ ํ–ˆ๊ฐˆ๋ฆฐ๋‹ค.... ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ + ํ๋ฆ„๊นŒ์ง€ ๊ฐ–๊ฒŒ ๋˜์–ด์„œ ์„ ์–ธํ•˜๋ฉด ํŽธํ•œ๋ฐ.. ๋ณธ์งˆ์ด ๋ง๊ฐ€์ง€๋Š”๊ฒŒ ์•„๋‹Œ์ง€ ๊ณ ๋ฏผ์Šค๋Ÿฝ๋‹ค.. ๊ฒฐ๋ก ์€ ๊ทธ๋ƒฅ Model์„ ์–ธ์„ ์•ˆํ•˜๋ฉด ๋˜๋Š”๋ฐ.. ๊ทธ๋ž˜์„œ ์•ˆ ํ–ˆ๋‹ค. (Model์˜ ์˜ํ–ฅ์ด ๋งŽ์ด ์ค„์—ˆ๋„ค..)

๊ทผ๋ฐ ํ•ด๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค.

์ƒˆ๋กœ ๋ฆฌํŽ™ํ„ฐ๋ง ํ•ด์•ผํ•  ๊ฒƒ

  • Feed VC ๊ด€๋ จ
  • Upload VC ๊ด€๋ จ

SearchController ๋ฅผ SearchViewModel๊ณผ ๋ถ„๋ฆฌํ•  ๋•Œ SearchViewModelProtocols ์š”๊ธฐ์—์„œ ์ด ๋‘ ํ•จ์ˆ˜๋ฅผ ๊ผญ UserViewModel๋กœ ๋ถ„๋ฆฌํ•ด์•ผํ•œ๋‹ค. SearchViewModel์— ์˜์กด์ ์ด๋‹ค.

แ„€แ…ขแ„‰แ…ฅแ†ซแ„’แ…ขแ„‹แ…ฃแ„’แ…กแ‡‚

์‹œํ—˜์ด 7์ผ ๋‚จ์•˜๋‹ค.. ํฐ์ผ๋‚ฌ๋‹ค.. ํ•™๊ต ๊ณต๋ถ€๋ณด๋‹ค ์Šค์œ„ํ”„ํŠธ๋ฅผ ํ•  ๋•Œ ์‹œ๊ฐ„์ด ๋นจ๋ฆฌ๊ฐ„๋‹ค.

// ์—ฌ๋‹ด..

์ปด๋ฐ”์ธ ๊ณต๋ถ€๋งŒ 3์ฃผ? ํ•œ๋‹ฌ ์งธ ๋˜๊ฐ€๋Š”๋ฐ ํ•œ๋‹ฌ ์ „์— ์ฃผ๋ฌธํ•œ ์ฑ…์ด ๋“œ๋””์–ด ๋„์ฐฉํ–ˆ๋‹ค. ๊ธฐ๋ง๊ณ ์‚ฌ ๋นจ๋ฆฌ ๋๋‚˜๋ฉด ์ข‹๊ฒ ๋‹ค. ห˜แ—œห˜

tetestt

[Clone/Instagram] ๐Ÿšฉ LoginController MVVM ๋ฆฌํŽ™ํ„ฐ๋ง(์—๋Ÿฌ์ฒ˜๋ฆฌ, clean code) with combine | LoginController Code Review ๐Ÿ–‹๏ธ | ๋งˆ์ฃผํ•œ ์—๋Ÿฌ & ๊ฐœ์„ ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ & ๋Š๋‚€์  & #13

TODO: ์ด๋ฒˆ์—” Never์ธ ๊ฒฝ์šฐ๋Š” ์—†๋‹ค๋Š” ์ƒ๊ฐ์œผ๋กœ LoginController ๋ฆฌํŽ™ํ„ฐ๋ง.

๊ตฌํ˜„ ์˜์ƒ


๊ฐ„๋‹จํ•œ LoginController ์ฝ”๋“œ ๋ฆฌ๋ทฐ ( ์‹œํ—˜ ๋๋‚˜๋„ ๊นŒ๋จน์ง€ ์•Š๊ธฐ ์œ„ํ•ด.. )

๐Ÿ‘‹ TODO: ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ํ•˜๋Š” ๊ณผ์ •์„ ์ปด๋ฐ”์ธ์œผ๋กœ ๊ตฌํ˜„ with mvvm pattern + DI(Dependency Injection). ์ด๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์˜ค๋ฅ˜ throws -> ์ฒ˜๋ฆฌ.

  • LoginController

  • LoginViewModelProtocols

  • LoginViewModel

์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ, ํ™”๋ฉด๊ณผ ๊ด€๋ จ์žˆ๋Š”(ํšŒ์›๊ฐ€์ž… ๋นผ๊ณ !!) ์†Œ์Šค์ฝ”๋“œ๋Š” ์œ„์— ์žˆ๋Š” ๋‹จ 3๊ฐœ๋กœ ๊ตฌ์„ฑํ–ˆ๋‹ค.

1. LoginController์— ๊ด€ํ•ด (LoginController Link)

  • input/output pattern. DI

แ„…แ…ตแ„‡แ…ฒ1

๊ตฌํ˜„์˜์ƒ ์ดˆ๊ธฐ ํ™”๋ฉด์—์„œ ๋ณด๋“ฏ LoginController์˜ view๋Š” 2๊ฐœ์˜ textfield(id, pw ์ž…๋ ฅ) login button์œผ๋กœ ๊ตฌ์„ฑ๋˜๋œ๋‹ค. RxSwift์—์„œ MVVM ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ๋•Œ input/ output pattern์„ ์ด์šฉํ•œ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•˜๋ฉด Dependency Injection(DI) ๋˜ํ•œ ๊ฐ€๋Šฅํ•˜๋‹ค. LoginController๊ฐ€ ์ดˆ๊ธฐํ™” ๋  ๋•Œ ๋ฐ˜๋“œ์‹œ LoginViewModelType๋กœ ์ดˆ๊ธฐํ™” ํ•จ์œผ๋กœ DIํ–ˆ๋‹ค.

  • input/output implement with error handling

แ„…แ…ตแ„‡แ…ฒ2

LoginController๋Š” viewModel์„ ์‚ฌ์šฉํ•  ๋•Œ ๋งŽ์€ ํ•จ์ˆ˜๊ฐ€ ํ•„์š” ์—†๋‹ค. ๊ทธ์ € input, ouput์„ ๋ฐ”์ธ๋”ฉ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ๋”ฐ๋ผ์„œ LoginController์—์„œ๋Š” viewModel ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด transform ๋‹จ ํ•œ๊ฐœ์˜ ํ•จ์ˆ˜๋งŒ ์‹คํ–‰ํ•˜๋„๋ก ํ–ˆ๋‹ค. ์™œ? input/output pattern์„ ํ†ตํ•ด์„œ LoginController์—์„œ ๋ฐœ์ƒ๋˜๋Š” ๋ชจ๋“  view์˜ Event flow handling์„ viewModel์—์„œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • render(in:)

แ„…แ…ตแ„‡แ…ฒ3

ํ•œ๊ฐ€์ง€ ๋”! LoginController์—์„œ ์ฃผ์‹œํ•  ํ•จ์ˆ˜๋Š” renderํ•จ์ˆ˜์ด๋‹ค. LoginController์—์„œ ๋ฐœ์ƒํ•œ ๊ฐ๊ฐ์˜ ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด์„œ viewModel์˜ transform(input:) ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํŠน์ • publisher์˜ chains ํ•จ์ˆ˜๋ฅผ ํ†ตํ•œ ํ๋ฆ„ ์ฒ˜๋ฆฌ ์ดํ›„์— ๊ฐ’์„ output๋กœ ๋ฐ›๋Š”๋‹ค.

แ„…แ…ตแ„‡แ…ฒ4

์ด๋•Œ์˜ output ์ข…๋ฅ˜๋Š” LoginControllerState์— ๋”ฐ๋ฅธ 3๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค. ์ฃผ ์—ญํ• ์€ view์˜ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์œ„ํ•œ output์„ enum์œผ๋กœ ์ •์˜ํ•œ ๊ฒƒ ๋ฟ์ด๋‹ค. ๊ทธ์ € state์— ๋”ฐ๋ผ view์˜ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

2. LoginViewModelProtocols์— ๊ด€ํ•ด (LoginViewModelProtocols Link)

LoginViewModel์„ ์„ค๋ช…ํ•˜๊ธฐ ์ „์— ์œ„์˜ protocols๋ฅผ ๋ณด๋ฉด์„œ ์ž‘์—…ํ•˜๋ฉด ํŽธํ•˜๋‹ค. ๋งจ ์ฒ˜์Œ์— delegate๊ฐ€ ์žˆ๋Š”๋ฐ ์ถ”ํ›„ ์—†์•จ ๊ณ„ํš์ด๋‹ค. (๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๋•Œ๋งค ๊ผฌ์ด๋Š” ๋Š๋‚Œ์ด..)

  • viewModel's all error type

แ„…แ…ตแ„‡แ…ฒ5

LoginController์˜ upstream input๋กœ ์˜ค๋Š” ๊ฐ๊ฐ์˜ publisher์— ๋Œ€ํ•ด stream operator chains๋ฅผ ์ˆ˜ํ–‰ํ•  ๋•Œ ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์˜ค๋ฅ˜๋ฅผ ์ •์˜ํ–ˆ๋‹ค. ๋งจ ์œ„ ์ œ๋ชฉ์—์„œ ๋ณด๋“ฏ Neverํƒ€์ž…์ด๋ž€ ์—†๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์—๋Ÿฌ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ์— ์ •์˜ ํ–ˆ๋‹ค. ์›๋ž˜๋Š” ์ฝ˜์†”์ฐฝ์— ๋‹จ์ˆœํ•œ ์ถœ๋ ฅ์ด ์•„๋‹Œ ํŠน์ • case์— ๋”ฐ๋ฅธ ์•Œ๋ฆผ or ๋‹ค๋ฅธ ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•ด ๋‹ค์‹œ ํŠน์ • ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๋ฐฉํ•™๋•Œ.. ํ•  ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜์„œ LoginController์˜ input, output publisher์˜ failureํƒ€์ž…์€ ์ „๋ถ€ LoginViewModelErrorType๊ฐ€ ๋œ๋‹ค. ( ์ œ๋„ค๋ฆญ๊ฐ’๋“ค์„ typealias๋กœ ๋ฐ”๊พธ๋ฉด ์–ผ๋งˆ๋‚˜ ์ข‹์„๊นŒ ์ฐพ์•„๋ดค๋Š”๋ฐ ์—†์—ˆ๋‹ค ใ…‹ใ…‹,,)

// ์—ฌ๋‹ด

ํ•œ๊ฐ€์ง€ ๋Š๋‚€์ ์€ c์–ธ์–ด๋กœ ํ…ŒํŠธ๋ฆฌ์Šค ๋งŒ๋“ค์—ˆ์„ ๋•Œ ๊ฐ๊ฐ์˜ enum์€ ์ˆซ์ž์˜ ๊ฐ’๋งŒ ๊ฐ–์„ ์ˆ˜? ์žˆ์—ˆ๋Š”๋ฐ swift๋Š” ํŠน์ • case์ž์ฒด๋ฅผ string์œผ๋กœ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ๊ฐ๊ฐ์˜ case์— ๋Œ€ํ•ด ํŠน์ • ํƒ€์ž…์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฒŒ ์ง„์งœ ๋งค๋ ฅ์ธ๋“ฏ ํ•˜๋‹ค.

  • LoginViewModelInput

แ„…แ…ตแ„‡แ…ฒ6

๋‹ค์Œ์€ LoginController์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฒคํŠธ๋“ค์„ struct๋กœ ์ •์˜ํ•œ ๊ฒƒ์ด๋‹ค. ์ด ๊ฐ๊ฐ์˜ publisher๊ฐ€ publised๋  ๊ฒฝ์šฐ viewModel์—์„  ํŠน์ • input์˜ publiser์— ๋Œ€ํ•œ upstream publisher's operator chaining์„ ์ˆ˜ํ–‰ํ•œ ํ›„ output์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • LoginViewModelInputCase

แ„…แ…ตแ„‡แ…ฒ7

๋‹ค๋ฅธ ๊ฑด ์—†๋‹ค. ๊ฐ๊ฐ์˜ input's upstream publisher์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ๋ฅผ stream์˜ ํ˜•ํƒœ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ์‹ค์งˆ์ ์ธ ํ•จ์ˆ˜๋“ค์ด๋‹ค. ์ด๋•Œ protocol๋กœ ๊ตฌํ˜„ํ•œ ์ด์œ ๋Š” ์ฝ”๋“œ๋ฅผ ๋ชจ๋“ˆํ™” ์‹œ์ผœ transform(input:)ํ•จ์ˆ˜์˜ ๋กœ์ง์„ ์ฝ์„ ๋•Œ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ทธ๋ ‡๋‹ค. ๋ฌผ๋ก  ๋‚ด๊ฐ€ ์ƒ๊ฐํ•œ๊ฒŒ ์•„๋‹ˆ๋‹ค.(์–ธ์  ๊ฐ„ ๋‚˜๋งŒ์˜ ๊ทœ์น™์„ ๊ผญ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค... ๋Œ€์ค‘์ ์œผ๋กœ ์ธ์ •๋ฐ›์œผ๋ฉด ์ข‹๊ณ ,,) (๋งํฌ) ์š”๊ธฐ์—์„œ ๋ณด์ด๋Š” ์ฑ…์˜ ์ €์ž๊ฐ€ ๋งŽ์€ ์„ธ์›”์„ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ํ•˜๋ฉด์„œ ์Œ“์€ ๋…ธํ•˜์šฐ๋“ค์„ ๋ฐ”ํƒ•์œผ๋กœ ํด๋ฆฐ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค. ๋‚œ ์ด ์ €์ž์˜ ๊ทœ์น™์ด ์ •๋ง ๊ดœ์ฐฎ์€ ๊ฒƒ ๊ฐ™์•„ ํด๋ฆฐ์ฝ”๋“œ์˜ ๊ทœ์น™์„ ๋”ฐ๋ผ ๊ตฌํ˜„์„ ํ–ˆ๋‹ค!!!

  • LoginControllerState

แ„…แ…ตแ„‡แ…ฒ8

input -> transform(input:) -> LoginViewModelInput -> LoginViewModelInputCase ๋ฅผ ๊ฑฐ์นœ ํ›„์— ๊ฐ๊ฐ์˜ input์— ๋Œ€ํ•ด์„œ Merge๋ฅผ ํ†ตํ•ด ์ตœ์†Œํ•œ์˜ subscriber๋œ ๊ฐ๊ฐ์˜ publiser ๊ฐ€ ์—ฐ์‚ฐ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ํฌ๊ฒŒ ๋ทฐ์˜ ์ƒํƒœ ๋ณ€ํ™”๋Š” 3๊ฐ€์ง€์ด๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ id, pw๋ฅผ ์ž…๋ ฅํ–ˆ๋Š”์ง€ -> ๋‘˜๋‹ค ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ loginButton enabled๋จ else disabled. none, ์‹คํ–‰์ค‘์ธ ์ธ๋””์ผ€์ดํ„ฐ ํ•ด์ œ. ์ด ์„ธ๊ฐ€์ง€๋‹ค!!

  • LoginViewModelNetworkServiceType

|แ„…แ…ตแ„‡แ…ฒ9

๊ทธ ๋ฐ–์— ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํ†ตํ•ด ๋กœ๊ทธ์ธ ํ•  ๋•Œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ๋“ฑ๋ก๋œ ๊ณ„์ •์ด ๋งž๋Š”์ง€ ์—ฌ๋ถ€ ํ•จ์ˆ˜๋‹ค. wwdc 2021์—์„œ ์†Œ๊ฐœ๋œ async, await ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋„์ž…ํ–ˆ๋‹ค. ํ—คํ—ค. ๋‚˜์ค‘์— ์ปด๋ฐ”์ธ๊ณผ ๊ฒฐํ•ฉ ํ•  ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ๊ฒƒ์ด๋‹ค.

// ์—ฌ๋‹ด2 ์ด๋ฒˆ ๋ฐฉํ•™๋•Œ Swinject ์•„๋‹ˆ๋ฉด needle๋ฅผ ๊ณต๋ถ€ํ•  ๊ฒƒ์ด๋‹ค. DI๋Š” ์ง€๋‚œ 3์ฃผ๊ฐ„ ์ปด๋ฐ”์ธ ๊ณต๋ถ€ ๋•Œ ๋จธ๋ฆฟ์†์œผ๋กœ๋งŒ ๊ณ„์† ๋– ์˜ฌ๋ฆฌ๋‹ค๊ฐ€ ํ•™๊ต ๊ณผ์ œ ISS (๋งํฌ)์•ฝ 2์ฃผ๊ฐ„ Instruction Set Simulator๋ฅผ ๊ตฌํ˜„ ํ•  ๋•Œ ์˜์กด์„ฑ์ด ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋„์ž… ํ•˜๊ณ ์ž ์—ด์‹ฌํžˆ ๋…ธ๋ ฅํ–ˆ๋‹ค. iss ํ”„๋กœ์ ํŠธ ๋๋‚œ ํ›„ ๊ฐœ๋…์œผ๋กœ๋งŒ ์ˆ™์ง€ํ•˜๊ณ  ์žˆ๋˜ Combine์„ ์ ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ protocol ๊ด€๋ จ์€ ๋‚˜์˜์ง€ ์•Š๊ฒŒ ์Šค์œ„ํ”„ํŠธ์— ๋ฐ”๋กœ ๋„์ž…ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
๊ทผ๋ฐ C++์— interface๊ฐ€ ์ง€์›์ด ์•ˆ ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์ง„์งœ ๋ชฐ๋ž๋‹ค. ๊ทธ๋ž˜์„œ define์œผ๋กœ ์ •ํ•˜๊ธด ํ–ˆ๋‹ค.. ๊ทผ๋ฐ ์ˆœ์ˆ˜ ๊ฐ€์ƒํ•จ์ˆ˜๋ฅผ ์„ ์–ธ ํ•ด๋„ ๊ฒฐ๊ตญ์—” ์ƒ์†๋ฐ›๋Š” ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•  ๋•Œ .h ํŒŒ์ผ์— ์žฌ ์„ ์–ธ ํ›„ .cpp ํŒŒ์ผ์—์„œ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค๋Š”๊ฒŒ ๋„ˆ๋ฌด ์•„์‰ฌ์› ๋‹ค. swift ์˜€๋‹ค๋ฉด ์ค‘์ฒฉ ์„ ์–ธ์ด ์—†๋Š” ๊น”๋”ํ•œ ์ฝ”๋“œ์˜€์„ ํ…๋ฐ.. ์•„๋ฌดํŠผ ISS๋ฅผ ๊ตฌํ˜„ํ•œ ๋•์— DI๊ด€๋ จ ๊ฐœ๋…์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋‚˜์˜์ง€ ์•Š์•˜๋‹ค๋Š” ๋ง!!

3. LoginViewModel (LoginViewModel Link)

์ด๊ฑฐ๋Š” ์ง์ ‘ ์ฝ”๋“œ๋กœ ๋ณด๋Š”๊ฒŒ ์ข‹๊ฒ ๋‹ค.

์›๋ž˜ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ์ •๋ง ์ข‹์•„ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฃผ์„ ์œผ๋กœ ๋ถ€์—ฐ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์„ ๊ต‰์žฅํžˆ ์ข‹์•„ํ•œ๋‹ค.. ํ•™๊ต ๊ต์ˆ˜๋‹˜๋“ค์ด ์‹œ์ผœ์„œ ์Šต๊ด€์ด ๋œ ๊ฒƒ์ด ์žˆ๊ธฐ๋„ ํ–ˆ๋‹ค. ํด๋ฆฐ ์ฝ”๋“œ๋ฅผ ์ฝ์œผ๋ฉฐ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ฝ์„ ๋•Œ ํ•œ๋ฒˆ์— ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋„ค์ด๋ฐ์ด ๊ต‰์žฅํžˆ ์ค‘์š”ํ•˜๋‹ค๊ณ  ํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์š”์ฆ˜์€ ์ฃผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์Šต๊ด€ ๋Œ€์‹  ๊นƒํ—™์˜ issue์— ๊ฐœ๋ฐœํ•˜๋‹ค๊ฐ€ ๋Š๋‚€ ๊ฒฝํ—˜์ด๋‚˜ ๋ฌธ์ œ, ์—๋Ÿฌ๋“ค์„ ๋ฌธ์„œํ™”?๋กœ ์ž‘์„ฑํ•˜๊ณ  ์žˆ๋‹ค. ๊ทผ๋ฐ ์ฝ”๋“œ๋ฆฌ๋ทฐ, ์ฃผ์„ ์Šต๊ด€์€ ์ •๋ง ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ฃผ์„ ์—†์ด ๋ช‡ ๋ฒˆ๋งŒ์— ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๋Š” ์ฝ”๋“œ๋Š” ์ •๋ง ํ›Œ๋ฃกํ•œ ์ฝ”๋“œ์ด๊ณ  ์ฃผ์„์ด ํ•„์š” ์—†์ง€๋งŒ ์ค‘๊ฐ„์— ๋งˆ์ฃผํ•œ ์ƒํ™ฉ, ๋ฐฐ์šด์ ๋“ค์€ ์ฃผ์„์ด ์•„๋‹Œ issue์— ๊ธฐ๋กํ•˜๋Š” ์ƒˆ๋กœ ์Šต๊ด€์„ ๋“ค์ด๊ณ  ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ตœ๋Œ€ํ•œ ๋„ค์ด๋ฐ์„ ์ž์„ธํžˆ ํ•ด์„œ ์ฝ”๋“œ์˜ ํ๋ฆ„์„ ์ •ํ™•ํ•˜๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋‚ด ๋ชฉํ‘œ๋‹ค. +_+


๋งˆ์ฃผํ•œ ์—๋Ÿฌ1

Combine์˜ publisher tryMap์˜ ์‚ฌ์šฉ์‹œ failureํƒ€์ž…์— ๊ด€ํ•œ ์—๋Ÿฌ.

แ„‹แ…ฆแ„…แ…ฅ1

แ„‹แ…ฆแ„…แ…ฅ2

tryMap์„ ์‚ฌ์šฉํ•ด error๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ์„ ๊ฒฝ์šฐ publisher์˜ failureํƒ€์ž…์€ Never๊ฐ€ ๋˜๋ฉด ์•ˆ๋œ๋‹ค. Merge -> ๊ทธ๋Œ€๋กœ eraseToAnyPublisher()๋กœ ๋ณ€ํ™˜ํ•œ subscription์„ ๊ฐ–์„ ๊ฒฝ์šฐ์— ํƒ€์ž…์˜ ๋ชจํ˜ธํ•จ ์—๋Ÿฌ๊ฐ€ ๋œฌ๋‹ค.

๋งˆ์ฃผํ•œ ์—๋Ÿฌ2

failure ํƒ€์ž…์ด Never๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ

แ„‹แ…ฆแ„…แ…ฅ3

tryMap ์€ any error ํƒ€์ž… ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋‚ด๊ฐ€ ์›ํ•˜๋Š” publisher failure type์— ๋งž๊ฒŒ mapError๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ปค์Šคํ…€ errorํƒ€์ž…์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์บ์ŠคํŒ… ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์•ผ subscriber์—๊ฒŒ failure๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ๋‹ค. publisher์˜ failureํƒ€์ž… Never๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋Š” map์ด ์•„๋‹Œ tryMap๊ฐ™์€ try ๊ธฐ๋Šฅ์ด ๋‹ด๊ธด ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

LoginController์™€ MainHomeTabViewController ๊ฐ„์— ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ์ด์ „์— ์ž‘์„ฑํ–ˆ๊ธฐ์— ์‚ด์ž‘ ๋ณต์žกํ–ˆ๋Š”๋ฐ publisher์˜ input output์— ๋‘๊ฐœ์˜ vc๋ฅผ ์ „๋‹ฌํ•จ์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค.

๋ณต์Šตํ•œ ๊ฐœ๋…

A, B๋‘ ๊ฐœ์˜ publisher๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •.
let myZip = A.zip(B)

  • combineLatest
    ์–˜๋Š” A๊ฐ€ publishํ•˜๊ณ  B๋˜ํ•œ publishํ•ด์•ผ๋งŒ myZip์ด published๋œ๋‹ค. ์•ฝ๊ฐ„ ์ปคํ”Œ๋Š๋‚Œ? ํ•œ ์Œ์ด publish๋˜์•ผ๋งŒ ๋น„๋กœ์†ŒmyZip์ด ์ž‘๋™ํ•œ๋‹ค. ์•ฝ๊ฐ„ ๋‚ด๊ฐ€ ๊ตฌํ˜„ํ•˜๋Š” id,pw๋‘˜๋‹ค ์ž…๋ ฅํ•ด์•ผ๋งŒ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํ•ด์ œ๋˜๋Š” ๋กœ์ง๊ณผ ๊ฐ™์Œ. ์•„๋ž˜๊บผ๋Š” ์•ฝ๊ฐ„ password ๋‘๋ฒˆ ์ž…๋ ฅํ•ด์„œ ์ž๊ธฐ๊ฐ€ ์ž…๋ ฅํ•œ password ๋งž๋Š”์ง€ ํ™•์ธํ•  ๋•Œ์˜ operator๋ผ๊ณ  ๋ณด๋ฉด ๋  ๊ฑฐ๊ฐ™๋‹ค.

  • zip
    ์–˜๋Š” A๊ฐ€ publishํ•˜๊ณ  B๊ฐ€ publishํ•ด์•ผ๋งŒ myZip์ด publised๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  A๊ฐ€ publish๋˜๋ฉด B์˜ ์ตœ์‹  ๊ฐ’๊ณผ ํ•จ๊ป˜ publish๋œ๋‹ค. ์ฆ‰ ๋‘˜๋‹ค publishedํ•œ ๊ฒฝ์šฐ์— A๋งŒ publishํ•ด๋„ B๋Š” ์ตœ์‹  publis ๊ฐ’์„ ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ๋„ ๊ฐ™๋‹ค.

์ถ”๊ฐ€, ๊ฐœ์„  ํ•ด์•ผํ•  ๊ธฐ๋Šฅ

  • ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ์„œ์น˜๋ฐ”๋ฅผ ํด๋ฆญํ•  ๋•Œ tableView reloadData๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์ด๊ฒƒ์„ ์—†์• ์•ผํ•œ๋‹ค.

  • LoginController ๋น„๋ฐ€๋ฒˆํ˜ธ ์ตœ์†Œ ์ž…๋ ฅ ๊ฐœ์ˆ˜ ์ œํ•œ

  • RegistrationController

๋˜ํ•œ ํ† ์Šค์˜ ํšŒ์›๊ฐ€์ž… ์ ˆ์ฐจ์ฒ˜๋Ÿผ ๋งŒ๋“ค์–ด ๋ณผ ๊ฒƒ์ด๋‹ค.

์ƒˆ๋กœ ๋ฆฌํŽ™ํ„ฐ๋ง ํ•ด์•ผํ•  ๊ฒƒ

  • Feed VC ๊ด€๋ จ
  • Upload VC ๊ด€๋ จ

SearchController ๋ฅผ SearchViewModel๊ณผ ๋ถ„๋ฆฌํ•  ๋•Œ SearchViewModelProtocols ์š”๊ธฐ์—์„œ ์ด ๋‘ ํ•จ์ˆ˜๋ฅผ ๊ผญ UserViewModel๋กœ ๋ถ„๋ฆฌํ•ด์•ผํ•œ๋‹ค. SearchViewModel์— ์˜์กด์ ์ด๋‹ค.

แ„€แ…ขแ„‰แ…ฅแ†ซแ„’แ…ขแ„‹แ…ฃแ„’แ…กแ‡‚

์‹œํ—˜์ด 6์ผ ๋‚จ์•˜๋‹ค.. ์ •๋ง ํฐ์ผ๋‚ฌ๋‹ค.

๋Š๋‚€์ 

์‚ฌ์‹ค ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ๋‹จ์ˆœํžˆ ์ฝ˜์†”์ฐฝ์— ์ถœ๋ ฅํ–ˆ๋‹ค. ๋ฐฉํ•™์ด ๋‚ด๊ฒŒ ์˜จ๋‹ค๋ฉด ํŠน์ • ์ƒํ™ฉ์— ๋งž๋Š” ์•Œ๋ฆผ์ด๋‚˜ ์˜ค๋ฅ˜๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ๊ฒƒ์ด๋‹ค.

(์‹œํ—˜๋งŒ ๋๋‚œ๋‹ค๋ฉด ์ปด๋ฐ”์ธ ์ฑ…์œผ๋กœ ์ถ”๊ฐ€ ๊ณต๋ถ€ํ•  ํ…๋ฐ)

[Clone/Instagram] ํ”„๋กœํ•„ Scene ๊ตฌํ˜„ | ์ƒ‰๋‹ค๋ฅธ ์‹œ๋„ & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋… & ๊ฐœ์„ ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ #7

ํ”„๋กœํ•„ Scene ๊ตฌํ˜„

๊ตฌํ˜„ ์˜์ƒ

๊ฐ•์˜์™€๋Š” ๋‹ค๋ฅด๊ฒŒ

  • ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ Firebase DB์—์„œ ๊บผ๋‚ด์™€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฐฑ์‹ ํ•˜๋„๋ก ์ถ”๊ฐ€ ๊ตฌํ˜„
  • profileHeader์˜ ํ”„๋กœํ•„, ์‚ฌ์šฉ์ž ์ด๋ฆ„๋“ฑ Firestore DB์˜ ๋ฐ์ดํ„ฐ๋ฅผ fetchํ•˜๋Š” ํ•จ์ˆ˜ ๋งŒ๋“ฌ
  • Firestore Database์— ๊ฐ’์„ ๊บผ๋‚ด์˜ค๊ฑฐ๋‚˜ ์ €์žฅํ•  ๋•Œ Codableํƒ€์ž…์œผ๋กœ Model์„ ์ƒˆ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๊ฐœ์„ ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ

  • ํšŒ์›๊ฐ€์ž… ์‹คํŒจ ์‹œ ๋ฒ„ํผ๋ง ๋Š๊ธฐ
  • profile Header์˜ image๋ฅผ Storage.storage์—์„œ ๋ฐ›์•„์˜ค๋Š”๋ฐ ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆผ. ๊ธฐ๋Šฅ ๊ฐœ์„ ์ด ํ•„์š”.. (์›๋ž˜ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์ž‘์€ ์ด๋ฏธ์ง€ ๋ฐ›์•„์˜ค๋Š” ๊ฒฝ์šฐ๋„ ๋Š๋ฆฐ์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค,,)

  • ProfileController์—์„œ grid, list bookmark ๋ฒ„ํŠผ์ด์žˆ๋Š”๋ฐ ์ด๋ฅผ stackview+pageViewController๋กœ ์ถ”๊ฐ€ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ

์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ๊ฒƒ

์ปฌ๋ž™์…˜ ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”

  1. ํ—ค๋”๋ฅผ ๋“ฑ๋กํ•ด์•ผํ•จ
    collectionView.register(_:forSupplementaryViewOfKind:withReuseIdentifier:)
  2. DataSource๋กœ Header๋ทฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋จ collectionView(_:viewForSupplementaryElementOfKind:at:)

์ด๋•Œ ์–˜๋Š” UICollectionReusableView๋ฅผ ๋ฐ˜ํ™˜ํ•จ์œผ๋กœ HeaderView์˜ ํƒ€์ž…์€ UICollectionReusableView๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.

  1. collectionView(_:layout:referenceSizeForHeaderInSection:)

ํ—ค๋” ํฌ๊ธฐ ๋ฐ˜ํ™˜!


CollectionViewDelegateFlowLayout

  • collectionView(_:layout:minimumLineSpacingForSectionAt:)

minimumLineSpacing ๊ฒฝ์šฐ ์•„๋ž˜๋กœ ์Šคํฌ๋กคํ•˜๋Š” ๋ ˆ์ด์•„์›ƒ์ผ ๋•Œ row๊ฐ„์˜ ์ตœ์†Œ ๊ฐ„๊ฒฉ์„ ์ •ํ•œ๋‹ค. horizontally์˜ collectionLayout์˜ ๊ฒฝ์šฐ column๊ฐ„ ์ตœ์†Œ ๊ฐ„๊ฒฉ์„ ๊ฒฐ์ •ํ•œ๋‹ค.

  • collectionView(_:layout:minimumInteritemSpacingForSectionAt: )

minimumInteritem์„ ์„ค๋ช…ํ•˜์ž๋ฉด ์•„๋ž˜๋กœ ๋‚ด๋ฆฌ๋Š” collection layout์ธ ๊ฒฝ์šฐ cell์˜ row๊ฐ„ ์ตœ์†Œ space๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ์˜†์œผ๋กœ ์Šคํฌ๋กคํ•˜๋Š” collectionLayout์ธ ๊ฒฝ์šฐ cell์˜ column๊ฐ„ ์ตœ์†Œ space๋ฅผ ์„ค์ •ํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.

vertical ๊ธฐ์ค€์œผ๋กœ minimumLineSpace๋Š” ํ–‰ ๊ฐ„์˜ ์ตœ์†Œ ๊ฐ„๊ฒฉ, minimumInteritem์˜ ๊ฒฝ์šฐ row์˜ cell๊ฐ„ ์ตœ์†Œ ๊ฐ„๊ฒฉ์„ ์ง€์ •ํ•œ๋‹ค.


cf.

UICollectionViewDelegateFlowLayout
-> collectionView cell์˜ ์‚ฌ์ด์ฆˆ ์กฐ์ ˆ

UICollectionViewDelegate
-> cell ์„ ํƒ ๊ด€๋ จ ๋ฉ”์„œ๋“œ


cocoapods ๊ด€๋ จ

์‚ญ์ œ ํ›„ ์žฌ์„ค์น˜ or ์—…๋ฐ์ดํŠธ

  • pod cache clean --all && pod install --repo-update

  • pod update

  • ๋‚ด๊ฐ€ ์„ค์น˜ํ•œ cocoapods๊ณผ์ • (iterm์„ ๋กœ์ œํƒ€๋กœ ์‹คํ–‰)

  • ์ฝ”์ฝ”์•„ํŒŸ ๋ฌธ์ œ ์ƒ๊ฒผ์„ ๋•Œ ์‚ญ์ œํ•˜๋Š” ๋ฐฉ๋ฒ• ์ฐธ๊ณ ๋กœ ํ”„๋กœ์ ํŠธ์— ์—ฐ๊ฒฐ๋œ Pods, .xcworkspace ๋“ฑ์€ ์‚ญ์ œํ•ด๋„ ๋œ๋‹ค. ๋‹ค์‹œ ๊น”๋ฉด ๋จ. ์ค‘์š”ํ•œ๊ฑด ์†Œ์Šค์ฝ”๋“œ๋‹ค.

๋งˆ์ฃผํ•œ ์—๋Ÿฌ

arch -x86_64๋กœ m1 ์šฉ์œผ๋กœ ์„ค์น˜ํ–ˆ๋Š”๋ฐ ์•„๋ž˜ ์—๋Ÿฌ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ๋‹ค. ์Œ Target-> Build Settings ->Architectures -> Excluded Architectures ์—์„œ arm64๋ฅผ ์ถ”๊ฐ€ ํ•ด๋ณด๊ณ  Any ios simulator SDK arm64๋กœ ์„ ์–ธํ•ด๋„ ์—ฌ์ „ํžˆ ํ•ด๊ฒฐ์ด ์•ˆ๋ฌ๋‹ค.


๋ญ”๊ฐ€ ๋Œ€๋‹จํžˆ ์ž˜๋ชป ๋˜์–ด๊ฐ€๊ณ  ์žˆ๋‹ค... ์›๋ž˜ ๋‚ด ๋ชฉ์ ์€ firestore์—์„œ ์ €์žฅ๋œ ๋„ํ๋ฉ˜ํŠธ์˜ ํ•„๋“œ๊ฐ’ ์œ ์ € ์ •๋ณด๋ฅผ Codable ํƒ€์ž…์œผ๋กœ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด์„œ ... pod FirebaseFirestoreSwift์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ ๋ฟ์ธ๋ฐ

แ„†แ…กแ„‹แ…ฆ2

แ„†แ…กแ„‹แ…ฆ1

์ด ์—๋Ÿฌ๋“ค์ด ๊ณ„์† ๋ฐœ์ƒํ–ˆ๋‹ค;;;

arch -x86_64๋กœ m1 ์šฉ์œผ๋กœ ์„ค์น˜ํ–ˆ๋Š”๋ฐ ์•„๋ž˜ ์—๋Ÿฌ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ๋‹ค. ์Œ Target-> Build Settings ->Architectures -> Excluded Architectures ์—์„œ arm64๋ฅผ ์ถ”๊ฐ€ ํ•ด๋ณด๊ณ  Any ios simulator SDK arm64๋กœ ์„ ์–ธํ•ด๋„ ์—ฌ์ „ํžˆ ํ•ด๊ฒฐ์ด ์•ˆ๋ฌ๋‹ค.

(์ง„์งœ ํฐ์ผ๋‚ฌ๋‹ค. 2์ผ์งธ ๊ฐœ๋ฐœ์€ ๋ฌผ๋ก  ์ง€๊ธˆ ํ”„๋กœ์ ํŠธ ๋‚ด ํŒŒ์ผ๊นŒ์ง€ ์ž˜๋ชป ์‚ญ์ œํ•ด ๋ฒ„๋ ธ๋‹ค;;)

cocoapods๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์žฌ ์„ค์น˜ํ•˜๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ

t11

์ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. chmod๋กœ user์—๊ฒŒ ๊ถŒํ•œ๋„ ์คฌ์ง€๋งŒ ์—ฌ์ „ํžˆ ์ด๋Ÿฐ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ณ  ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–‡๋‹ค.

ใ„ท1

ใ„ท2

(์‚ด๋ ค์ค˜..)

์ง€๊ธˆ gem์œผ๋กœ bundler๋„ ์„ค์น˜๊ฐ€์•ˆ๋˜๊ณ  cocoapods๋„ ์„ค์น˜๊ฐ€ ์—ฌ์ „ํžˆ ์•ˆ๋˜๊ณ  ์žˆ๋‹ค...

์–ด์ฐŒ์–ด์ฐŒ ํ•ด์„œ arch -x86_64 ๋กœ ์ฝ”์ฝ”์•„ ํŒŸ์„ ์„ค์น˜ํ–ˆ์„ ๋•

Ignoring ffi-1.15.4 because its extensions are not built. Try: gem pristine ffi --version 1.15.4

์ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด์„œ

แ„†แ…กแ„‹แ…ฆ1

์ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”๋ฐ ์ด ์—๋Ÿฌ๋Š” ์ž์„ธํ•œ ์—๋Ÿฌ๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค๊ณ  ํ•œ๋‹ค... ํ“จใ… ใ…  ์ด๊ฒƒ๋•Œ๋งค ๋ญ ์ž˜๋ชป ์‚ญ์ œ ํ–ˆ๋‹ค๊ฐ€ ํ”„๋กœ์ ํŠธ ์•ˆ์— ํŒŒ์ผ ์ผ๋ถ€๋ฅผ ์‹ค์ˆ˜๋กœ ์‚ญ์ œ ํ•ด๋ฒ„๋ฆฐ ๊ฒƒ..

์ง€๊ธˆ ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋Š” gem์„ ํ†ตํ•ด ์„ค์น˜ํ•˜๋ ค๊ณ ํ•˜๋ฉด ์‚ฌ์šฉ์ž ๊ถŒํ•œ์ด ์•„๋‹ˆ๋ผ ๋ฃจํŠธ ๊ถŒํ•œ์„ ์š”๊ตฌํ•ด์„œ **(Gem::FilePermissionError)**๊ฐ€ ์ž๊พธ๋งŒ ๋ฐœ์ƒํ–ˆ๋‹ค.

์ด๋ถ„์˜ ๋ธ”๋กœ๊ทธ ๊ธ€์„ ํ†ตํ•ด์„œ ์„ค์น˜ํ•ด๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์˜€๋Š”๋ฐ...

rbenv ์ตœ์‹  ๋ฒ„์ „ 3.1.2์ธ๊ฐ€? ๊ทธ๊ฑธ๋กœ ๊ณ„์†ํ–ˆ๋Š”๋ฐ ์•ˆ๋ฌ๋‹ค. ์–ด๋–ค ๋‹ค๋ฅธ ๋ถ„์˜ ๊ธ€์—์„œ๋Š” 3.xx๋ฒ„์ „์—์„  ๋ญ”๊ฐ€๊ฐ€? ์„ค์น˜๊ฐ€ ์•ˆ๋œ๋‹ค๊ณ ํ•ด์„œ 2.xx๋ฒ„์ „์œผ๋กœ ์žฌ ์„ค์น˜ํ–ˆ๋Š”๋ฐ ๋‹คํ–‰ํžˆ Gem::FilePermissionError ๊ฐ€ ๋”์ด์ƒ ๋ฐœ์ƒ๋˜์ง€ ์•Š์•˜๋‹ค...

๊ทธ๋ž˜๋„ ์—ฌ์ „ํžˆ Command ComplieSwift failed with a nonzero exit code๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค...

๊ฒฐ๊ตญ ํ•ด๊ฒฐ์ฑ…์€ ์ฐพ์ง€ ๋ชปํ•ด์„œ ์•ฑ์„ ๋‹ค์‹œ ์ƒˆ๋กœ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ๋„ ์œ„์— ์—๋Ÿฌ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ๋‹ค.

์ง€๊ธˆ ๊ทธ ์ด์œ ๋ฅผ ์•Œ์•˜๋‹ค;;;; RESTful API๊ฐ€ ์•„๋‹ˆ๋ผ ํŒŒ์ด์–ด๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ์ด์–ด๋ฒ ์ด์Šค ์‹œ์ž‘ ํ•  ๋•Œ ์•ฑ ๋ฒˆ๋“ค ์•„์ด๋””๋ฅผ ํ† ๋Œ€๋กœ ํŒŒ์ด์–ด๋ฒ ์ด์Šค plist๊ฐ€ ์ฃผ์–ด์ง€๊ณ , AppDelegate์— FirebaseApp.configure()๋กœ ๋“ฑ๋ก๋„ ํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ ์ด ๋ถ€๋ถ„์„ ๊ฐ„๊ณผํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ๋“ฑ๋ก๋œ ์•ฑ์„ ์‚ญ์ œํ•˜๊ณ  ๋‹ค์‹œ ์ƒˆ๋กœ ๋งŒ๋“  ๋ฒˆ๋“ค์„ ์ถ”๊ฐ€ํ•ด์„œ ๋‹คํ–‰ํžˆ ์—๋Ÿฌ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค... ใ… ใ……ใ…  ์•ฝ 2์ผ๊ฐ„ ๊ณ ์ƒํ–ˆ๋‹ค..


๋‹ค์Œ์—” rvm์„ ์จ๋ด์•ผ๊ฒ ๋‹ค. ๊ฒฐ๋ก . ๊นƒํ—™ ์ปค๋ฐ‹์„ ์ž์ฃผ์ž์ฃผ ํ•˜๊ณ  ์ •๋ง ์•ˆ ๋ ๋•Œ๋Š” ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์„œ ์†Œ์Šค์ฝ”๋“œ ๋ณต๋ถ‡ํ•˜๊ธฐ. ํŒŒ์ด์–ด๋ฒ ์ด์Šค ์“ธ ๊ฒฝ์šฐ ์•ฑ ๋ฒˆ๋“ค์•„์ด๋”” ์‚ญ์ œ ํ›„ ์ƒˆ๋กœ ๋“ฑ๋กํ•˜๊ธฐ

[Clone/Instagram] ์ „์ฒด์ ์ธ ๊ธฐ๋Šฅ ๊ฐœ์„ , ์—๋Ÿฌ ์ˆ˜์ • | ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋… #9

์ „์ฒด์ ์ธ ๊ธฐ๋Šฅ๊ฐœ์„ 

  • ํšŒ์›๊ฐ€์ž…๋ฒ„ํŠผ ํด๋ฆญ์‹œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ๋“ฑ๋กํ•˜๋Š” ๊ณผ์ • ์‹œ๊ฐ„ ์ข€ ๊ฑธ๋ ค์„œ ์ธ๋””์ผ€์ดํ„ฐ ์ฒ˜๋ฆฌ ์™„๋ฃŒ
  • ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฉ”์ธ ํƒญ์ปจํŠธ๋กค๋Ÿฌ์˜ subController๋“ค์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ ํ•œ๋ฒˆ์œผ๋กœ ๊ฐœ์„ 
  • ๋กœ๊ทธ์ธ ํ™”๋ฉด ์•ฑ์ด ์‹œ์ž‘๋  ๊ฒฝ์šฐ ๋ฉ”์ธ ํƒญ ๋ฐ”์˜ FeedVC ์ธ์Šคํ„ด์Šค ๋“ฑ๋ก ์•ˆ๋˜๋Š” ๋ฒ„๊ทธ ๊ฐœ์„ 
  • ๋กœ๊ทธ์ธ ์ƒํƒœ์—์„œ ๋กœ๊ทธ์•„์›ƒ ํ›„ ๋‹ค๋ฅธ ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ์‹œ์— ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ currentUser๊ฐ€ ์ž˜ ์ž‘๋™์ด ์•ˆ๋˜์„œ ํ”„๋กœํ•„ VC์˜ ํ”„๋กœํ•„์ด ์•ฑ์„ ๊ป๋‹ค ์ผœ์•ผ ํ•˜๋Š” ๊ฐฑ์‹ ๋˜๋Š” ๋ฒ„๊ทธ ๊ณ ์นจ. (Auth.auth().currentUser ๋ฏฟ์ง€ ๋ง๊ฒƒ,,)
  • ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ํ•˜๋Š” ๊ฒƒ์„ ์ดˆ๊ธฐ ๋กœ๊ทธ์ธ ๋•Œ๋ถ€ํ„ฐ ๋น„๋™๊ธฐ๋กœ ๋ฐ›์•„์™€ ํ”„๋กœํ•„VC๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ๊ฑฐ์˜ ๋ฐ”๋กœ ๋ณด์—ฌ๋„๋ก ๊ฐœ์„ 
  • ์ƒ๋Œ€์ ์œผ๋กœ ํฌ๊ธฐ๊ฐ€ ํฐ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋Š” ๋‹ค์šด์ด ์•ˆ๋˜๋Š” ๋ฒ„๊ทธ ์ˆ˜์ •

๊ตฌํ˜„ ์˜์ƒ

์—๋Ÿฌ ์ˆ˜์ •(๊ฒช์€ ์ )

์•ฑ ์‚ญ์ œํ•˜๊ณ  ๋งจ ์ดˆ๊ธฐ์— ๋กœ๊ทธ์ธํ™”๋ฉด์—์„œ ๋กœ๊ทธ์ธ ํ›„ mainTab์ปจํŠธ๋กค๋Ÿฌ์˜ first subviewController FeedVC ์•ˆ ๋“ค์–ด๊ฐ€์ง€๋Š” ์—๋Ÿฌ ์ˆ˜์ •.

ํ˜„์žฌ ์•ฑ ์ƒํƒœ๋ฅผ ๊ฐ„๋‹จํžˆ ์š”์•ฝ.

UIWindow์˜ ๋ฃจํŠธ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ ๋””ํดํŠธ๋Š” ๋ฉ”์ธ ํ™ˆ ํƒญ ์ปจํŠธ๋กค๋Ÿฌ์ด๋‹ค. ์ดˆ๊ธฐ ์•ฑ์ด ์‹คํ–‰๋˜๋ฉด ๋ฉ”์ธ ํ™ˆ ํƒญ์ปจํŠธ๋กค๋Ÿฌ ๋ทฐ ๋กœ๋“œ ๊ณผ์ •์—์„œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ๋ฅผ ํ™•์ธํ•œ๋‹ค. ํ•ด๋‹น ์ •๋ณด๋ฅผ ํ™ˆ ํƒญ ์ปจํŠธ๋กค๋Ÿฌ ํ”„๋กœํผํ‹ฐ userVM์— ์ดˆ๊ธฐํ™” ํ•˜๋ฉด์„œ๋ถ€ํ„ฐ ์•ฑ์ด ์‹œ์ž‘๋œ๋‹ค. userVM์ด ์ดˆ๊ธฐํ™” ๋˜๋ฉด tabController์˜ viewControllers์˜ ๋ทฐ๋“ค์ด ๋“ฑ๋ก๋˜๊ณ  ์ฒซ๋ฒˆ์งธ ๋ทฐ์ธ FeedVC๊ฐ€ ๋กœ๋“œ๋œ๋‹ค. ๋ฉ”์ธํƒญ์ปจํŠธ๋กค๋Ÿฌ์˜ subViewController๋“ค์€ userVM์— ์ •๋ง ์˜์กด์ ์ด๋‹ค. userVM๊ฐ’์ด ์ดˆ๊ธฐํ™” ๋˜์•ผ ์„œ๋ธŒ์ปจํŠธ๋กค๋Ÿฌ๋“ค์ด ๋“ฑ๋ก๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.(ํŒŒ์ด์–ด์Šคํ† ์–ด์—์„œ ๋‹ค์šด๋ฐ›๋Š” ๋ฐฉ์‹์ด ์‚ด์ง ๋Š๋ ค์„œ ๋ฏธ๋ฆฌ๋ฏธ๋ฆฌ ์ตœ์†Œํ•œ์˜ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๊ธฐ๊ธฐ ์œ„ํ•ด ์ด๋ ‡๊ฒŒ ์ •ํ–ˆ๋‹ค.)

๊ทผ๋ฐ ๋งŒ์•ฝ ์•ฑ์—์„œ (ํŒŒ์ด์–ด๋ฒ ์ด์Šค)๋กœ๊ทธ์•„์›ƒ์„ ํ•œ ๋‹ค์Œ์— ์•ฑ ์ข…๋ฃŒ -> ๋‹ค์‹œ ์•ฑ์„ ์‹œ์ž‘ํ•  ๋•Œ ํ˜„์žฌ ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ๊ธฐ๋ก์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์ธ ํ™ˆ ํƒญ์ปจํŠธ๋กค๋Ÿฌ์˜ ์„œ๋ธŒtabVC๋“ค์ด ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š๋Š”๋‹ค. userVM์ด ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ. ๋ฉ”์ธ ํ™ˆํƒญ์ปจํŠธ๋กค๋Ÿฌ viewLoad ์‹œ์ ์—์„œ LoginVC๋กœ ์ด๋™๋œ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฉ”์ธ ํ™ˆ ํƒญ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์™„์ „ํžˆ ๋ทฐ๊ฐ€ ๋กœ๋“œ๋˜์ง€ ์•Š์€ ์ฑ„๋กœ ๋กœ๊ทธ์ธ ๋ทฐ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์„ ํ•  ๋•Œ ๊ฒฝ๊ณ  ๋ฉ”์„ธ์ง€๊ฐ€ ๋ฐœ์ƒ๋ฌ๋‹ค.

    • Unbalanced calls to begin/end appearance transitions for <Instagram.MainHomeTabController: 0x12d02ca00>

์—ฌ๊ธฐ์„œ ์•ฝ๊ฐ„ ์• ๋งคํ•˜๊ณ  ๋‚œ๊ฐํ•œ ์ƒํ™ฉ์ด ๋ฐœ์ƒ๋ฌ๋‹ค. ๋ฐ˜๋“œ์‹œ userVM์ด ์ดˆ๊ธฐํ™” ๋˜์–ด์•ผ ๋ฉ”์ธ ํ™ˆ์ปจํŠธ๋กค๋Ÿฌ์˜ ์„œ๋ธŒVC๋“ค์ด ์ถ”๊ฐ€๋˜๋ฉด์„œ FeedVC๊ฐ€ ๋กœ๋“œ๋œ๋‹ค๋Š” ์ ์ธ๋ฐ... userVM์ด ์ดˆ๊ธฐํ™”๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ๋กœ๊ทธ์ธ ๋˜์–ด์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ๋ทฐ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ๋˜๋Š” viewDidLoad ์‹œ์ ์— ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ณ  ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐ€์ž๋‹ˆ ์œ„์™€ ๊ฐ™์€ ๊ฒฝ๊ณ  ๋ฉ”์„ธ์ง€๊ฐ€ ๋ฐœ์ƒ ๋˜์ง€๋งŒ ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ํ™”๋ฉด์€ ๋ถˆ๋Ÿฌ์™€์ง„๋‹ค. ๋‹ค์‹œ LoginVC๋ฅผ dismissํ–ˆ์„ ๊ฒฝ์šฐ์— ๋ฉ”์ธ ํ™ˆํƒญ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ด์ƒํ•˜๊ฒŒ ์ดˆ๊ธฐํ™”๋˜์„œ ๊ทธ๋Ÿฐ์ง€ ํฐ ํ™”๋ฉด์ด ๋œฌ๋‹ค. ๋ทฐ ๊ณ„์ธต ๊ตฌ๋„๋ฅผ ๋ด๋„ FeedVC๊ฐ€ ์•ˆ ๋ถˆ๋Ÿฌ์™€ ์ง„๋‹ค.( userVM์ดˆ๊ธฐํ™” ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ LoginVC์—์„œ ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์„ฑ๊ณต์‹œ์— ๋“ฑ๋กํ•ด์คฌ์ง€๋งŒ ์•ˆ๋ฌ๋‹ค. ์œ„์˜ ๊ฒฝ๊ณ ๋ฉ”์‹œ์ง€์ฒ˜๋Ÿผ UIWindow์— ๋ฃจํŠธ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ ๋“ฑ๋กํ•  ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋‚œ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด,,) viewWillAppear์‹œ์ ์— ๋กœ๊ทธ์ธ ์ปจํŠธ๋กค๋Ÿฌ ํ™”๋ฉด ์ „ํ™˜์„ ํ•ด๋„ ์—ญ์‹œ ์œ„์™€ ๊ฐ™์€ ๊ฒฝ๊ณ  ๋ฉ”์„ธ์ง€๊ฐ€ ๋ฐœ์ƒ๋œ๋‹ค.(viewWillAppear๊นŒ์ง€ ํ•จ์ˆ˜๊ฐ€ ์™„๋ฃŒ๋˜์•ผ ๋น„๋กœ์†Œ ๋ฉ”๋ชจ๋ฆฌ์— ๋ทฐ๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค..์•„๋‹Œ๊ฐ€? ๋” ์•Œ์•„๋ด์•ผ๊ฒ ๋‹ค.)

๋ฉ”์ธ ํ™ˆ ๋ทฐ๊ฐ€ ์™„๋ฒฝํ•˜๊ฒŒ ์ดˆ๊ธฐํ™” ๋œ ์ดํ›„์— ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ณ  ๋‚˜์„œ ๋กœ๊ทธ์ธVC๋ฅผ ์ดˆ๊ธฐํ™” ํ•ด์•ผํ•˜๋Š”๋ฐ ๋ฐฉ๋ฒ•์ด ๋– ์˜ค๋ฅด์ง€ ์•Š์•„์„œ ๋‹ค์–‘ํ•œ ์‹œ๋„๋ฅผ ํ–ˆ๋‹ค. ๊ณ„์† ์”จ๋ฆ„ํ•˜๋˜ ์ค‘ ์ข‹์€ ๋ฐฉ๋ฒ•์ด ๋– ์˜ฌ๋ž๋‹ค. ์›๋ž˜ ๋‚ด๊ฐ€ ๊ตฌํ˜„ํ•œ ๋กœ๊ทธ์ธ ํ™•์ธ ์ฝ”๋“œ๋Š” ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ์ž์˜ current ์ •๋ณด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์— ๋ฌด์กฐ๊ฑด ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ presentํ•˜๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ–ˆ์—ˆ๋‹ค. isLogin ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ๋ฉ”์ธ ํ™ˆํƒญ์ปจํŠธ๋กค๋Ÿฌ์˜ ๋ฉ”๋ชจ๋ฆฌ ๋กœ๋“œ์‹œ์ ์—์„œ ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ์— ๋Œ€ํ•œ bool ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ๋ทฐ ๋กœ๋“œ๊ฐ€ ์™„๋ฒฝํ•˜๊ฒŒ ๋œ ํ›„๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋ณ€์ˆ˜๋“ค์ด ์ดˆ๊ธฐํ™” ๋œ ์‹œ์ ์ธ didSet์„ ํ†ตํ•ด์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.. (ํ•˜ํ•˜)

๋กœ๊ทธ์•„์›ƒ ํ›„ ๋‹ค๋ฅธ ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ์‹œ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ ๊ณ„์ • ์ •๋ณด ์—…๋ฐ์ดํŠธ ์•ˆ๋˜๋Š”๊ฒƒ ๊ณ ์นจ
๋กœ๊ทธ์•„์›ƒ ํ›„ ๋กœ๊ทธ์ธ์‹œ UserService.fetchCurrentUserInfo(completion:)์—์„œ current user๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜จ๋‹ค. ์ด๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ ๋„ํ๋จผํŠธ key๊ฐ’์ธ uid๋ฅผ Auth.auth().currentUser๋กœ ๋ฐ›์•„์˜จ๋‹ค. ๊ทผ๋ฐ ์ด๊ฒŒ ๋ฐ”๋กœ ๋ฐ”๋กœ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.(์™œ ๊ทธ๋Ÿฐ์ง„ ๋ชจ๋ฅด๊ฒ ๋‹ค. ์•ฑ์„ ์ข…๋ฃŒํ•˜๊ฑฐ ์žฌ์ ‘์†ํ•ด์•ผ๋งŒ ๋น„๋กœ์†Œ ๋ฐ˜์˜์ด ๋œ๋‹ค.) ๊ทธ๋ž˜์„œ ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๋กœ๊ทธ์ธ ํ•  ๋•Œ (handleIsLoginAccount) ๋ฐ”๋กœ ๋ฐ˜ํ™˜๋ฐ›๋Š” ๊ฒฐ๊ณผ๋Š” ๋”ฐ๋ˆ๋”ฐ๋ˆํ•˜๊ฒŒ ๋ฐฉ๊ธˆ ๋กœ๊ทธ์ธ ๋œ ์‚ฌ์šฉ์ž์˜ uid๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์ด์ ์„ ์ด์šฉํ–ˆ๋‹ค.

ํ˜„์žฌ ์—๋Ÿฌ

๊ณ„์†์ ์œผ๋กœ ํ™•์ธํ•ด๋ณธ ๋ฐ” x

์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…

Error Domain=FIRAuthErrorDomain Code=17008

  • ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์ด๋ฉ”์ผ, ๋น„๋ฒˆ ๋งŒ๋“  ๊ฑฐ ๋“ฑ๋กํ•  ๋•Œ ์ด๋ฉ”์ผ์€ ์ด๋ฉ”์ผ์˜ ๊ทœ์น™์„ ์ง€์ผœ์•ผํ•œ๋‹ค.

NSLocalizedFailureReason" : "Password should be at least 6 characters"

  • ๋น„๋ฒˆ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉ์ž๋Š” ์ตœ์†Œํ•œ 6์ž๋ฆฌ ๋„˜๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

  • ํ•œ๊ฐ€์ง€ ๊ถ๊ธˆํ•œ ์ ์€ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ๋“ฑ๋ก๋œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต์‹œ์— result๋Š” ๋ฐ”๋กœ ์‚ฌ์šฉ์ž์˜ account ๋ฐ˜์˜์ด ๋˜๋Š”๋ฐ ์™œ Auth.auth().currentUser๋Š” ์•ฑ์„ ์žฌ์‹œ์ž‘ ํ•˜๊ธฐ ์ „๊นŒ์ง€ ์ด์ „ ๋กœ๊ทธ์ธ๋œ ๊ณ„์ • ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ๊ฒƒ์ผ๊นŒ?

HotCoffee Postman ์‚ฌ์šฉ!!

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2022-09-07 แ„‹แ…ฉแ„’แ…ฎ 12 43 00

์‰ฝ๊ฒŒ ์„œ๋ฒ„์— GET์œผ๋กœ ๋ฐ์ดํ„ฐ ํ™•์ธํ• ์ˆ˜๋„์žˆ๊ณ  POST๋กœ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ค„ ์ˆ˜๋„ ์žˆ๋‹ค.

์ดˆ๊ธฐ MVCํŒจํ„ด์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ apiํŒŒ์‹ฑํ›„ tableViewCell ๊ตฌ์„ฑ.

์ดˆ๊ธฐ๊ตฌํ˜„

news API๋ฅผ Alamofire๋กœ ํŒŒ์‹ฑํ•œ json Object๋ฅผ ์šฐ์„  ๊ทธ๋ƒฅ Controller๋ฅผ ํ†ตํ•ด tableViewCell์„ ๊ตฌ์„ฑํ–ˆ๋‹ค.
์ด์ œ Controller๊ฐ€ ์•„๋‹ˆ๋ผ ViewModel์˜ ๊ด€์ ์—์„œ ์–ด๋–ป๊ฒŒ View์— ๊ด€์—ฌํ•˜๋Š”์ง€ ๊ณต๋ถ€ํ•  ๊ฒƒ์ด๋‹ค.

[Clone/Instagram] Firebase ๊ตฌํ˜„ | ๋ณต์Šต & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋… #5

Firestore Database๋กœ ํšŒ์›๊ฐ€์ž… ๊ตฌํ˜„

๊ตฌํ˜„ ์˜์ƒ

๋Š๋‚€์ 

์ด๋ฒˆ์—๋Š” ํŒŒ์ด์–ด๋ฒ ์ด์Šค๋ฅผ ์ฒ˜์Œ ๋‹ค๋ค˜๊ธฐ์— ๊ฐ•์˜๋ฅผ ๋ณด๋ฉฐ ๊ตฌํ˜„ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ณ„์† ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.( ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” ์˜ฌ๋ผ๊ฐ”๋Š”๋ฐ AuthService.registerUserํ•จ์ˆ˜์˜ completion ํด๋กœ์ €์˜ error.localizedDescription์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ๊ฒฌ๋ฌ๋‹ค.)

์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ๊ฐœ๋…

  • firestore์—์„œ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•

Firestore.firestore().collection("users").document(uid).setData(data, completion: completion)

  1. collection์ด๋ฆ„ ์ •์˜ -> users๋กœ ์ •ํ•จ
  2. ๋„ํ๋จผํŠธ ์ด๋ฆ„ ์ •์˜ -> uid๋กœ ๊ฐ’์„ ๊ฐ€์ง
  3. ๋„ํ๋จผํŠธ์— ํ•ด๋‹นํ•˜๋Š” ๋ฐ์ดํ„ฐ ์ •์˜ ->data๋Š” RegistrationViewModel ๋ชจ๋ธ์ž„

  • ๋กœ๊ทธ์ธ์‹œ ์ •๋ณด๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผํ•˜๋Š”๊ฐ€?
  1. ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์ด ๋ˆŒ๋ฆด์‹œ ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์ •๋ณด๊ฐ€ ์žˆ๋‹ค. ์ด ์ •๋ณด๋ฅผ ํŒŒ๋ฒ ์— ๋ฐ”๋กœ ์—…๋กœ๋“œ ํ•˜๊ธฐ ์ „์— ์šฐ์„  ์ด๋ฏธ์ง€๋ฅผ ๋”ฐ๋กœ ์ฒ˜๋ฆฌ ํ•ด์•ผ ํ•œ๋‹ค. ๋กœ๊ทธ์ธ ์ด๋ฉ”์ผ ๋น„๋ฒˆ ๋“ฑ์˜ ์ •๋ณด๋Š” Firebase Database์— ์ €์žฅํ•˜๋Š”๋ฐ ์ด๋•Œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฏธ์ง€์˜ ๊ฒฝ์šฐ UIImage๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆœ ์—†์–ด์„œ data๋‚˜ url ์ฃผ์†Œ๋ฅผ JSON์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ด๋ฏธ์ง€๋Š” Storage์— ๋”ฐ๋กœ ์ €์žฅ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ๋จผ์ € ์ฒ˜๋ฆฌํ•˜๊ธฐ ์ „์— ์ด๋ฏธ์ง€๋ถ€ํ„ฐ Storage์— ์—…๋กœ๋“œ ํ•˜๊ณ  ์„ฑ๊ณต์ ์œผ๋กœ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ์—…๋กœ๋“œ ๋ฌ๋‹ค๋ฉด ๊ทธ url์„ ํฌํ•จํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ํšŒ์›๊ฐ€์ž… ์ •๋ณด๋ฅผ FirestoreDatabase์— ์˜ฌ๋ฆฐ๋‹ค.

  2. ์ด๋ฏธ์ง€ ์ž์ฒด๋ฅผ ์˜ฌ๋ฆฌ๊ณ  ๋‚ด๋ ค๋ฐ›์„ ๊ฒฝ์šฐ์— ์šฉ๋Ÿ‰์ด ํฌ๊ธฐ ๋•Œ๋ฌธ์— jpegData(compressionQuality:)๋ฅผ ํ†ตํ•ด ํ•ด์ƒ๋„๋ฅผ ์•ฝ๊ฐ„ ๋‚ฎ์ถ”์–ด์„œ Storage().storage().reference(withPath:)๋ฅผ ํ†ตํ•ด ์ €์žฅ๋˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•œ ํ›„์— ์ด ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€๋ฅผ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ์˜ฌ๋ฆฐ๋‹ค. ์—…๋กœ๋“œ๋œ ์ด๋ฏธ์ง€์˜ url๋˜ํ•œ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์ด url์„ ํฌํ•จํ•ด์„œ Firestore Database ํ•„๋“œ์— ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

แ„‰แ…ก0

  1. Firestore Database ํ•„๋“œ์— ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋“ฑ๋กํ•˜๊ธฐ ์œ„ํ•ด
    Auth.auth().createUser(withEmail:password:)๋ฅผ ํ†ตํ•ด ๋จผ์ € ์‚ฌ์šฉ์ž ๋“ฑ๋ก์„ ํ†ตํ•œ user ์‹๋ณ„์ž๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

createUser๋ฅผ ํ†ตํ•ด์„œ ๊ฐ ์‚ฌ์šฉ์ž๋Š” ์ž์‹ ๋งŒ์˜ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค. firestore()์˜ collection("users").document(uid).setData()์— ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ธฐ์—
users๋Š” uid๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ๊ณ  ๊ทธ uid๋Š” .setdata ํ•„๋“œ ์ •๋ณด๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์žˆ๋‹ค.

แ„‰แ…ก2

createUser์˜ completion์—์„œ ์—๋Ÿฌ๊ฐ€ ์—†๋‹ค๋ฉด ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๊ฐ€ ๋“ฑ๋ก๋จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ํŠน๋ณ„ํ•œ ์‹๋ณ„ ์ธ์Šคํ„ด์Šค๋Š” result?.user.uid๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

์žฌ ์ •๋ฆฌํ•˜์ž๋ฉด

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ 2. ์˜ ์ด๋ฏธ์ง€ ์šฐ์„  ์—…๋กœ๋“œ ์ดํ›„์— url ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ์‚ฌ์šฉ์ž์˜ ํšŒ์›๊ฐ€์ž… data๋Š” firestore Database์— ์ €์žฅํ•  ๊ฒƒ์ด๋‹ค.

แ„‰แ…ก1

์ด ๊ตฌ์กฐ๋Š” firestore Database์—์„œ ๊ตฌํ˜„ํ•œ ๊ตฌ์กฐ์ด๋‹ค.(RegistrationViewModel -> JSON)

ํŒŒ์ด์–ด์Šคํ† ์–ด๋Š” ๋‹ค์–‘ํ•œ ์ปฌ๋ž™์…˜๋“ค์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. (์•Œ๋ฆผ, ํฌ์ŠคํŠธ, ์‚ฌ์šฉ์ž ์ •๋ณด ๋“ฑ๋“ฑ) (์—”ํ„ฐํ‹ฐ๋กœ ์ดํ•ดํ•˜๊ณ  ์‹ถ๋„ค,,) ์ปฌ๋ž™์…˜์€ Firestore.firestore().collection() ์„ ํ†ตํ•ด ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ปฌ๋ž™์…˜์—๋Š” ๊ฐ๊ฐ์˜ ๋ฌธ์„œ๊ฐ€ ์žˆ๋‹ค. ์ด ๋ฌธ์„œ๋Š” ๊ฐ๊ฐ์˜ ์‚ฌ์šฉ์ž ์ •๋ณด ํ…Œ์ด๋ธ”(ํ•„๋“œ)์„ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•œ ํŠน๋ณ„ํ•œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. document์˜ ์ด๋ฆ„์€ ..collection("users").document(ํŠน๋ณ„ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฐ’) ์„ ํ†ตํ•ด ์ •์˜ํ•œ ํ›„์— ์ด ํŠน๋ณ„ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฐ’์— JSONํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ๋‹ค.(ํ•„๋“œ)

ํ•œ๋งˆ๋””๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ฃผ์ œ๋กœ ๋‚˜๋‰  ์ˆ˜ ์žˆ๋Š” ์ปฌ๋ž™์…˜ ์ง‘ํ•ฉ ์ค‘ ํ•œ ์ปฌ๋ž™์…˜์€ ์ด ์ปฌ๋ž™์…˜์˜ data modeling ์—”ํ„ฐํ‹ฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ค์–‘ํ•˜๊ฒŒ ์ •์˜๋œ ํ…Œ์ด๋ธ”๋“ค์˜ ๋ฐ์ดํ„ฐ(ํ•„๋“œ)๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ ํ…Œ์ด๋ธ”๋“ค์„ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ๋ฌธ์„œ๋‹ค. ์ด ๋ฌธ์„œ๋“ค๋กœ ํŠน์ •ํ•œ ํ•œ ์ปฌ๋ž™์…˜์ด ๊ตฌ์„ฑ๋œ๋‹ค.

์ด ๊ฐ•์˜์—์„  ์ปฌ๋ž™์…˜์— users๋ผ๋Š” ์ปฌ๋ž™์…˜์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ปฌ๋ž™์…˜์„ ๊ตฌ์„ฑํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฌธ์„œ๋Š” uid๋ฅผ ํ†ตํ•ด์„œ ๋ฌธ์„œ๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค. ๊ทผ๋ฐ ์ด uid๋Š” Auth.auth().createUser(withEmail:password:)๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค์–ด์ง„ ๊ณ ์œ ์˜ ์‹๋ณ„์ž์ด๋ฏ€๋กœ ๋ฌธ์„œ์˜ ๊ฐ’๋“ค์€ ์ง‘ํ•ฉ(Set)์˜ ์†์„ฑ์„ ์ง€๋‹ˆ๊ฒŒ ๋œ๋‹ค. ๋ฌธ์„œ๋ฅผ ์—ด์–ด๋ณด๋ฉด ํ•„๋“œ๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ ์ด ํ•„๋“œ์— RegistrationViewModel์˜ ํŠน์ • ์‚ฌ์šฉ์ž ํšŒ์›๊ฐ€์ž… ๋ฐ์ดํ„ฐ JSON๊ตฌ์กฐ๊ฐ€ ์ €์žฅ๋œ๋‹ค.

์œฝ;; AuthService.registerUser(withUserInfo:)์—์„œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—๋Š” ์„ฑ๊ณต์ ์œผ๋กœ ์œ ์ €์˜ ์ •๋ณด๊ฐ€ ์—…๋กœ๋“œ ๋˜๋Š”๋ฐ ์ฐจ๊พธ๋งŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค nil์ฒ˜๋ฆฌ๊ฐ€ ๋˜์—ˆ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ ์•Œ๊ณ ๋ณด๋‹ˆ ์—๋Ÿฌ์ฒ˜๋ฆฌ๋ฅผ ์ž˜๋ชปํ•œ ๋‚ด ์‹ค์ˆ˜์˜€๋‹ค... ๊ทธ๋ž˜๋„ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์— ๋Œ€ํ•ด ์ข€ ๋” ์•Œ์•„๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.


์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋…

  • jpegData(compressionQuality)

์›๋ž˜๋Š” pngData()๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ์ด๋ฒˆ์— ์ƒˆ๋กญ๊ฒŒ jpegData()์— ๋Œ€ํ•ด ์•Œ๊ฒŒ ๋ฌ๋‹ค.

  • ํŒŒ์ด์–ด๋ฒ ์ด์Šค ํ”„๋กœ์ ํŠธ ๋“ฑ๋ก,,
  1. ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
  2. Authentication์—์„œ ๋กœ๊ทธ์ธ ์ œ๊ณต์—…์ฒด ์ง€์ •
  3. storage bucket ์„ค์ •. ์•ฑ์—์„œ ๋กœ๊ทธ์ธ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์ง„์„ requestํ–ˆ๋‹ค๋ฉด ๋”ฐ๋กœ ์„ค์ •ํ•ด์ค˜์•ผํ•œ๋‹ค. Rules์—์„œ ์‚ฌ์šฉ์ž์˜ ์Šน์ธ ์ „์— ์‚ฌ์ง„ ์—…๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ๋„๋ก setupํ•ด์•ผํ•œ๋‹ค.

allow read, write: if request.auth != null || request.auth == null ;

  1. db์ถ”๊ฐ€ํ•˜๋Š”๋ฐ ios -> ๋ฒˆ๋“ค์•„์ด๋”” ๋“ฑ๋“ฑ ์ž…๋ ฅ.

Hotcoffee ์™„๋ฃŒ

แ„‹แ…ชแ†ซแ„…แ…ญ
แ„‘แ…ฉแ„‰แ…ณแ„แ…ณแ„†แ…ขแ†ซ getแ„€แ…งแ†ฏแ„€แ…ช
แ„‹แ…ฆแ„…แ…ฅ

์ค‘๊ฐ„์— ๋งˆ์ฃผํ•œ ์—๋Ÿฌ๋Š” POST๋กœ data๋Š” ์ž˜ ์ „์†ก๋ฌ์ง€๋งŒ ์ด์ „ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐ€์ง€์ง€ ์•Š๊ณ 

UITableViewAlertForLayoutOutsideViewHierarchy error: Warning once only (iOS 13 GM) ์ด ์—๋Ÿฌ๋ฅผ ๋งˆ์ฃผํ–ˆ๋‹ค.
์•„๋งˆ ์˜์ƒ๋ณด๋ฉด์„œ ๋”ฐ๋ผํ–ˆ์ง€๋งŒ ํ™”๋ฉด ์ „ํ™˜๊ณผ์ • ๋“ฑ๋“ฑ ๋‹ค๋ฅด๊ฒŒ ํ–ˆ๊ธฐ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค... ์›์ธ์€ ์ด๋ฏธ ํ…Œ์ด๋ธ”๋ทฐ๊ฐ€ ์กด์žฌํ•จ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ถ”๊ฐ€์ ์ธ Order๋ฅผ ๋„ฃ์–ด์„œ ๊ณง๋ฐ”๋กœ ํ…Œ์ด๋ธ” ๋ทฐ ์˜ ์…€์„ ํ•œ์นธ๋Š˜๋ฆฌ๋„๋กํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•œ ์—๋Ÿฌ์ธ ๊ฒƒ ๊ฐ™๋‹ค.

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€ viewWillAppear์— tableView.reloadData()๋ฅผ ์‹คํ–‰ํ•ด์ฃผ๊ณ  ๊ทธ๋ƒฅ ์˜ค๋” ๋ฐ›์œผ๋ฉด ์ฒซ๋ฒˆ์งธ ๋ฉ”์ธํ™”๋ฉด์—์„œ ๋‹จ์ง€ list์— ๊ฐ’๋งŒ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค.

[Clone/Instagram] ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€, ๋ฆฌํŽ™ํ„ฐ๋ง | ๋งˆ์ฃผํ•œ ์—๋Ÿฌ & ๊ฐœ๋… ์ •๋ฆฌ(UIResponder) #14 - 1

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€, ๋ฆฌํŽ™ํ„ฐ๋ง

  • ํŠน์ • ์‚ฌ์šฉ์ž ๊ฒ€์ƒ‰ ํ›„ ํ•ด๋‹น ํ”„๋กœํ•„ ์•„๋ž˜์˜ posts ์ค‘ ํ•˜๋‚˜ ํด๋ฆญ์‹œ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ๋“ค์–ด๊ฐ
  • PostController์—์„œ ๋ถ€๋ถ„์ ์œผ๋กœ ๋™์‹œ์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ async let. or TaskGroup๋กœ ๋™์‹œ์„ฑ ์ ์šฉ.
  • API fetch ์ „๋ถ€ async await ๋ฆฌํŽ™ํ„ฐ๋ง

๋งˆ์ฃผํ•œ ๋ฌธ์ œ1

FeedController์—์„œ ๋ฆฌํ”„๋ ˆ์‹œํ•  ๋•Œ ์—๋Ÿฌ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. FeedController์—์„œ ๋ฆฌํ”„๋ ˆ์‰ฌ๋ฅผ ํ•˜๋ฉด Index out of range๊ฐ€ ๋œฌ๋‹ค.

แ„‹แ…ฆแ„…แ…ฅ0

แ„‹แ…ฆแ„…แ…ฅ2

FeedController ๋ณ€์ˆ˜ posts๋ฅผ ํ™”๋ฉด์— ๋„์šด๋‹ค. ๋ฆฌํ”„๋ ˆ์‹œํ•  ๋•Œ ํ˜„์žฌ ์žˆ๋Š” posts๋ณ€์ˆ˜๋ฅผ RemoveAllํ•œ๋‹ค.

แ„‹แ…ฆแ„…แ…ฅ1

๊ทธ ํ›„ fetchPosts() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ๋ฐ์ดํ„ฐ๋“ค์„ fetchํ•œ ํ›„์— posts(collectionView cell ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ์ดํ„ฐ) ๊ฐ’์„ ๊ฐฑ์‹ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ง์ž‘๋˜๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” fetchPosts()๋Š” asyncํ•จ์ˆ˜์ธ ์ ์ด๋‹ค. Task()์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ fetchํ•ด์•ผ posts๊ฐ€ ๊ฐฑ์‹ ๋œ๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ์€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ผ๋Š” ๊ฒƒ.

refresh ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ ํ›„ handleRefresh()๋กœ ํฌ์ŠคํŠธ๋Š” ์‚ญ์ œ๋ฌ๋‹ค. ๋™์‹œ์— ๋ฆฌํ”„๋ ˆ์‰ฌ ๋™์ž‘์œผ๋กœ ์ธํ•ด ์ปฌ๋ž™์…˜ ์…€๋“ค์ด ์•„๋ž˜์„œ ์œ„๋กœ ์˜ฌ๋ผ์˜ค๋ฉด์„œ ์•„๋ž˜ ๋‚˜์˜ฌ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” 1~2๊ฐœ์˜ cell์„ dequeueReusableCell์—์„œ ๊บผ๋‚ด์˜จ๋‹ค. ์ด๋•Œ posts๋Š” ๊ฐ’์ด ์—†์œผ๋ฏ€๋กœ Index out of range ์˜ค๋ฅ˜๊ฐ€ ๋œจ๋Š” ๊ฒƒ์ด๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋ฆฌํ”„๋ ˆ์‹œ ์ด๋ฒคํŠธ ํ—จ๋“ค๋Ÿฌ์—์„œ posts.removeAll()์ดํ›„์— ๋ฐ”๋กœ ์ปฌ๋ž™์…˜ ๋ทฐ๋ฅผ ๋ฆฌ๋กœ๋“œ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ collectionView์˜ cell์˜ ๊ฐœ์ˆ˜๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋‹ค๋ฅธ ๋Œ€์•ˆ์ด ์žˆ๊ธดํ•œ๋ฐ... ๊ทธ๋ƒฅ ์ด ๋ฐฉ๋ฒ•์ด ๋‚˜์˜์ง€ ์•Š์€๊ฒƒ ๊ฐ™๋‹ค

๋งˆ์ฃผํ•œ ๋ฌธ์ œ2

Concurrency๋กœ taskGroup๊ฐ€ ์•„๋‹Œ async let ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค. In ProfileViewModel.swift

fetchToCheckIfUserIsFollowed() //์‚ฌ์šฉ์ž๊ฐ€ ๋‚˜๋ฅผ ํŒ”๋กœ์šฐํ–ˆ๋Š”์ง€(bool)

fetchUserStats() //์‚ฌ์šฉ์ž์˜ ํŒ”๋กœ์šฐ, ํŒ”๋กœ์ž‰ ์ƒํƒœ

fetchImage(profileUrl:) ์‚ฌ์šฉ์ž์˜ ์ด๋ฏธ์ง€

์ด ์„ธ๊ฒŒ๋ฅผ ๋™์‹œ์— fetch ํ•˜๋ ค๊ณ ํ•œ๋‹ค.

4

๊ฐ๊ฐ์˜ async ํ•จ์ˆ˜๋“ค์€ ์•ˆ์—์„œ ์—๋Ÿฌ๋ฅผ ์žก์•„์ฃผ๊ธฐ ๋•Œ๋ฌธ์— async let ์„ ์„ ์–ธํ•  ๋•Œ ํ•จ์ˆ˜ throw ์ฒ˜๋ฆฌ ์ƒ๊ฐํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

5

์ด๋ ‡๊ฒŒ Concurrency๋ฅผ ์„ ์–ธํ–ˆ๋‹ค๋ฉด ํƒ€์ž… ํ‘œํ˜„์ด ambigousํ•˜๋‹ค๋Š” ๊ฒฝ๊ณ ๊ฐ€ ๋‚˜์˜จ๋‹ค. ์™œ ๊ทธ๋Ÿด๊นŒ

๊ณฐ๊ณฐํžˆ ์ƒ๊ฐํ•ด๋ดค๋Š”๋ฐ 249๋ผ์ธ์—์„œ ๊ฒฐ๊ตญ ๋ฐฐ์—ด์˜ ๊ฐ ์›์†Œ๋Š” Bool, Userstats, UIImage ์›์†Œ๊ฐ€ ์žˆ์„ ๊ฑฐ๊ณ  ์ด ์„ธ๊ฐ€์ง€ ํƒ€์ž…์„ ๋ชจ๋‘ ํ—ˆ์šฉํ•˜๋Š” ๋ฐฐ์—ด์€ ์—†๋‹ค. ๊ทธ๋ž˜์„œ ๋ฐฐ์—ด์˜ ํƒ€์ž…์€ Any๊ฐ€ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ํ”„๋กœํผํ‹ฐ ๋ณ€์ˆ˜์— ๊ฐ’์„ ๋Œ€์ž…ํ•  ๋•Œ ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

6

์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜์žˆ๋Š” ํŠœํ”Œ์„ ์‚ฌ์šฉํ•ด์„œ ํ•ด๊ฒฐํ–ˆ๋‹ค.

๋งŒ์•ฝ ๊ฐ๊ฐ์˜ ํ•จ์ˆ˜์•ˆ์—์„œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋ผ๋ฉด

async let ๋ณ€์ˆ˜ = try async ํ•จ์ˆ˜ ๋ฅผ ํ•œ ํ›„์—

let _ = try await [๋ณ€์ˆ˜1,๋ณ€์ˆ˜2,...] ์ด๋Ÿฐ์‹์œผ๋กœ ํ•  ๊ฒฝ์šฐ

๊ฐ๊ฐ์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ์ข‹์„์ง€ ๊ณ ๋ฏผํ–ˆ๋Š”๋ฐ ์•„์ง ํ•ด๊ฒฐ๋ฐฉ์•ˆ์„ ๋– ์˜ฌ๋ฆฌ์ง„ ๋ชปํ–ˆ๋‹ค.

์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ๊ฐœ๋…1

  • cell์˜ ํŠน์ • ๊ฐ์ฒด ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ ํ™”๋ฉด ์ „ํ™˜

FeedCell์—์„œ ๋Œ€ํ™” ๋ฒ„ํŠผ ํด๋ฆญํ•˜๋ฉด navigation stack์„ ํ†ตํ•ด CommentController Scene์„ ๋ณด์—ฌ ์ฃผ๋ ค๊ณ  ํ•œ๋‹ค.

t7

FeedCell์˜ ํƒ€์ž…์€ UICollectionViewCell์ด๋‹ค. ์ƒ์œ„ View๋Š” collectionView์ด๋‹ค. ๊ทธ๋ž˜์„œ UICollectionReueableView ํƒ€์ž…์— ์†ํ•˜๋Š”๋ฐ ์ด๋Š” UIView ํƒ€์ž…์ด๋‹ค. ์ฆ‰ UINavigationController๋ฅผ ์ƒ์†๋ฐ›์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— pushViewController(:aninamted:) ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๋˜ํ•œ UIViewController์˜ present(:animated:) ๋ฉ”์†Œ๋“œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๊ฒฐ๊ตญ FeedCell์—์„œ ํ™”๋ฉด์„ ์ „ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” FeedCell์„ ํ˜ธ์ถœํ•˜๋Š” FeedController์˜ ํž˜์„ ๋นŒ๋ ค์•ผ ํ•œ๋‹ค.

์ด๋ฒคํŠธ๋Š” FeedCell์˜ @objc func didTapCommnet(_:)์—์„œ ๋ฐœ์ƒํ•œ๋‹ค. ์–ด๋–ป๊ฒŒ FeedController์˜ UIViewController๋‚˜ UINavigationController์˜ ๊ฐ์ฒด๋ฅผ ๋นŒ๋ ค์„œ ํ™”๋ฉด ์ „ํ™˜์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

ํ˜„์žฌ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€์ด๋‹ค.

  1. delegate ์ฑ„ํƒํ•ด์„œ FeedController์— FeedCell์˜ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ์ฑ„ํƒ.

  2. Combine์‚ฌ์šฉํ•ด์„œ publiser์˜ published ํ๋ฆ„์— ๋”ฐ๋ฅธ ํ™”๋ฉด ์ „ํ™˜.

  3. delegate ์‚ฌ์šฉ์˜ ๊ฒฝ์šฐ

  • ํ”„๋กœํ† ์ฝœ ์ถ”๊ฐ€

8

  • FeedCell์— ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€.

9

  • FeedCell์—์„œ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•œ ํ•จ์ˆ˜ ์‚ฌ์šฉ.

10

๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํƒ€์ž…์˜ ์˜์กด์„ฑ์„ ๊ฐ–๋Š” delegate๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•œ ํ›„ didTapComment(_:) ํ•จ์ˆ˜์—์„œ ํ”„๋กœํ† ์ฝœ์˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  • FeedController์— ํ”„๋กœํ† ์ฝœ ์ฑ„ํƒ ํ›„ ๊ตฌํ˜„.

11

์ด์ œ ํ™”๋ฉด ์ „ํ™˜ ํ•  ๋กœ์ง์€ FeedController์—์„œ FeedCellDelegateํ”„๋กœํ† ์ฝœ ์ฑ„ํƒ ํ›„ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.

  • FeedController์˜ collectionView(_:cellForItemAt:)์—์„œ ๊ฐ ์…€๋งˆ๋‹ค delegate ์ž์‹ ์œผ๋กœ ๋“ฑ๋ก

15@@@@

  1. Combine ์‚ฌ์šฉ์˜ ๊ฒฝ์šฐ
  • FeedCell์—์„œ publiser์™€ anyCancellable ์„ ์–ธ

12

  • FeedCell์—์„œ publisher์—๊ฒŒ published.

13

  • FeedController์˜ collectionView(_:cellForItemAt:)์—์„œ ๊ฐ ์…€๋งˆ๋‹ค cell์—์„œ publiser์˜ input stream ๊ตฌ๋….

14

  • ์ฝ”๋“œ์ •๋ฆฌ

FeedController์˜ collectionView(_:cellForItemAt:) ์—์„œ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— cell์˜ ๋ฉ”์„œ๋“œ๋กœ ๋บ๋‹ค.

17

FeedController์—์„  ๊ทธ๋ƒฅ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋งŒํ•˜๋ฉด๋œ๋‹ค.

16

์ปด๋ฐ”์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ ๋‘˜๋‹ค ๋น„์Šทํ•œ ๊ฐœ๋…์ธ ๊ฒƒ ๊ฐ™๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ์€ cell ๋‚ด๋ถ€ ํด๋ž˜์Šค์—์„  ํ™”๋ฉด ์ „ํ™˜์„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฐœ๋…์„ ์ƒˆ๋กœ ์•Œ๊ฒŒ ๋ฌ๋‹ค.

๊ทผ๋ฐ ์ปด๋ฐ”์ธ์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ํ™”๋ฉด ๋ช‡ ๋ฒˆ ๋‚ด๋ฆฐ ํ›„์— ์…€์˜ ๋ฉ”์„ธ์ง€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ ์žฌ์‚ฌ์šฉํ ๋ณด๋‹ค ๋นจ๋ฆฌ ํ„ฐ์น˜๊ฐ€ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

์žฌ์‚ฌ์šฉ ํ๋กœ ๊บผ๋‚ด์ง€๊ธฐ ์ „์— ์žˆ๋Š” ํฌ์ŠคํŠธ cell๋กœ ๋“ค์–ด ๊ฐ”๋‹ค๊ฐ€ ๋’ค๋Šฆ๊ฒŒ ์žฌ์‚ฌ์šฉ ํ์— ์˜ํ•ด ๊บผ๋‚ด์ง„ cell๋กœ ์ธํ•œ ํฌ์ŠคํŠธ๊ฐ€ ๊ฐฑ์‹ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ž˜์„œ ๋˜ ๋Œ€ํ™” ์ฐฝ์œผ๋กœ ๋“ค์–ด๊ฐ€์ง„๋‹ค. subscribeFromDidTapPublisher์—์„œ ๋“ค์–ด๊ฐˆ ๋•Œ๋งˆ๋‹ค ๊ธฐ์กด didTapPublisher์˜ ๊ฐ’์„ ๋‹ค์‹œ nil ์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋‹ค.

์ƒˆ๋กœ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…2

18

ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜๊ธฐ ์œ„ํ•œ TextField์™€ ๋ฒ„ํŠผ์„ view๋กœ ๋งŒ๋“ค์—ˆ์„ ๋•Œ inputAccessoryView์— ๋‚ด๊ฐ€ ์ปค์Šคํ…€ํ•œ UIView(TextField์™€ ๋ฒ„ํŠผ์ด ์žˆ๋Š”)๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.
inputAccessoryView๋Š” nil์ด๋‹ค. ์ปค์Šคํ…€์œผ๋กœ ์ •์˜ํ•œ ๋ทฐ๋ฅผ system์—์„œ ์ง€์›ํ•ด์ฃผ๋Š” input view๋กœ ๋ถ€์ฐฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” inputAccessoryView๋ฅผ ์žฌ ์ •์˜ํ•ด์„œ UIResponder์—์„œ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์•ผ ํ•œ๋‹ค.

Responder

UIResponder๋Š” UIKit app์—์„œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ์˜ ๋ผˆ๋Œ€์ด๋‹ค. ๋งŽ์€ ํ‚ค ์˜ค๋ธŒ์ ํŠธ๋Š” responder๋‹ค.(such as UIApplicaiton, UIViewController, UIView) ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด UIKit๋Š” ์•ฑ์˜ responder ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ๋ฐœ์†กํ•ด์ค€๋‹ค.

  • ์ด๋ฒคํŠธ?

touch event, motion event, remote- control evetn, press event๊ฐ€ ๋Œ€ํ‘œ์ ์œผ๋กœ ์žˆ๋‹ค. ํŠน์ • ํƒ€์ž…์˜ ์ด๋ฒคํŠธ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด์„  responder๊ฐ€ ํŠน์ • ๋ฉ”์„œ๋“œ์™€ ์ผ์น˜ํ•˜๊ฒŒ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ ์˜ˆ๋กœ ํ„ฐ์น˜ ์ด๋ฒคํŠธ์—์„  responder๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” touchesBegan(:with:), touchesEnded(:with:) ๋“ฑ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ํ„ฐ์น˜๋ฅผ ์˜ˆ๋กœ ๋“ค์ž๋ฉด responder๋Š” ์ด๋ฒคํŠธ ์ •๋ณด๋ฅผ UIKit์—์„œ ์ œ๊ณต ๋ฐ›๊ณ  ํ„ฐ์น˜๋‚˜ ์•ฑ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์•Œ๋งž๊ฒŒ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ์ถ”์ ํ•˜๊ณ  ๋ฐ”๊พผ๋‹ค.

์ด๋ฒคํŠธ ํ—จ๋“ค๋ง์€ UIKit responder๋“ค์ด ๋˜ํ•œ ์•ฑ์—์„œ ์•ž์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์„ ์ด๋ฒคํŠธ ๋˜ํ•œ ๊ด€๋ฆฌํ•œ๋‹ค. ์ฃผ์–ด์ง„ responder๊ฐ€ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด responder chain ์˜ ๋‹ค์Œ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ˜ธ์ถœํ•œ๋‹ค. UIKit๋Š” responder chain์„ ๋™์ ์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค. ๋ฏธ๋ฆฌ ์ •์˜๋œ ๊ทœ์น™๋“ค์„ ์‚ฌ์šฉํ•ด ์–ด๋Š object๊ฐ€ ๋‹ค์Œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์„ ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.
๊ทธ ์˜ˆ๋กœ view๋Š” ์ž์‹ ์˜ superView๋กœ ์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ๊ณ„์ธต๊ตฌ์กฐ์˜ root view ์—ฐ๊ฒฐ๋œ viewController๋กœ ์ด๋ฒคํŠธ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

Responder๋Š” UIEvent object๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๊ทผ๋ฐ ์ปค์Šคํ…€ input. input view ๋˜ํ•œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. system's keyboard๊ฐ€ input view์˜ ๊ฐ€์žฅ ๋ช…๋ฐฑํ•œ ์˜ˆ์ œ์ด๋‹ค.

input view๋ž€?

์‚ฌ์šฉ์ž๊ฐ€ ํ™”๋ฉด์—์„œ UITextField ๋˜๋Š” UITextView object๋ฅผ tapํ•  ๋•Œ, The view becoms the first responder and display its input view. ๋ทฐ๋Š” ์ตœ์ดˆ responder๊ฐ€ ๋˜๊ณ  input view๋ฅผ ํ™”๋ฉด์— ๋„์šด๋‹ค. ์—ฌ๊ธฐ์„œ input view๋Š” system keyboard์ด๋‹ค. ์œ ์‚ฌํ•˜๊ฒŒ, ์ปค์Šคํ…€ input view๋ฅผ ๋งŒ๋“ค๊ณ  ๋‹ค๋ฅธ responder๊ฐ€ activate๋  ์ˆ˜ ์žˆ์„ ๋•Œ ํ™”๋ฉด์— ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค. resopnder๋ฅผ ํ†ตํ•œ input view๋ฅผ ์ปค์Šคํ…€ํ•˜๊ณ  ์—ฐ๊ฒฐ์‹œํ‚ค๋ ค๋ฉด inputView ํ”„๋กœํผํ‹ฐ์˜ responder๋ฅผ ๋ทฐ์— ํ• ๋‹นํ•˜๋ฉด ๋œ๋‹ค.

๋‹ค์‹œ ๋งํ•ด Responder๋Š” raw event data๋ฅผ ๋ฐ›๊ณ  ๋‹ค๋ฅธ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ responder object์—๊ฒŒ ํ˜ธ์ถœํ•œ๋‹ค. ์•ฑ์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›๋Š”๋‹ค๋ฉด UIKit ์€ ์ž๋™์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ responder object์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ์ง€์‹œํ•œ๋‹ค. ๊ทธ ์˜ˆ๋กœ first responder๊ฐ€ ์žˆ๋‹ค.

20

๋งŒ์•ฝ์— UITextField์—์„œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด UIKit์€ ์ด๋ฒคํŠธ๋ฅผ text field์˜ ๋ถ€๋ชจ์ธ UIView object์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.( UIWindow์ธ ๋ฃจํŠธ ๋ทฐ์—์„œ ํŒŒ์ƒ๋œ,,) root view์—์„  responder chain์œผ๋กœ ๋‹ค์ด๋ ‰ํŠธ๋กœ root view์ธ UIWindow์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์ „์—!! UIView์™€ ์—ฐ๊ฒฐ๋œ UIViewController์—๊ฒŒ event๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. ๋งŒ์•ฝ window ๋˜ํ•œ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค๋ฉด UIKit๋Š” UIApplication object์—๊ฒŒ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์•„์ง responder chain์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด app delegate์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.

Controls

์ปจํŠธ๋กค์€ action message๋ฅผ ์‚ฌ์šฉํ•ด์„œ target ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋œ object์™€ directํ•˜๊ฒŒ ์†Œํ†ตํ•œ๋‹ค. ์ปจํŠธ๋กค์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์ƒํ˜ธ์ž‘์šฉ์ด ์ผ์–ด๋‚  ๋•Œ, ์ปจํŠธ๋กค์€ action message๋ฅผ ์ž์‹ ์˜ target object์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค. action message๋Š” ์ด๋ฒคํŠธ๊ฐ€ ์•„๋‹Œ๋ฐ, ์—ฌ์ „ํžˆ responder chain์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. target object์˜ control์ด nil์ธ ๊ฒฝ์šฐ์— UIKit๋Š” target object๋กœ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ resopnder chain์„ ํ†ตํ•ด ์ ์ ˆํ•œ action method๋ฅผ ์ทจํ•  ์ˆ˜ ์žˆ๋Š” object๋ฅผ ์ฐพ์„ ๋•Œ๊นŒ์ง€ chain์— ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด๋“ค์„ ์ฐพ์•„๊ฐ„๋‹ค.

Gesture

Gesture recognizer๋Š” ๋ทฐ์—์„œ ํ„ฐ์น˜์™€ ์ž…๋ ฅ ์ด๋ฒคํŠธ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ์—ฐ์†์ ์ธ ํ„ฐ์น˜๋กœ ์ธํ•ด view's gesture๊ฐ€ ์ธ์‹ ์‹คํŒจ ํ•œ๋‹ค๋ฉด, UIKit์€ ๋ทฐ์—๊ฒŒ ํ„ฐ์น˜๋ฅผ ๋ณด๋‚ธ๋‹ค. ๋ทฐ๊ฐ€ ํ„ฐ์น˜์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด UIKit๋Š” responder chain์œผ๋กœ ํ†ต๊ณผ์‹œํ‚จ๋‹ค.

์—ฌ๋Ÿฌ Response chain ์ค‘ ํ˜„์žฌ ์ƒํƒœ์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ€์žฅ ๋จผ์ € ๋ฐ›๋Š”๋‹ค๋ฉด Frist Responder๊ฐ€ ๋œ๋‹ค. ๊ทธ ์˜ˆ๋กœ ํ…์ŠคํŠธ ํ•„๋“œ๋ฅผ ๋ˆ„๋ฅด๊ณ  ํƒ€์ดํ•‘ ํ•  ๊ฒฝ์šฐ First Responder๋Š” Textfiend์ด๋‹ค. ๋งŒ์•ฝ textfield์—์„œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด(๋ชปํ•œ๋‹ค๋ฉด) Resopnder chain์— ์˜ํ•ด ๋‹ค๋ฅธ responder๋กœ ๋„˜๊ธด๋‹ค.

inputView, inputAccessoryView

์œ„์—์„œ๋„ ์„ค๋ช…ํ–ˆ์ง€๋งŒ inputView๋Š” Frist Responder๊ฐ€ ๋  ๋•Œ ์ธ๋ฐ ๋Œ€ํ‘œ์ ์œผ๋กœ system keyboard๋‹ค. UITextField, TextView๊ฐ€ First Responder๊ฐ€ ๋ฌ์„ ๋•Œ ์ž๋™์œผ๋กœ ๋‚˜์˜จ๋‹ค. ๊ทธ๋ž˜์•ผ ํ…์ŠคํŠธ ํ•„๋“œ๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ,, ๊ทผ๋ฐ inputView๋Š” get-only ํ”„๋กœํผํ‹ฐ์ธ๋ฐ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•œ๋‹ค๋ฉด ์ปค์Šคํ…€ input view์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ณ  ๊ทธ๋ ‡๋‹ค๋Š”๊ฑด ํ…์ŠคํŠธ ํ•„๋“œ๋ฅผ ํด๋ฆญํ•œ ํ›„ First Responder๊ฐ€ ๋˜์—ˆ์„ ๋•Œ ์•Œ๋ฆผ์„ ํ†ตํ•œ ๊ธฐ๋Šฅ์ด๋‚˜ picker ๋“ฑ ๋‹ค์–‘ํ•˜๊ฒŒ ๋‹ค๋ฅธ UIViewํƒ€์ž…์˜ object๋ฅผ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค.


autoresizingMask = .flexibleHeight ์ด๊ฑธ ์„ ์–ธํ•  ๊ฒฝ์šฐ superview์˜ ํฌ๊ธฐ, ๋ฐ”์šด์Šค ๋“ฑ์— ๋”ฐ๋ผ ๋†’์ด๊ฐ€ ์ž๋™์ ์œผ๋กœ ์กฐ์ •๋œ๋‹ค. ( in CommentInputAccessoryView.swift )

[Clone/Instagram] SignUp ๊ตฌํ˜„ | ๋ณต์Šต & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋… #4

์ดˆ๊ธฐ ๊ตฌํ˜„ ์˜์ƒ

๊นŒ๋‹ค๋กœ์› ๋˜ ์ 

View์—์„œ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ photo plus๋ฅผ UIImageVIew๋กœ ์„ค์ •ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ œ์Šค์ณ๋ฅผ ์ถ”๊ฐ€ ๋“ฑ๋กํ–ˆ๋Š”๋ฐ ์ด์ƒํ•˜๊ฒŒ๋„ sender๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š๋‹ค๋Š” ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฒ„ํŠผ์— ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค.

  • TextField์— ๋Œ€ํ•ด์„œ

๋ฐ”์ธ๋”ฉ์„ ์ง์ ‘ ๊ตฌํ˜„ ํ›„์— ์ „๋ถ€ ๊ฐ’์ด ๋“ค์–ด์žˆ์„ ๊ฒฝ์šฐ ๋ฒ„ํŠผ์˜ .isEnable true์ฒ˜๋ฆฌํ•ด์•ผํ•˜๋Š”๋ฐ ๋ฐ”์ธ๋”ฉ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ดํ›„์— ๊ฐ’์„ VM์— ๋„ฃ์€ ๋’ค์— ์ „๋ถ€ ๊ฐ’์ด ๋“ค์–ด์žˆ๋Š”์ง€์˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์—ˆ์–ด์•ผ ํ–ˆ๋Š”๋ฐ ๊ฐ’ ์žˆ๋Š”์ง€ ์ฒดํฌํ•˜๋Š” ํ•จ์ˆ˜๋ถ€ํ„ฐ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ”๋žŒ์— ์‚ด์ง ์• ๋ฅผ ๋จน์—ˆ๋‹ค. ํ•™๊ต ๊ณต๋ถ€ํ•˜๊ณ  ํ•˜๋ฃจ ์ง€๋‚˜๊ณ  ๋ณด๋‹ˆ ๋‹จ๋ฒˆ์— ์—๋Ÿฌ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ฝ”ํ…Œ ๊ตฌํ˜„ํ•  ๋•Œ๋„ ๊ทธ๋ ‡๊ณ  ๊ฐ€๋”์€ ๋„ˆ๋ฌด ์ฝ”๋“œ๋งŒ ๋ฐ”๋ผ๋ณด๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ์‰ฌ์šด ๋‹ต๋„ ๋ชป ์ฐพ๋Š”๊ฒƒ ๊ฐ™๋‹ค.

๋ณต์Šตํ•œ ๊ฐœ๋…

  • clipsToBounds์˜ต์…˜

RegistrationController์—์„œ ์ด๋ฏธ์ง€ ํ”ผ์ปค๋กœ ์„ ํƒ๋œ ์ดํ›„์— ์ด๋ฏธ์ง€ ์„ ํƒ ๋ฒ„ํŠผ์˜ cornerRadius๋ฅผ ํ•ด๋‹น ๋ฒ„ํŠผ์˜ ์ ˆ๋ฐ˜์œผ๋กœ ๋‘ฅ๊ธ€๊ฒŒ ์กฐ์ ˆํ–ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ์‚ฌ์ง„์€ ์—ฌ์ „ํžˆ ImagePicker์˜ edited๋œ ๋„ค๋ชจ์˜€๋‹ค. ์•„ํ•˜,, ๋ฒ„ํŠผ์˜ clipsToBounds ์˜ต์…˜์„ true๋กœ ๋ฐ”๊พธ์ง€์•Š์•„์„œ ๋‚ด๋ถ€์˜ View๊ฐ€ ์ž˜๋ฆฌ์ง€ ์•Š์•˜๋˜ ๊ฒƒ..(๊นœ๋นก)

  • withRenderingMode(.alwaysTemplate)

์ด๋ฏธ์ง€์˜ ์ƒ‰ ๋Œ€์‹  ๋‚ด๊ฐ€ ์ง์ ‘ ์ด๋ฏธ์ง€์˜ ์ƒ‰์„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋…

  • ์ปค์Šคํ…€ ๋ทฐ์˜ super.init(frame:) ์— ๊ด€ํ•ด์„œ

UIView๊ด€๋ จ๋œ ๊ฐ์ฒด๋ฅผ ์ปค์Šคํ…€ํ•  ๋•Œ ํ•ญ์ƒ ๊ถ๊ธˆํ–ˆ์—ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ override init(frame: CGRect) ๋ฅผ ๊ตฌํ˜„ํ•ด์„œ super.init(frame:frame)์œผ๋กœ frame์„ ๋„˜๊ฒจ์ค˜์•ผ ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์–ด์•ผ init๊ฐ€ ๊ฐ€๋Šฅํ–ˆ์—ˆ๋‹ค. ๋‚ด ๋ง˜๋Œ€๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•ด๋„ ์–ด์ฐจํ”ผ super.init()์€ ์—†๊ณ  super.init(frame)์ด๋‚˜ .init(coder:)๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ–ˆ์—ˆ์–ด์„œ ๋‚œ ๋งค๋ฒˆ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ปค์Šคํ…€ ๋ทฐ๋“ค์˜ ์˜ต์…˜์„ ๋ถ€์—ฌํ–ˆ์—ˆ๋‹ค.

์ด๋ฒˆ ๊ฐ•์˜๋ฅผ ํ†ตํ•ด ๋‚ด๊ฐ€ ์ปค์Šคํ…€์œผ๋กœ init()์„ ์„ ์–ธํ•ด๋„ ๋ฐ˜๋“œ์‹œ ๋ถ€๋ชจ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š”๋ฐ ์ด๋•Œ super.init(frame: .zero) ๊ฐ’์„ ์ค€ ํ›„์— ๋‹ค์‹œ size๋ฅผ ์ •์˜ํ•˜๋ฉด ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์ƒˆ๋กญ๊ฒŒ ์•Œ์•˜๋‹ค +_+

์ƒˆ๋กœ ์ ์šฉํ•œ ๊ฐœ๋…

์•„์ง ์ปด๋ฐ”์ธ์„ ๋ฐฐ์šฐ์ง€ ์•Š์•„์„œ ํด๋กœ์ €๋กœ textField๋ฐ”์ธ๋”ฉ์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒˆ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. ์›๋ž˜๋Š” TextField์˜ ๋ฐ”์ธ๋”ฉ๋งŒ ์ ์šฉํ•˜๋ฉด ๋ฌ๋Š”๋ฐ ๋ณต์Šต๊ฒธ VM์—์„œ ๊ฐ’ ๋ณ€๊ฒฝ์‹œ TextField์— ๋ฐ˜์˜๋˜๋„๋ก Dynamic ํƒ€์ž…์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๊ฐ•์˜ ๋ณด๊ธฐ ์ „ Login์—์„œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ isEnable๊ด€๋ จํ•ด์„œ id pw์ž…๋ ฅ๋˜์–ด์•ผ๋งŒ ํ„ฐ์น˜์ด๋ฒคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ ๋“ฑ๋กํ•˜๋Š” ํ™”๋ฉด์—์„œ๋„ ์“ฐ์ผ ๊ฒƒ ๊ฐ™์•„ ํ”„๋กœํ† ์ฝœ๋กœ ์ฒ˜๋ฆฌํ–ˆ๋‹ค. ๊ฐ•์˜์—์„œ๋„ ๋น„์Šทํ•˜๊ฒŒ ํ–ˆ๋‹ค .. ใ…Žใ„ทใ„ท ๊ทผ๋ฐ ์ข€ ๋‹ค๋ฅธ ๊ฒƒ์€ ๋‚œ ํ•จ์ˆ˜ ํ„ฐ์น˜ ์ด๋ฒคํŠธ ํ•จ์ˆ˜๊นŒ์ง€ ์„ ์–ธํ–ˆ์—ˆ๋‹ค +_+

Add MVVM Pattern

Simulator Screen Recording - iPhone 13 Pro Max - 2022-09-02 at 02 52 54

์›น๋ทฐ๋„ ํ•œ๋ฒˆ ์Šฅ ๊ตฌํ˜„ ํ–ˆ๋Š”๋ฐ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ์ ์šฉ์ด ์–ด๋ ต๋„ค,,

[Clone/Instagram] ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„ | ๋ณต์Šต & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋… #6

Login, Logout๊ธฐ๋Šฅ ๊ตฌํ˜„

๊ตฌํ˜„ ์˜์ƒ

๊ฐ•์˜์™€๋Š” ๋‹ค๋ฅด๊ฒŒ

  • ํšŒ์›๊ฐ€์ž… ์ง„ํ–‰์™„๋ฃŒ์‹œ์— ํŒŒ๋ฒ ์— ์—…๋กœ๋“œํ•˜๋Š” ๊ณผ์ •์ด ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๊ณ  ๋กœ๊ทธ์ธ ์‹œ์—๋„ ๋Œ€๊ธฐ์‹œ๊ฐ„์ด ์žˆ์–ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ธ๋””์ผ€์ดํ„ฐ๋กœ ๊ณผ์ •์„ ํ‘œ์‹œํ–ˆ๋‹ค.

  • ํšŒ์›๊ฐ€์ž…์„ ํ•ด๋„ ๋กœ๊ทธ์ธ์„ ์ง์ ‘ ํ•ด์•ผ๋งŒ ์ธ์Šคํƒ€๊ทธ๋žจ ๊ณ„์ •์ด ํ™œ์„ฑํ™” ๋˜๋„๋ก ํ–ˆ๋‹ค.

  • ๋งค์ธ ํ™ˆ ๋ทฐ(first vc == Feed Scene)์—์„œ ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ ์ตœ๊ทผ ์œ ์ € auth๊ฐ€ ์—†์„ ๊ฒฝ์šฐ์— ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ presnt ๋˜๋Š”๋ฐ ์ด ๊ณผ์ •์—์„œ ์ด๋ฏธ ๋งŒ๋“ค์–ด์ ธ ์žˆ๋Š” Feed Scene๊ฐ€ ๋ณด์ธ ํ›„์— ๋กœ๊ทธ์ธ Scene๊ฐ€ present๋ฌ๋‹ค. ์ถ”๊ฐ€์ ์ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์„œ Feed Scene๊ฐ€ ๋ณด์ด๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

์•ฝ๊ฐ„ ์˜์•„ํ–ˆ๋˜ ์ ์€ ๊ฐ•์˜ ๋ณด๊ธฐ์ „์— ๋‚œ ๋กœ๊ทธ์•„์›ƒ์‹œ์— ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ Auth.auth.signIn(withEmail:email:password:) ์„ ๋ฐ”๋กœ ๋กœ๊ทธ์ธ ์ปจํŠธ๋กค๋Ÿฌ์˜ ๋กœ๊ทธ์ธ์— ํ˜„์žฌ ๋™์ ์œผ๋กœ ๋ฐ”์ธ๋”ฉ๋œ vm์„ ์ด์šฉํ•ด์„œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ ๊ฐ•์˜์—์„œ๋Š” ๊ตณ์ด,,?
Auth.auth.signIn(withEmail:email:password:) ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ•œ๋ฒˆ ๊ฐ์‹ธ์„œ AuthService ํด๋ž˜์Šค ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„ํ•ด์คฌ๋‹ค.

์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ๊ฐœ๋…

์ดˆ๊ธฐ์— ์‚ฌ์šฉ์ž ํšŒ์›๊ฐ€์ž…์„ ํ•  ๋•Œ Auth.auth()์˜ createUserํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด firebase์˜ Authentication ์— email, password๋ฅผ ๋“ฑ๋กํ•˜๊ณ  UID๋ฅผ ๋ถ€์—ฌ๋ฐ›์•˜๋‹ค. ์ด ๋•์— ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—๋Š” ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฒˆ ๊ทธ์—๋”ฐ๋ฅธ ์œ ์ผํ•œ ์‹๋ณ„์ž UID๋ฅผ Authentication์— ์ €์žฅํ•œ๋‹ค. UID๋ฅผ ํ†ตํ•ด Firestore DB ์ปฌ๋ž™์…˜์˜ ๋ฌธ์„œ๋ฅผ ์‹๋ณ„์ด ๊ฐ€๋Šฅํ•˜๊ณ  ํ•„๋“œ๊ฐ’๋„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. (ํŒŒ์ด์–ด๋ฒ ์ด์Šค๋ฅผ ์จ์„œ,, ์ƒ๋‹นํžˆ ๊ฐ„ํŽธํ–ˆ๋‹ค. ๋ฐฑ์—”๋“œ์˜ ์ž…์žฅ์—์„œ ๋‚˜์ค‘์— ๋ฐฐ์›Œ๋ณด๊ณ ์‹ถ์€ ๋งˆ์Œ์ด ๋“ค์—ˆ๋‹ค.)

์ด ๋•Œ๋ฌธ์— Auth.auth() ๋ฅผ ํ†ตํ•ด์„œ signInํ• ์ˆ˜๋„, signOut์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  signIn์„ ํ•œ ๊ฒฝ์šฐ Auth์— ํŠน์ • ์‹๋ณ„์ž๊ฐ€ ๊ธฐ๋ก์ด ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์ด ์ •๋ณด๋Š” Auth.auth().currentUser๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์•ฑ์„ ์ข…๋ฃŒํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰ํ•ด๋„ Auth์— ์ €์žฅ๋œ currentUser๋Š” Auth.auth().signOut()๋ฅผ ํ•˜๊ธฐ ์ „๊นŒ์ง€ ๊ณ„์†ํ•ด์„œ ์œ ์ง€ ๋œ๋‹ค.

// ์ถ”๊ฐ€๋กœ ๊ตฌํ˜„ํ•ด์•ผํ• ๊ฒƒ

  • ๊ฐ„๋‹จํ•œ ์ปค์Šคํ…€ ์•Œ๋ฆผ์ฐฝ

[Clone/Instagram] FeedCell ์ดˆ๊ธฐ UI ๊ตฌํ˜„ | ๋ณต์Šต & ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋… #2

FeedCell ์ดˆ๊ธฐ UI๊ตฌํ˜„

cell์˜ ๋””์ž์ธ์„ ๋ณด๊ณ  ๊ฐ•์˜ ๋ณด๊ธฐ ์ „์— ํ˜ผ์ž ๊ตฌํ˜„ํ•ด๋ดค๋‹ค. ๊ฐ•์˜์—์„  ์˜คํ† ๋ ˆ์ด์•„์›ƒ์„ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•˜๊ฒŒ UIView๋ฅผ Extensionํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ AutoLayout ๋ณต์Šต๋„ ํ• ๊ฒธ ๊ทธ๋ƒฅ anchor๋กœ AutoLayout์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๊นŒ๋‹ค๋กœ์› ๋˜ ์ 

tableView์™€ ๋‹ฌ๋ฆฌ collectionView๋Š” cell์˜ width์˜ ๊ธธ์ด์— ๋”ฐ๋ผ ๋งŽ์€ cell์ด ํ•œ line์— ์˜ฌ ์ˆ˜๋„ ๋‹จ ํ•œ๊ฐœ์˜ cell์ด ํ•œ ๋ผ์ธ์„ ์ฐจ์ง€ํ•  ์ˆ˜ ์žˆ์Œ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. width๋Š” view์˜ width๋กœ ํ•˜๋ฉด ๋˜๋Š”๋ฐ height๊ฐ€ ๋ฌธ์ œ์˜€๋‹ค. collectionView(: cellForItemAt:) DataSource ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ด์ „์— collectionView(:layout:sizeForItemAt:)๊ฐ€ ์‹คํ–‰๋˜์–ด์„œ height๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์• ๋งคํ–ˆ๋‹ค. ๋‹ค์ด๋‚˜๋ฏนํ•œ cell์˜ height ์„ค์ • ๋ฐฉ๋ฒ•์„ ๊ณ ๋ฏผํ•˜๊ณ  ์žˆ๋‹ค.

๋ณต์Šตํ•œ ๊ฐœ๋…

  • UIImageView contentMode

ScaleToFill : UIImageViewํฌ๊ธฐ์™€ ๊ฐ™๊ฒŒ ์ด๋ฏธ์ง€ size ๋Š˜์–ด๋‚จ

ScaleAspectFit : ์ด๋ฏธ์ง€ ์›๋ณธ ๋น„์œจ ์œ ์ง€ํ•˜๋ฉฐ UIImageView์˜ size์— ๋งž๊ฒŒ ์ด๋ฏธ์ง€๋ฅผ ํ™•์žฅ

ScaleAspectFill : ๋น„์œจ ์œ ์ง€ํ•˜๋ฉด์„œ view์˜ size์— ๋งž๊ฒŒ ์ด๋ฏธ์ง€ ์ฑ„์šด๋‹ค.

  • ContentCompressionResistance

cell์˜ ํฌ๊ธฐ๋Š” ์ •ํ•ด์ ธ์žˆ๊ณ  vertical๋กœ 5๊ฐœ์ •๋„์˜ subView๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. imageView์˜ ํฌ๊ธฐ๊ฐ€ ์ƒ๋‹นํžˆ ํด์ˆ˜ ์žˆ๊ธฐ์— ๊ทธ ์•„๋ž˜์— ์กด์žฌํ•˜๋Š” subView๋“ค์€ ๊ฐ€๋ ค์ง€๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ contentCompressionResistance ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ค„์—ฌ ์ด๋ฏธ์ง€ ๋ทฐ ์•„๋ž˜์— ์กด์žฌํ•˜๋Š” subView๋“ค์˜ ๊ฐ์ž intrinsic size๋Š” ์ฑ™๊ธฐ๊ณ  imageView์˜ height๋ฅผ ๊ฐ์†Œํ•˜๋„๋ก ํ–ˆ๋‹น..

์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฐœ๋…

  • ClipsToBounds

View์˜ bounds์— ์˜ํ•ด subview๋“ค์ด clip(์ž˜๋ฆฌ๋‹ค)๋  ์ˆ˜ ์žˆ๋Š”์ง€ ์˜๋ฏธ

  • UIView์˜ frame๊ณผ bounds ์ฐจ์ด

frame.origin์€ superView์— ์˜ํ•ด ๊ฒฐ์ •๋˜๊ณ  bounds.origin์€ ์ˆœ์ˆ˜ View์ž์ฒด์— ๊ธฐ์ค€์„ ๊ฐ–๋Š”๋‹ค.

frame.size๋Š” View๊ฐ€ ์ฐจ์ง€ํ•˜๋Š” ์˜์—ญ์„ ์‚ฌ๊ฐํ˜•์œผ๋กœ ๊ฐ์‹ผ ๊ฐ’์ด ๋“ค์–ด๊ฐ„๋‹ค. ( ์œ ๋™์ ์œผ๋กœ ๋ฐ”๋€๋‹ค.)

bounds.size๋Š” View์ž์ฒด ์ˆœ์ˆ˜ size๋‹ค.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.