[TIL] TodoList 과제 Lv.1 ~ 2

한철희·2024년 3월 21일
0

TIL

목록 보기
18/57

오늘은 앱 입문 주차주 개인과제로 나온 TodoList앱 구현한것을 Lv.2까지 정리해서 포스팅하려고 한다.
우선은 Lv.1부터 살펴보자


Lv.1은 기본 화면 UI를 구성하는 단계다.

예시 영상에서 나온 위 화면을 그래도 구성하면 된다.
일단 화면을 봤을 때 생각나는 요소들은
UIBUtton, UITableView, UILabel, UISwitch정도다

일단 UIBUttonUITableView부터 스토리보드 화면에서 배치해줬다.

이렇게 큰 틀은 완성했고
UILableUISwitch는 따로 UITableViewCell에서 xib파일을 통해 배치해줘야한다.
xib 파일은 테이블뷰셀 파일을 생성하면서 만들어줄 수 있다.

위 화면에서는 체크가 안되어있는데
Also create XIB file부분에 체크를 해줘야한다.

여기서 잠깐! Xib가 뭐냐구요?

  • Xib는 유저 인터페이스 필드를 저장하기위한 파일
  • xml형태로 제공된다.

쉽게 말하면 스토리보드처럼 사용자 인터페이스를 디자인 및 개발하는 것이라 보면 된다.

이어서 추가해주면
이런 모양이된다.
여기서 추가한 UI요소들은 스토리보드에서는 보이지 않는다.
그 다음에는 스토리보드에서 하듯이 .swift파일에 @IBOutlet으로 연결해준다.
이런식으로 해준다.
그래야 UI요소들에 접근하고 변경할 수 있기 때문이다.
이렇게 셀을 만들어주고 바로 사용할 수 있는 것이 아니라
ViewController에서 호출해줘야 사용할 수 있으므로
그를 위한 identifier도 같이 설정해준다.
내가 한 방식처럼 코드로 작성해줘도 되고

이렇게 커스텀 클래스를 지정해줘도 된다.

여기까지하면 기본적인 배치는 끝나고 이제 화면에 띄워주기 위해서 ViewController에서 호출 작업 및 더미 데이터를 넣어서 제대로 화면에 출력되는지 확인해보자.

코드를 한번에 제시하고 설명하도록 하겠다

viewController 부분

class ViewController: UIViewController {
    
    @IBOutlet weak var myTableView: UITableView!
    
    var sampleTodo: [Todo] = Todo.sampleTodo
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let nib = UINib(nibName: TodoTableViewCell.identifier, bundle: nil)
        myTableView.register(nib, forCellReuseIdentifier: TodoTableViewCell.identifier)
        
        myTableView.delegate = self
        myTableView.dataSource = self
    }
}

우선 UITableView를 사용하기 위해 @IBOutlet으로 연결해주고
viewDidLoad부분에 아까 제작한 Cell을 추가하기 위한 코드를 작성해준다.
그리고 밑의 delegate나 dataSource부분을 작성하면 에러가 뜰텐데 그 경우 밑의 extension에서 볼 수 있는것처럼
UITableViewDelegate, UITableViewDataSource부분을 작성해준다. 아마 이 부분은 Xcode에서도 에러메시지를 띄워주기 때문에 놓치지 않을것이다.

extension Todo {
    static var sampleTodo: [Todo] = [
        Todo(id: 1, title: "title1", isCompleted: false),
        Todo(id: 2, title: "title2", isCompleted: false)
    ]
}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView,heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 90
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.sampleTodo.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: TodoTableViewCell.identifier, for: indexPath) as? TodoTableViewCell else { return UITableViewCell() }
        
        cell.setData(self.sampleTodo[indexPath.row])
        
        return cell
    }
}

ViewController에 추가해줘도 되지만 가독성과 파악하기 편하도록 따로 빼둬서 작성했다

맨 위의 Todo부분은 셀이 올바르게 나오는지 확인하기 위한 더미데이터다.

UITableViewDelegate, UITableViewDataSource 부분의 코드는 거의 정형화된 코드들이 많이 쓰이는 것같은데 공식문서와 구글링 해서 나오는 코드들을 참조하여 작성했다.
아직 완벽하게 이해하지는 못했지만 자주 사용하면서 익숙해질것같다.

이렇게까지 Lv.1을 마무리했다


이제 Lv.2를 보자

Lv.2는 Lv.1에서 추가한 UI요소들에 본격적으로 기능을 구현하는 단계다.

일단 추가하기 버튼에 UIAlert을 띄우고 거기서 추가적인 기능을 구현하는것이다. 이 부분이 코드가 좀 길어져서 힘들었다

@IBAction func addTodo(_ sender: Any) {
        //alert 창 요소들
        let title = "할 일 추가"
        let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
        // alert창 버튼 추가 및 기능
        let cancel = UIAlertAction(title: "취소", style: .cancel)
        let add = UIAlertAction(title: "추가", style: .default) { (_) in
            // 추가하기 눌렀을 때 처리할 내용
            if let txt = alert.textFields?[0] {
                if let text = txt.text, !text.isEmpty {
                    // 새로운 Todo 객체 생성 및 배열에 추가
                    let newId = (self.sampleTodo.last?.id ?? 0) + 1
                    let newTodo = Todo(id: newId, title: text, isCompleted: false)
                    self.sampleTodo.append(newTodo)
                    
                    // 테이블 뷰 업데이트
                    self.myTableView.reloadData()
                } else {
                    print("입력된 값이 없습니다")
                }
            }
        }
        alert.addAction(cancel)
        alert.addAction(add)
        
        // alert창에 textField추가
        alert.addTextField(){ (tf) in
            tf.placeholder = "할 일을 입력하세요"
        }
        
        self.present(alert, animated: true)
    }

기본적으로 얼럿창에 들어가는 버튼이나 메시지 입력 창 등을 정의하고 추가해주는 코드다
특히 추가 기능을 구현한 add부분은 클로저를 이용해서 그에 맞는 기능들도 구현했다.
버튼이 눌렀을때 텍스트 창에 글자가 있다면 새로운 Todo객체를 생성하고 그게 아니라면 메시지를 출력해준다.



추가되는 모습을 확인할 수 있다.

추가하기 버튼을 구현한 뒤에는 완료하기 기능을 구현해야한다.
즉 오른쪽의 스위치를 전환했을때를 구현하면 된다.
나는 스위치가 전환되었을 때 왼쪽 Label에 취소선이 그어지도록 했다.

어 근데 이 기능을 구현하려고 하니 swift에는 따로 취소선을 구현하는 기능이 없다
그래서 구글링을 해보니 의외로 해결책은 간단했다.
swift 취소선 구현하기!
위의 블로그를 참고해서 했다.

extension String {
    func strikeThrough() -> NSAttributedString {
        let attributeString = NSMutableAttributedString(string: self)
        attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0, attributeString.length))
        return attributeString
    }
}

String에 extension으로 기능을 추가해서 해결했다.
이후 스위치를 @IBAction으로 연결해서 스위치가 바뀔때 작동하도록 만들었다

@IBAction func switchToggled(_ sender: Any) {
        if todoCheckSwitch.isOn == true{
            todoTitleLabel.attributedText = todoTitleLabel.text?.strikeThrough()
        }
    }

코드 자체는 간단하다.
스위치를 작동하면 저렇게 취소선이 그어지게 된다.

여기까지 Lv.2를 마무리하겠다
다음에는 Lv.3~ 이후로 포스팅해보자

profile
초보 개발자 살아남기

0개의 댓글