๐Ÿ‘จโ€๐ŸŽ“
Today I Learned
  • Today-I-Learend
  • ๐ŸŽWWDC
    • Developer Tools
      • Testing in Xcode
    • UIKit
      • UIDiffableDataSource
        • [WWDC 19] Advances in UI Data Sources
      • [WWDC2019] Advances in CollectionView Layout
  • ์ž๋ฃŒ๊ตฌ์กฐ
    • Heap ์ž๋ฃŒ๊ตฌ์กฐ
  • Clean code
    • ๋„ค์ด๋ฐ
    • ์ฃผ์„๊ณผ ํฌ๋งทํŒ…
    • ํ•จ์ˆ˜
    • ํด๋ž˜์Šค
    • ์—๋Ÿฌ ํ•ธ๋“ค๋ง
    • ๊ฐ€๋…์„ฑ ๋†’์ด๊ธฐ
    • ๊ฐ์ฒด์ง€ํ–ฅ
  • Network
    • RestAPI
  • Swift
    • DateType
    • ARC
    • Availablity
    • KeyPath
    • Network
    • Neverํƒ€์ž…
    • Result
    • Selector
    • ๊ฒ€์ฆํ•จ์ˆ˜
    • ๋ฉ”ํƒ€ํƒ€์ž…
    • ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ
    • ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ „
    • ์—๋Ÿฌ์ฒ˜๋ฆฌ
    • ์ ‘๊ทผ์ œ์–ด (Access Control)
    • ์ œ๋„ค๋ฆญ
    • ์ฃผ์š” ํ”„๋กœํ† ์ฝœ
  • ์•Œ๊ณ ๋ฆฌ์ฆ˜
    • ๊ทธ๋ž˜ํ”„
    • ๊ธฐ์ดˆ ์•Œ๊ณ ๋ฆฌ์ฆ˜
    • ๋ˆ„์ ํ•ฉ(Prefix)
    • ๋ณต์žก๋„
    • ๋น„ํŠธ๋งˆ์Šคํ‚น
  • ์šด์˜์ฒด์ œ
    • ์šด์˜์ฒด์ œ์˜ ๊ฐœ์š”
    • ํ”„๋กœ์„ธ์Šค์™€ ์Šค๋ ˆ๋“œ
    • CPU ์Šค์ผ€์ค„๋ง
    • ํ”„๋กœ์„ธ์Šค ๋™๊ธฐํ™”
    • ๊ต์ฐฉ์ƒํƒœ
    • 07. ๋ฉ”๋ชจ๋ฆฌ
    • 08.๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ
    • ์ž…์ถœ๋ ฅ ์žฅ์น˜
    • ํŒŒ์ผ ์‹œ์Šคํ…œ
  • UIKit
    • UITableView xib์œผ๋กœ ๋งŒ๋“ค์–ด๋ณด๊ธฐ
  • ๐Ÿ–Š๏ธ์ •๋ณด ๊ธฐ๋ก
    • ์ฝ”์ฝ”์•„ํŒŸ ๋ฐฐํฌํ•˜๋Š” ๋ฐฉ๋ฒ•
  • iOS Project
    • ์ฑ„ํŒ… ์•ฑ ๋งŒ๋“ค๊ธฐ
      • Trouble shooting
      • 1. ๋””์ž์ธ
      • 2. AutoLayout
    • ๋‚ ์”จ ์กฐํšŒ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜
      • Figma๋ฅผ ์ด์šฉํ•œ UI ์„ค๊ณ„
      • TableView ์—ฐ๊ฒฐํ•˜๊ธฐ
      • Networking
    • MVC -> MVVM์œผ๋กœ ๊ตฌ์กฐ ๋ณ€๊ฒฝํ•ด๋ณด๊ธฐ
      • MVC
      • MVVM
    • OAuth Project
      • ๋กœ์ปฌ ํ˜ธ์ŠคํŠธ๋ฅผ ์ด์šฉํ•œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์ œ์ž‘
      • Github์˜ OAuth App ์„ค์ •
    • Rest API ํ”„๋กœ์ ํŠธ
      • UI์„ค๊ณ„ (with Figma)
      • Network Model
      • MVVM ๊ตฌ์กฐ ์ „ํ™˜
  • ๐Ÿ•ถ๏ธUIKit
    • Compositional Layout
Powered by GitBook
On this page
  • AutoLayout
  • storyboard ID๋ฅผ ์„ค์ •ํ•ด๋„ id๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•จ.
  • Firestore
  • FIRInvalidArgumentException', reason: 'Unsupported type: __SwiftValue
  • Chat์˜ ๋ณ€ํ™”๋งŒ ๊ฐ์ง€ํ•  ์ˆœ ์—†์„๊นŒ?
  • ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
  1. iOS Project
  2. ์ฑ„ํŒ… ์•ฑ ๋งŒ๋“ค๊ธฐ

Trouble shooting

Previous์ฑ„ํŒ… ์•ฑ ๋งŒ๋“ค๊ธฐNext1. ๋””์ž์ธ

Last updated 1 year ago

AutoLayout

storyboard ID๋ฅผ ์„ค์ •ํ•ด๋„ id๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•จ.

Storyboard doesn't contain a view controller with identifier "ChattingViewController"

์ƒํ™ฉ ์„ค๋ช…

  1. Main View Controller์—์„œ Sign In ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด, ChattingViewController๊ฐ€ ๋‚˜์™€์•ผํ•จ.

  2. ChattingViewController ์„ค์ •

  3. ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ

    @IBAction func didTappedSignInButton(_ sender: UIButton) {
        
        guard let email = emailTextField.text,
              let password = passwordTextField.text else { return }
        
        Auth.auth().signIn(withEmail: email, password: password) { [weak self] result, error in
            guard let strongSelf = self else { return }
            
            if let error { return }
            guard let viewController = self?.storyboard?.instantiateViewController(withIdentifier: "ChattingViewController") as? ChattingViewController else { return }
            self?.present(viewController, animated: true, completion: nil)
        }
    }

์›์ธ๊ณผ ํ•ด๊ฒฐ๊ณผ์ •

Main.storyboard์—์„œ storyboard๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ , storyboard reference๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ํ•ด๋‹น reference๋ฅผ ์„ ์–ธํ•ด์ฃผ์ง€ ์•Š์•„์„œ self.storyboard์—์„œ ํ•ด๋‹น ID๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋˜ ๊ฒƒ์ด์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ storyboard reference๋ฅผ ๋‹ค์‹œ ์„ ์–ธํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค. (push๋กœ ๋ณด์—ฌ์คฌ๋˜ ์—ฐ๊ฒฐ์„ ๋Š๊ณ  ์‚ญ์ œํ–ˆ์—ˆ๋‹ค)

์ถ”๊ฐ€. ์ƒˆ๋กœ์šด ๋„ค๋น„๊ฒŒ์ด์…˜์œผ๋กœ ์ด๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•

    // MARK: function
    private func moveUserListViewController() {
        let storyboard = UIStoryboard(name: "UserList", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "UserList") as! UserListViewController
        let navigationController = UINavigationController(rootViewController: viewController)
        navigationController.modalPresentationStyle = .fullScreen
        
        self.present(navigationController, animated: true, completion: nil)
    }
    
    // MARK: IBAction
    @IBAction func didTappedSignInButton(_ sender: UIButton) {
        
        guard let email = emailTextField.text,
              let password = passwordTextField.text else { return }
        
        Auth.auth().signIn(withEmail: email, password: password) { [weak self] result, error in
            guard let strongSelf = self else { return }
            
            if let error {
                let alert = UIAlertController(title: "์˜ค๋ฅ˜", message: "์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.", preferredStyle: .alert)
                return
            }
            self?.moveUserListViewController()
        }
    }

Firestore

FIRInvalidArgumentException', reason: 'Unsupported type: __SwiftValue

  • ์ฑ„ํŒ… ๋ฐฉ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด, ์ฐธ์—ฌ์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ˜„์žฌ ์ฑ„ํŒ… ๋ฐฉ์ด ์กด์žฌํ•˜๋Š”์ง€, ์กด์žฌํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

  • ๊ทธ๋ž˜์„œ users์— [currentUser, tableView์—์„œ ์„ ํƒํ•œ user]๋ฅผ ๊ธฐ์ค€์œผ๋กœ chatroom์— ์กด์žฌํ•˜๋Š” ๋ฐฉ์ด ์žˆ๋Š”์ง€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

  • ๊ทธ๋Ÿฐ๋ฐ FIRInvalidArgumentException', reason: 'Unsupported type: __SwiftValue ์ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค;;

  • ๊ฒฐ๋ก : ๋น„์–ด์žˆ๋Š” collection์— ์ ‘๊ทผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    • chatrooms collection๊ณผ documents๊ฐ€ ๋ชจ๋‘ ๋น„์–ด์žˆ์—ˆ๋‹ค.

    • ๊ทธ๋ž˜์„œ ๋‚ด๊ฐ€ ์„ ์–ธํ•œ codable๋Œ€๋กœ ๋น„์–ด์žˆ๋Š” ๋ฐ์ดํ„ฐ ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋‹ˆ ์กฐํšŒ๊ฐ€ ์ž˜ ๋œ๋‹ค..... ๋‚ด ์‚ฝ์งˆ...

Chat์˜ ๋ณ€ํ™”๋งŒ ๊ฐ์ง€ํ•  ์ˆœ ์—†์„๊นŒ?

์šฐ์„  ์œ„ ์‚ฌ์ง„์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ ๋‚˜๋Š” Chat Rooms๋ฅผ Collection์œผ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. ์ฆ‰, ์ฑ„ํŒ…์ด ๋ณ€ํ•˜๋ฉด, ChatRoom์ด ๋ณ€ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๊ณ , ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค€ ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋Ÿด ๋•Œ ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋А๋ƒ! ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ tableview๋ฅผ reloadํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, ์ „์ฒด ์ฑ„ํŒ…์ด ์ƒˆ๋กœ๊ณ ์นจ๋˜๊ฒŒ ๋œ๋‹ค. (๋ฐฑ๋ฌธ๋ถˆ์—ฌ์ผ๊ฒฌ ์˜์ƒ์„ ๋ณด์ž)

๋ฌธ์ œ๊ฐ€ ๋œ ์˜์ƒ

๋ฌธ์ œ๊ฐ€ ๋œ ์ฝ”๋“œ

    func setUpDataListener(id: String, completion: @escaping ([Chat]) -> Void) {
        let reference = database.collection("chatRooms").document(id)
        
        reference.addSnapshotListener {document, error in
            guard let document, document.exists,
                  let chatData = document.data()?["chat"] as? [[String: Any]] else {
                print("invalid format")
                return
            }
            
            do {
                let data = try JSONSerialization.data(withJSONObject: chatData, options: [])
                let chats = try JSONDecoder().decode([Chat].self, from: data)
                completion(chats)
            } catch { }
        }
    }

reference์ธ ChatRooms์— snapshot Listner๋ฅผ ๋‹ฌ์•˜๋‹ค. ๊ทธ๋ž˜์„œ Chat์ด ์ถ”๊ฐ€๋˜๋ฉด, ChatRoom์˜ ๋ณ€ํ™”๊ฐ€ ๊ฐ์ง€๋˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ chatData์— ["chat"]์œผ๋กœ ์˜ค๋Š” ๊ฐ’๋“ค์ด ์ถ”๊ฐ€๋˜๊ฒŒ ๋œ๋‹ค ใ…  ใ… 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

์ฟผ๋ฆฌ์— listener๋ฅผ ๋‹ฌ์•„๋ณด์ž -> ์‹คํŒจ.. (์กฐ๊ธˆ ๋” ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค)

listener๋Š” ๊ทธ๋Œ€๋กœ ๋‘๋˜, View Controller์—์„œ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค.

  1. ๊ธฐ์กด ์ฝ”๋“œ

    private func setupChatDataListener() {
        
        guard let chattingRoomID = chattingRoom?.uuid else { return }
        ChatManager.shared.setUpDataListener(id: chattingRoomID) { [weak self] chats in
            for chat in chats {
                self?.chatDatas.append(chat)
                let index = IndexPath(row: (self?.chatDatas.count ?? 0) - 1, section: 0)
                self?.chattingTableView.insertRows(at: [index], with: .bottom)
                self?.chattingTableView.scrollToRow(at: index, at: .bottom, animated: true)
            }
        }
    }

๊ธฐ์กด ์ฝ”๋“œ์—์„œ๋Š” ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ๊ธฐ์กด Chat data๋ฅผ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ์—ˆ๋‹ค. ์˜ˆ์ „์—” ๋ชฐ๋ž์ง€๋งŒ ์ด ์ฝ”๋“œ ์“ฐ๋ฉด, A, B, C๊ฐ€ ์žˆ์„ ๋•Œ ์ƒˆ๋กœ์šด D๊ฐ€ ๋“ค์–ด์˜จ๋‹ค๋ฉด A, B, C, A, B, C, D ์ด๋Ÿฐ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฑ„ํŒ…๋ฐฉ์— ๋‚จ์•„์žˆ์—ˆ์„ ๊ฒƒ์ด๋‹ค.

  1. ์ƒˆ๋กœ์šด ์ฝ”๋“œ

    private func setupChatDataListener() {

        guard let chattingRoomID = chattingRoom?.uuid else { return }
        ChatManager.shared.setUpDataListener(id: chattingRoomID) { [weak self] chats in
            var newChat = [Chat]()
            for chat in chats {
                newChat.append(chat)
            }
            
            newChat = (self?.filterNewChatting(newData: newChat, oldData: self?.chatDatas))!
            
            self?.chatDatas.append(contentsOf: newChat)
            self?.chattingTableView.reloadData()
            
            let index = IndexPath(row: (self?.chatDatas.count ?? 1) - 1, section: 0)
            self?.chattingTableView.scrollToRow(at: index, at: .bottom, animated: true)
            
        }
    }
    
    private func filterNewChatting(newData: [Chat], oldData: [Chat]?) -> [Chat] {
        guard let oldData = oldData else { return [] }
        var newChat = [Chat]()
        
        for chat in newData {
            if !oldData.contains(chat) {
                newChat.append(chat)
            }
        }
        return newChat
    }

๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ Chat Rooms์— ์žˆ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜์ง€๋งŒ, filterNewChatting์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ธฐ์กด ์ฑ„ํŒ…์— ์—†๋Š” ์ฑ„ํŒ…๋งŒ ๊ฐ€์ ธ์˜ค๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” Chat ๋ชจ๋ธ์— Hashable ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. (contains๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ)

5MB
Simulator Screen Recording - iPhone 14 Plus - 2023-06-08 at 20.48.48.mp4
1MB
Simulator Screen Recording - iPhone 14 Plus - 2023-06-09 at 17.31.27.mp4