ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS] 4주차 세미나 정리
    iOS 2022. 10. 28. 15:35
    • 미션 검사 및 피드백

    Q. present 방식에서 라이프 사이클이 호출이 안되는 문제 (viewWillDisappear이 호출안됨)

    A. .modalPresentationStyle = .fullscreen으로 변경해주면 호출되는걸 확인할 수 있음! or protocol delegate를 사용해도 가능 (오늘 배울 내용)

    • TableView 이론

    - 아래 화면을 개발한다고 가정해보자!

    구현 방법

    1) UI View를 여러개 깔아서 구현

    but, 요구사항이 바뀌어서 6개가 아니라 200개를 만들어야 한다면?

    UI View 200개, Image View 200개, Label은 하나당 3개이므로 600개가 들어간다. 이런식으로 UI요소들이 몇백개, 몇천개가 들어가게 되면, 메모리 부족문제, 퍼포먼스 문제(렉이 많이걸림) 등의 다양한 문제들이 생긴다!

     

    2) 이런 동일한 유아이가 반복될때 사용되는게 바로 Table View다!

    - 목록형태의 뷰를 구현하는데 용이

    - 재사용 큐를 활용해서 메모리 관리

    - 스크롤뷰를 상속받아 스크롤도 가능

     

    ex) 카카오톡 채팅방 같은 경우도 테이블뷰 활용되며 이 외에도 아래 그림처럼 여러곳에 사용되고있다.

     

    • Collection View 이론

    Table View와 흡사하고 구현방식에만 차이가 있으며, 동작원리는 비슷하다. (Table View와 Collection View중에서 무엇을 사용해야하는지만 알면 된다!)

    Collection View는 주로 목록이 일자가 아니라 격자인 형태일떄 사용된다.

    위 사진을 봤을때, 첫번째사진처럼 쇼핑몰앱 같은경우나 두번째 사진처럼 배달의 민족 앱 같은 경우 격자형식으로 구성되어있다면 Tabe View로 구현하기에 애매하다. 이런 경우에는 Collection View를 사용하는것이 좋다. (Table View와 마찬가지로 Cell이 반복되는 형태의 구조를 띄는것을 볼수있다.

    Table View vs Collection View

    Table View는 단순한 목록 구현에 맞춘 형태이며, Collection View는 더 복잡한, 다양한 형태로 커스터 마이징이 가능하다!

    cf) 페이지네이션같은 경우 컬렉션뷰를 이용하고, 격자가 아니라 특이한 디자인이어도 커스터 마이징을 통해 컬렉션 뷰로 구상이 가능하다.

     

    테이블뷰는 Cell의 스와이프 옵션을 지원한다.

    ex) 메모장 같은 앱을 쓰더라도 가로로 스와이프하면 메모를 지우거나, 카카오톡 같은 경우 채팅방 나가지거나 읽음 처리를 하는 등 스와이프 옵션 지원

     

    컬렉션뷰는 페이징 옵션 지원

    ex) 앱같은거봤을때 최상단에 베너가 달려있는데, 이런것들도 다 컬렉션뷰로 처리가능

     

    둘다 스크롤뷰를 상속받고있다는것은 마찬가지이다.

    디자인을 보고 구현할때 더 편할것같은 뷰를 판단하는게 중요하며, 추가적으로 테이블뷰로 구현할수있는것은 컬렉션뷰로 처리가 가능하지만, 컬렉션뷰로만 처리가되는 형태가 있다 (컬렉션뷰는 테이블뷰로 대체하기 좀 어려움)

     

    • Protocol 이론

    WWDC에서 공식적으로, 스위프트는 프로토콜 지향언어라고 공개한바가 있다. 이에 IOS 개발자라면 당연하게 알고가야 하는 이론이다. 

     

    - 프로토콜에 대한 예시를 들어 설명해보면, 치킨집 사장이라고 가정하고 본사에서 치킨 매뉴얼이 내려왔다고 상황 가정하자.

    본사로부터 치킨 매뉴얼을 받았고, 위와 같이 4가지 상황이 정해져있다. (반죽을 한다, 재료를 섞는다, 튀긴다, 장식을 한다)

    == 치킨 매뉴얼이라는 프로토콜이 선언되어있고, 4가지 함수가 정의되어있다.

    cf) 해당 매뉴얼은 단순히 매뉴얼일뿐이지 조금씩 차이가있긴하다.

     

    - 이번에는 서로 다른 사장님이 다른 매뉴얼을 가지고 한다고 가정해보자

    사장님 A와 B는 네가지 매뉴얼을 지키되, 실질적인 요리방법은 다르다! (본사에서 매뉴얼은 잘 따랐으므로 문제가 되지않는다!)

     

    그렇지만, 사장님A의 조리법의 결과와 B의 결과는 다른메뉴가 나올것이다.

    == 두 사장님은 본사의 치킨 매뉴얼은 지키되, 조리방법이 달라서 다른 메뉴가 나온것.

     

    이처럼 프로토콜은 한가지 매뉴얼이다. 즉, 가이드라인

    프로토콜을 활용하게 된다면 매뉴얼에 대한 이름을 정의하고, 이름을 정의를 하고 내부를 보면 매뉴얼만 있지 실제 구현부는 없다

    프로토콜의 가장 큰 특징은 한가지 청사진이다. 실질적으로 구현은 하지않지만, 청사진은 있는 (가이드 라인은 있는) 그런 요소라고 보면된다.

    실제 구현부까지 정하진않지만, 매뉴얼은 반드시 지켜야함!

     

    그렇다면 프로토콜은 왜 배우는가?

    1) 스위프트에 여러 요소, 함수 등등이 있을텐데, 보통 프로토콜로 정의해서 구현되어있는 부분이 많기때문에

    2) 디자인 delegate or 아키텍쳐를 설계할때는 프로토콜이 중요하기때문에!

    + 코드 이해를 잘 하려면, 즉, 성장 가능한 개발자가 되려면 필요하다.

     

    • TableView, Protocol 실습

    Delegate Protocol

    - 실제로 어떻게 활용하는지 실습

    Delegate이용해서 자식뷰가 닫힐때, 부모뷰의 Label값이 바뀌도록!

    Delegate : 대리자, 위임자 (무언가를 다른사람이 대신하는)처럼 프로토콜을 선언하고 delegate를 활용해서 데이터를 전달!

    정해져있는 메소드를 대신 실행시켜줌

     

    부모 View (View Controller)

    //
    //  ViewController.swift
    //  week4
    //
    //  Created by 김민경 on 2022/10/28.
    //
    
    import UIKit
    
    // delegate : 정해져있는 메소드를 대신 실행시켜줌
    
    protocol labelChangeProtocol {
        func onChange(text: String) // text는 String 타입으로 전달
    }
    
    // 뷰컨트롤러가 protocol을 채택함으로써 (매뉴얼을 따르겠다!) 부모뷰로 값이 넘어왔을때 text가 변경되게 구현
    class ViewController: UIViewController, labelChangeProtocol {
        // 부모뷰에서 정의했지만, 자식뷰에서 사용 (대신 처리)
        func onChange(text: String) { // 프로토콜 채택시, 반드시 구현해야 하는 최소 요구 사항, 부모뷰에는 정의만해두고 사용하지는 않음. (자식뷰에서 사용해야한다.)
            label.text=text // 최소 요구사항 구현
        }
        
        @IBOutlet weak var label: UILabel!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }
    
        @IBAction func buttonDidTap(_ sender: Any) {
            guard let SecondViewController = UIStoryboard(name: "Main", bundle:nil).instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else {return}
            
            SecondViewController.modalPresentationStyle = .fullScreen
            SecondViewController.delegate=self // 자식뷰에 delegate 변수는 부모뷰(자기자신)다 - 반드시 선언해줘야함
            present(SecondViewController, animated: true)
        }
        
    }

     

    자식 View (SecondViewController)

    //
    //  SecondViewController.swift
    //  week4
    //
    //  Created by 김민경 on 2022/10/28.
    //
    
    import UIKit
    
    class SecondViewController: UIViewController {
        
        @IBOutlet weak var textField: UITextField!
        // var delegate: labelChangeProtocol? == 부모뷰가 되는것!
        var delegate: labelChangeProtocol? // type만 옵셔널로 선언 (정의는 하지않았음.)
        // 데이터타입은 언제나 정의되어있어야함! (var number:Int = 10 이런식으로!) - 반드시 초기화 시켜야함 (부모뷰에서 초기화 시킴, 값이 넘어가기전에 SecondViewController.delegate=self 이런식으로!)
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }
        
        @IBAction func backButtonDidTap(_ sender: Any) {
            guard let text=textField.text else {return}
            
            delegate?.onChange(text: text) // protocol에 접근해서 함수 실행 (부모뷰의 함수가 실행된다고 생각하면됨! - 간단하게)
            dismiss(animated: true) // 화면 끄기
        }
    
    }

     

    화면 전환 간단한 View 구상

     

    화면 시연

     

    TableView

    - 카카오톡 채팅방 구현

    1) 기초 모양 잡기

    - 테이블뷰를 이용하여 셀 모양을 하나 잡은 후에 이미지 컴포넌트와 라벨 컴포넌트를 추가해 기본적인 틀을 잡는다.

     

    2) 테이블 뷰 셀 파일을 추가한다.

    + viewController 연동하는것처럼 Cell도 연동해주면된다! 

    Cell 연결해줄때, identifier도 지정해주어야 에러안난다,,,,같이 지정해주어야한다! (몰랐다,,,,이걸 몰라서 20분을 수업듣다가 중단했다,,,)

    TableViewCell에서는 각 컴포넌트와 연결해주고, 프로필 이미지와 메시지 배경은 원으로 변경해준다 (.cornerRadius 이용)

    //
    //  KakaoTalkTableTableViewCell.swift
    //  week4
    //
    //  Created by 김민경 on 2022/10/29.
    //
    
    import UIKit
    
    class KakaoTalkTableTableViewCell: UITableViewCell {
    
        @IBOutlet weak var profileImageView: UIImageView!
        @IBOutlet weak var lastMessageLabel: UILabel!
        @IBOutlet weak var memberCountLabel: UILabel!
        @IBOutlet weak var nameLabel: UILabel!
        @IBOutlet weak var messageCountLabel: UILabel!
        @IBOutlet weak var timeLabel: UILabel!
        @IBOutlet weak var messageCountBackgroundView: UIView!
        
        // ViewDidLoad() method와 동일하다고 보면됨.
        override func awakeFromNib() {
            super.awakeFromNib()
            profileImageView.layer.cornerRadius=22
            messageCountBackgroundView.layer.cornerRadius=10
            // Initialization code
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
            // Configure the view for the selected state
        }
        
        
    
    }

     

     

    ViewController에서는 미리 구조체 변수를 지정해준후에,  

    struct ChattingRoomDataModel {
        let profileImage: UIImage? // 에러방지 : 옵셔널 처리
        let name: String
        let lastMessage: String
        let memberCount: String? // 있을수도있고, 없을수도 있으므로 옵셔널 타입으로 선언 (단톡방일때는 있고, 개인방일때는 없으므로)
        let time: String
        let messageCount: String
    }

    해당 모델에 값을 넣어준다. 

    let chattingRoomData: [ChattingRoomDataModel] = [
            ChattingRoomDataModel(
                profileImage: UIImage(named: "swiftIcon"),
                name: "iOS 단톡방",
                lastMessage: "사진을 보냈습니다.",
                memberCount: "200",
                time: "오전 1:05",
                messageCount: "61"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "umcIcon"),
                name: "UMC 3기 단톡방",
                lastMessage: "다들 미션 다 끝내셨나요?",
                memberCount: "15",
                time: "오전 12:31",
                messageCount: "31"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "euniceIcon"),
                name: "유니스",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "오전 12:02",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명1",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "13"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명2",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "15"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명3",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "14"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명4",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "13"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명5",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명6",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "10"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명7",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "15"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명8",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "13"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명9",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명10",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명11",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명12",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명13",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "112"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명14",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            )
        ]

     

    이미지 파일은 Asset에 미리 저장해두었다! (에셋 추가하는 방법 참고)

    https://jeong9216.tistory.com/143

     

    [iOS/Swift] 에셋(Asset) 추가하는 방법 / 이미지 넣기

    [iOS/Swift] 에셋(Asset) 추가하는 방법 / 이미지 넣기 안녕하세요. 개발하는 정주입니다. 오늘은 에셋(Asset)에 대해 포스팅하려고 합니다. 그럴듯한 앱을 만들기 위해서는 이미지 소스나 효과음 같은

    jeong9216.tistory.com

     

    프로토콜을 채택했으니, 해당 함수를 정의해주는 작업을 해야한다.

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return chattingRoomData.count // 한 섹션안에 들어갈 행의 개수 (구현해야하는 디자인의 셀의 개수) == 채팅방의 개수
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "KakaoTalkTableTableViewCell", for: indexPath) as? KakaoTalkTableTableViewCell else {return UITableViewCell() }
            
            // 몇번째 셀에 어떤것이 들어가는지 모르기때문에 indexPath활용
            cell.profileImageView.image = chattingRoomData[indexPath.row].profileImage
            cell.nameLabel.text=chattingRoomData[indexPath.row].name
            cell.lastMessageLabel.text=chattingRoomData[indexPath.row].lastMessage
            
            // memberCountLabel은 개인톡일때 없으므로 nil값이 넘어오기 때문에 옵셔널 바인딩으로 처리
            if let memberCount = chattingRoomData[indexPath.row].memberCount{
                cell.memberCountLabel.text=memberCount
            } else {
                cell.memberCountLabel.isHidden=true
            }
            
            cell.timeLabel.text=chattingRoomData[indexPath.row].time
            cell.messageCountLabel.text=chattingRoomData[indexPath.row].messageCount
            
            return cell // 테이블뷰에 넣을 셀
        }

     

    하나의 테이블뷰안에 들어가야할 행의 개수를 지정해주고, 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return chattingRoomData.count // 한 섹션안에 들어갈 행의 개수 (구현해야하는 디자인의 셀의 개수) == 채팅방의 개수
        }

     

    indexPath를 활용해서 컴포넌트별로 Cell에 들어갈 값들을 지정해준다. (라벨은 스트링타입의 텍스트, 이미지는 미리 지정해둔 이미지)

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "KakaoTalkTableTableViewCell", for: indexPath) as? KakaoTalkTableTableViewCell else {return UITableViewCell() }
            
            // 몇번째 셀에 어떤것이 들어가는지 모르기때문에 indexPath활용
            cell.profileImageView.image = chattingRoomData[indexPath.row].profileImage
            cell.nameLabel.text=chattingRoomData[indexPath.row].name
            cell.lastMessageLabel.text=chattingRoomData[indexPath.row].lastMessage
            
            // memberCountLabel은 개인톡일때 없으므로 nil값이 넘어오기 때문에 옵셔널 바인딩으로 처리
            if let memberCount = chattingRoomData[indexPath.row].memberCount{
                cell.memberCountLabel.text=memberCount
            } else {
                cell.memberCountLabel.isHidden=true
            }
            
            cell.timeLabel.text=chattingRoomData[indexPath.row].time
            cell.messageCountLabel.text=chattingRoomData[indexPath.row].messageCount
            
            return cell // 테이블뷰에 넣을 셀
        }

     

    가장 중요한것은 마지막으로 대리자 위임을 해주는것이다! (대리자 위임을 해주지않으면 화면에 해당 셀들이 뜨지않는다!)

    override func viewDidLoad() {
            super.viewDidLoad()
            // 대리자 위임 (필수로 해줘야함, 안해주면 화면에 뜨지않음)
            KakaoTalkTableView.delegate=self
            KakaoTalkTableView.dataSource=self
            
            // Do any additional setup after loading the view.
        }

     

    ViewController 전체코드

    //
    //  KakaoTalkViewController.swift
    //  week4
    //
    //  Created by 김민경 on 2022/10/28.
    //
    
    import UIKit
    
    class KakaoTalkViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { // 공식문서를 통해 각 프로토콜 조사해보기
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return chattingRoomData.count // 한 섹션안에 들어갈 행의 개수 (구현해야하는 디자인의 셀의 개수) == 채팅방의 개수
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "KakaoTalkTableTableViewCell", for: indexPath) as? KakaoTalkTableTableViewCell else {return UITableViewCell() }
            
            // 몇번째 셀에 어떤것이 들어가는지 모르기때문에 indexPath활용
            cell.profileImageView.image = chattingRoomData[indexPath.row].profileImage
            cell.nameLabel.text=chattingRoomData[indexPath.row].name
            cell.lastMessageLabel.text=chattingRoomData[indexPath.row].lastMessage
            
            // memberCountLabel은 개인톡일때 없으므로 nil값이 넘어오기 때문에 옵셔널 바인딩으로 처리
            if let memberCount = chattingRoomData[indexPath.row].memberCount{
                cell.memberCountLabel.text=memberCount
            } else {
                cell.memberCountLabel.isHidden=true
            }
            
            cell.timeLabel.text=chattingRoomData[indexPath.row].time
            cell.messageCountLabel.text=chattingRoomData[indexPath.row].messageCount
            
            return cell // 테이블뷰에 넣을 셀
        }
        
        
        @IBOutlet weak var KakaoTalkTableView: UITableView!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // 대리자 위임 (필수로 해줘야함, 안해주면 화면에 뜨지않음)
            KakaoTalkTableView.delegate=self
            KakaoTalkTableView.dataSource=self
            
            // Do any additional setup after loading the view.
        }
        
        let chattingRoomData: [ChattingRoomDataModel] = [
            ChattingRoomDataModel(
                profileImage: UIImage(named: "swiftIcon"),
                name: "iOS 단톡방",
                lastMessage: "사진을 보냈습니다.",
                memberCount: "200",
                time: "오전 1:05",
                messageCount: "61"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "umcIcon"),
                name: "UMC 3기 단톡방",
                lastMessage: "다들 미션 다 끝내셨나요?",
                memberCount: "15",
                time: "오전 12:31",
                messageCount: "31"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "euniceIcon"),
                name: "유니스",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "오전 12:02",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명1",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "13"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명2",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "15"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명3",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "14"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명4",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "13"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명5",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명6",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "10"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명7",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "15"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명8",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "13"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명9",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명10",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명11",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명12",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명13",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "112"
            ),
            ChattingRoomDataModel(
                profileImage: UIImage(named: "defaultProfileIcon"),
                name: "익명14",
                lastMessage: "화이팅 해봐요!!!",
                memberCount: nil,
                time: "어제",
                messageCount: "12"
            )
        ]
    
    }
    
    struct ChattingRoomDataModel {
        let profileImage: UIImage? // 에러방지 : 옵셔널 처리
        let name: String
        let lastMessage: String
        let memberCount: String? // 있을수도있고, 없을수도 있으므로 옵셔널 타입으로 선언 (단톡방일때는 있고, 개인방일때는 없으므로)
        let time: String
        let messageCount: String
    }

     

    기본 틀 화면

     

    시연영상

     

    • 미션 안내

    스탠다드 미션

    - TableView가 대표적으로 사용되는 메모장 구현

    (테이블 뷰에 들어가는 데이터모델은 임의로 정의하기)

    + TableView의 대표적 특징 (재사용 큐) 

    테이블뷰는 메모리관리를 위해 셀을 재활용을한다. 재활용을 하다보면 문제점이 발생하게 되는데, 예를 들면

    if indexPath.row == 0 { // 이렇게 쓰다보면 재활용이 되어 속성이 남아있게 된다. (0번째 셀일때만 빨간색이 되도록 처리해보기!)
                cell.backgroundColor = .red
            }

    해당 코드를 추가했을때, 시연화면을 살펴보자! 0번째 셀에만 배경색이 추가되어야하는데, 스크롤을 내리다보면 여러셀에 배경속성이 추가되는것을 볼수있다.

     

     

    이는 테이블뷰의 대표적인 속성인 재사용큐때문에 일어나는 현상인데, 이 현상을 해결하는것까지 미션!

     

    챌린지 미션

    - 테이블뷰의 두번째 특징 (스와이프 옵션제공)

    스와이프 옵션을 통해서 셀 삭제, 혹은 셀 정렬 등 커스텀 옵션을 추가해서 만들어오기! (기본적으로 삭제하는것을 해와도 OK!)

     

    • 공부해두면 좋은 내용

    'iOS' 카테고리의 다른 글

    [iOS] TableView를 이용한 메모장 만들기  (0) 2022.10.29
    [iOS] TableView 재사용큐  (0) 2022.10.29
    [iOS] 간단한 계산기 만들기  (0) 2022.10.06
    [iOS] 3주차 세미나 정리  (2) 2022.10.03
    [iOS] 전화 기본앱 만들기  (0) 2022.09.29
Designed by Tistory.