iOS/iOS 자료실

Swift 스터디. 4번째

Chipmunks 2018. 5. 19.
728x90

Swift 스터디. 4번째

테이블뷰 코드로 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import UIKit
 
internal var data: [String= ["1""2""3"]
 
// 커스텀에 코드 넣을 수 있음
internal class TableViewCell: UITableViewCell {
    private var didUpdateConstraints: Bool = false
    private var label: UILabel = {
        let label: UILabel = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "abc"
        label.textColor = .blue
        return label
    }()
    
    func setTitle(text: String) {
        label.text = text
    }
    
    override func updateConstraints() {
        if !didUpdateConstraints {
            NSLayoutConstraint.activate([
                label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
                label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15),
                label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10)
                ])
            
            didUpdateConstraints = true
        }
        
        super.updateConstraints()
    }
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        contentView.addSubview(label)
        contentView.setNeedsUpdateConstraints()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder: ) not been implemented")
    }
}
 
class ViewController: UIViewController {
 
    @IBAction func addAction(_ sender: Any) {
        data.append("\(data.count + 1)")
        tableView.reloadData()
        
        // 스크롤 마지막으로
        let indexPath = IndexPath(row: data.count - 1, section: 0)
        tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
    }
    
    var didUpdateConstraints: Bool = false
    
    lazy var tableView: UITableView = {
        let tableView: UITableView = UITableView.init(frame: .zero, style: .grouped)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
        tableView.delegate = self
        tableView.dataSource = self
        // tableView.isEditing = true // Delete 버튼 나타남
        return tableView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        view.addSubview(tableView)          // 뷰에 넣기
        view.updateConstraintsIfNeeded()    // 넣은 테이블뷰 업데이트
    }
 
    override func updateViewConstraints() {
        if !didUpdateConstraints {
            NSLayoutConstraint.activate([
                tableView.topAnchor.constraint(equalTo: view.topAnchor),
                tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
                ])
        
            didUpdateConstraints = true
        }
        
        // 마지막에 넣기
        super.updateViewConstraints()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
 
extension ViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int-> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // as? 하지 않으면 UITableViewCell 로 받아옴. ㅠㅠ
        // guard let 으로 처리
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell"for: indexPath) as? TableViewCell else {return UITableViewCell() }
        cell.setTitle(text: "\(data[indexPath.row])")
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath)
        tableView.deselectRow(at: indexPath, animated: true)
        
        cell?.accessoryType = .checkmark
    }
}
cs


새로 배운 점

1. internal

정의 된 모듈 어디에서든 사용할 수 있다. 그러나 그 모듈이 아닌 파일에서는 사용할 수 없다.

2. 클로저로 객체들을 생성하는 법

UITableView와 UILabel을 생성할 때, 클로저 안에서 여러 속성들을 적용한 객체를 저장하고 있다.

UITableView 를 생성할 때, lazy 키워드를 붙이지 않으면 self 키워드를 ViewController 로 인식을 하지 못한다.

3. 코드로 Constraint 제약 주는 법

updateViewConstraints() 메소드를 오버라이딩한다. 그 안에서

NSLayoutConstraint.activate([...]) 으로 Constraint 속성을 설정한다. 한 번만 실행하기 위해 플래그 변수도 설정한다.

4. 새 프로토콜의 구현할 메소드들을 Extension 으로 코드 분리하기

UIViewController 를 구현한 ViewController 에서 프로토콜을 추가해 구현할 수 있다.

extension 을 이용해 ViewController 에 프로토콜을 추가해 코드를 분리시켰다.

5. TableCell의 accessoryType

.checkmark 로 설정하면, 흔히 기본 iOS 앱에서 볼 수 있는 삭제 UI를 볼 수 있다.

6. 코드로 View 넣기

addSubview() 메소드와 updateConstraintsIfNeeded() 메소드를 사용한다.
addSubview() 메소드는 상위 뷰 아래에 새 뷰를 넣어준다.
updateConstraintsIfNeeded() 메소드는 뷰들의 Constraints 속성을 조정해준다.

7. 테이블뷰

테이블뷰는 셀들을 identifier 로 구분해 재사용 할 수 있다. 새 셀 양식을 테이블뷰에 저장할 때는 register() 메소드로 저장한다.


꺼낼 때는 dequeueReusableCell() 메소드로 identifier 에 맞는 셀을 가져온다. 이 때 형식 변환을 하지 않으면 dequeueReusableCell() 반환 형식인 UITableViewCell 으로 들어온다.

as? TableViewCell 으로 변환한다. 변환에 실패할 때를 처리해주기 위해, guard let 구문을 사용한다.


댓글