포스트

3주차 과제 복기 (Fin)

그전까지는 이렇게까지 복기를 하지는 않았는데, 이제는 실제로 UIKit도 다루다 보니.

이런식으로 글로 작성을 해두면 나중에 볼때도 그당시의 기분이나, 느낀점을 다시 회상할 수 있을 것같아서 글을 남긴다.

Diagram

현재 진행은 이렇게 되었다.

Lv.1

사실 1단계는 디자인적인 측면이 어서. 크게 어렵지는 않았다.

물론 처음에는 Custom Cell이 아닌, Prototype Cell을 추가하여 사용하려고 하였으나, uiswitch라던가 그런걸 라벨링을 해주고 좀 장기적인 측면에서는 custom cell을 만들어 사용하는게 더 좋을 것이라는 생각이 들어 선회하게 되었다.

아무래도 uiswitch를 코드로 addview이런식으로 하다보니, 뭔가 코드가 지저분해지지 않을까? 라는 생각을 했는데, 실질적으로 switch를 custom으로 만들었어도 tableview 함수내에서 쓰는 코드는 비슷비슷 했다.

  • before : addview로 cell 추가
  • after : Custom Cell 추가

Lv.2

가장 오랜 시간이 걸렸던 파트

1. UIAlertController

한번 정리를 쭉 하고 시작하니, 크게 구현하는데 있어 문제를 느끼지 않았다.

확실히 그냥 찾으면서 주먹구구식으로 하는것 보다는 이렇게 한번 정리를 하고 시작하면, 에러가 나도 어느 부분인지 생각을 하게되고 대처를 할 수 있게 된다.

이것에 대한 생각은 여기까지.

2. UISwitch

취소선을 구현하는데 있어 약간의 시간이 걸리긴 했다.

처음에 커스템 셀이아닌 일반 적인 StoryBoard에 추가하는 방식으로 진행을 했을때, 생각해보니 Label을 만들지 않고 진행했다는 걸 알았는데, 그건 이미 Custom Cell을 구현하고 나서였다…

구글링을 하다보면 내배켐 이전 기수에서도 똑같이 진행했던 과제같은데, 일부러 그 자료는 안봤다.

그런것에 의존을 하고싶지 않았다. 그래서 더 시간이 걸렸던것 같은데, addTarget을 구현하여, on/off에 따른 함수 호출이었으나, 문제는 이것이었다.

현재 호출한 Cell의 indexrow는 그래서 누구?

그것과 관련된 자료를 찾다가 Stackoverflow에 나와 비슷한 문제를 올렸던 사람이 있었다.

관련자료를 보고 indexpath에 관한 글을 조금 더 찾아 보았다.

과제를 진행하면서 관련된 글을 적지 않았는데, 아래에 간단하게 정리를 해보겠다.

1. IndexPath

우리가 tableview하면 아무렇지 않게 쓰는 IndexPath와 IndexPath.row

이걸 알기위해 Table의 cell이 어떻게 이뤄지는지를 봐야한다.

이렇게 table을 section으로 구분을 짓게 되고,

그안에 있는 하나의 cell을 row로 판단하게 된다.

이걸 이해하자마자 바로 UISwitch에 대한 문제가 해결되었다.

3. TableView

가장 오랜시간이 걸렸고 밤새도록 수없이 많은 검색을 해도, 자료를 찾아봐도 힘들었던 부분.

우선 TableView 구현 자체에는 큰 어려움은 없었다.

구현을하고 시도를 하는것 자체는 좋았다.

문제는 바로 셀이 reload될때, 이전 cell의 위치가 가지고 있는 정보를 가지고 있어 뒤죽 박죽으로 된다는 것이다.

가장 시간이 오래걸렸던 부분이다, 내스스로 어떻게든 해보려고 검색과 여러 시도를 다해봤지만 안되었다.

그러다 로컬의 문제인가? 싶어서 DB로 전환까지 가게한 녀석이다.

DB전환은 이후에 하려고 했는데 본의아니게 미리해버린셈이 되었다.

그래도 미리해버리니, 기능을 추가할때 마다 DB도 같이 하게되니 오히려 이게더 괜찮은데? 라는 생각도 든다.

그리고 해봤지만 역시나 안되었다. DispatchQueue를 사용해서 비동기식으로 전화하면 되지 않을까? 라는 생각으로 DB화를 시켰던건데 나의 생각은 틀렸었다.

결국 튜터님께 갔는데, 듣자마자 아차싶었다.

바로 일종의 Cache 개념인데, 그전에 셀의 캐시가 남아있어, 내가 원하는대로 보여지지 않았던 것이다.

튜터님은 prepareForReuse 메서드를 알려주셨고, 해당기능을 셀을 만든쪽에 오버라이딩 해서 써보라고 하셨다.

그리고 switch를 어떻게 사용하는지 알려주셔서 그대로 적용을 했다.

그렇게 또 잘되나 싶었다.

하지만 이젠 취소선이 문제였다.

근데 이건 똑같은 개념이라, 내가 prepareForReuse 에 대해 좀 더 알아보고 해야겠다는 생각이 들었다.

생각히보니 너무 알려주신대로 곧이곧대로 내가 사용을 하는 것 같았다.

그래서 이런저런 자료를 찾다보니, 이녀석들도 초기화를 해줘야한다는 글을 본것같다.

이번에도 역시 아차싶었다. uiswitch도 결국 false로 해준게 초기화를 그렇게 해준건데, 취소선도 초기화를 해주면 되겠다 싶어

toDoLabel.attributedText = nil을 추가 해줬다.

바로 해결이 되었다.

Lv.3

삭제를 하는 기능이었다, 구현자체는 문제가 안되었다.

하지만 이젠 DB에 대한것이 문제였다.

1. DB documents 재설정

그전에 Documents naming을 할때 즉, DB를 사용하게 되면 Document가 생기고 그곳에 내가 입력한 값이 하나씩 등록이 된다.

처음에는 위와 같은 방식으로 그대로 사용을 하다가, Uiswitch를 할때 Query를 사용해야하는데, 그부분 사용을 해보려고 했는데 Query라는 데이터 타입으로 나오는것을 처음에 어떻게 사용해야할지 몰라서, 그냥 Documents를 id값과 동일하게 하면 되겠다 라고 생각하여 그렇게 진행을 했다.

documents와 id값 그대로가니 삭제기능을 구현하기 전까지는 문제가 없었다.

삭제기능을 구현하자마자 indexpath.row와 id값이 달라지는 경우가 발생하면서, 내가 구현했던 것들이 모두 꼬이기 시작하는 사태가 발생하였다.

사실 삭제기능을 구현하면서 이미 꼬일줄은 알고 있었다. 일단은 삭제 기능을 먼저 구현하고 DB를 다시 고치자라는 생각으로 삭제기능을 우선적으로 구현하였고,

바로 DB접근을해서 id값으로 Document 네이밍을 하던것을 고대로 다시 원복했다. (위의 사진과 같은 방식)

그리고 실패했던 쿼리를 다시사용해서 어떻게든 해결해야겠다라는 생각을 갖고 다시 쿼리로 접근하였다. Sql을 이미 써봤기에, 무조건 이건 Query로 접근해서 해야한다는 생각 밖에 없었다.

Field가 id인 곳에서, 내가 선택한 그 셀의 id를 어떻게 가져와야할까?

이게 근본적인 문제였고, 곰곰히 생각을 해보았다.

그리고 바로 깨달았다.

내가 구현해둔 getData 함수에는, DB로 부터 받아온 정보를 lists라는 배열에 담아둔다.

거기엔 id,title,isComplete 이렇게 3가지의 정보를 가지고있는다.

그리고 값이 추가 삭제가 되어도, 그값이 가지고 있는 기본틀은 변하지 않는다.

즉 내가 원하는 indexPath.row의 위치에 해당하는 lists의 id값을 가져오면 되는 부분이었다.

lists[indexPath.row].id 를 하게 되면 그 행에 해당하는 DB로 부터 로컬개념에 저장된 id값을 반환할수 있던 것이었다.

이것을 깨닫자마자 모든 문제가 해결이 되었다.

그렇게 Lv.3 구현은 끝나게 되었다.

튜터님과 대화를 하다 userdefault localDB가 있다고 하신다.

주말에 해봐야겠다.

LV.4 ~ 5

Mindmap

Diagram

lv.4, 5

1. 수정기능

이부분은 크게 문제가 없었다.

2. 즐겨찾기기능

이부분 역시도 크게 문제가 없었다.

3. segControl

사용하는데 있어서는 크게 문제가 안되었다. 다만 SegControl을 사용함으로써, 여러 다중쿼리들을 만들어야했고, Firebase는 이런 다중쿼리를 실행하려면 별도로 콘솔에 링크를 알려주는데 그링크들 들어가서 쿼리를 추가해줘야 구현이 가능했다.

4. 새로운 화면 보여주기

이부분 역시 크게 어렵지는 않았다.

5. SideView 구현

이부분은 코드이해를 하기엔 시간이 없어 우선 코드를 그대로 차용 할 수 밖에 없었다. 주말에 별도로 해보면서 여러 테스트를 좀 해봐야 하지 않을까 싶다.

6. ImagePicker

처음에는 너무 기능이 과한건가 싶었지만 사용해보면서 별거 없다는 생각이 들었다. edit일때는 무조건edit이미지만 사용해야한다는걸 알게 되었다.

UIImagePicker는 곧 사라지므로 PHPicker를 앞으로 사용해 봐야겠다.

7. SideViewTableView구현

함수나 코드적인부분에서는 아무런 문제가 없는데 왜 보이지 않을까 생각을 했다.

새로운 테스용 VC를 만들어서 했을때는 아무런 문제가 없는데 왜 안되는지 내 지식으로는 해결이 되지 않았다.

그래서 결국 튜터님에게 찾아갔고, 너무나 어이없는 실수를 하고야 말았다.

바로 AutoLayout설정에 대한 문제였다.

총 4개를 코드로 구현하였는데, 3개는 bottom Constraints를 주지 않아도 보여서 tableview 아무렇지 않게 복붙을 해버리고 말았다.

tableview에 bottom부분이 없는것 같다고 튜터님이 말씀하셔서 바로 적용해보니 보였다.

그리고 AutoLayout을 함에 있어서 아직 스스로 부족함이 많다는 것 또한 알게 되는 기회였다.

이것도 주말에 좀 연습을 해보면서 스스로 다듬어야겠다는 생각이 든다.

8. DB 예외 처리

쿼리에 해당이 되지 않는 내용을 조회할때 이전에 값이 그대로 보여지는 경우가 있었다. 그래서 하나하나 역으로 print를 하면서 찾아가기 시작했다.

그리고 해당 부분을 발견하여 바로 예외 처리를 해주었다.

하지만 값이 소팅된 상태에서 값이 추가 될때 그 소팅된 그상태로 추가되는 모습을 보여주고 싶은데 그부분은 아직 능력 부족으로 구현하지 못한게 아쉽다.

제출시 작성한 내용.

1. 과제를 구현하며 어려웠던 점이나 도움이 필요한 부분이 있다면 작성해주세요.

  • 어려웠던 점
    1. Cell 갱신시 Cell이 꼬이던 문제 우선 TableView.reload 가 말그대로 모든걸 refresh하고 reload하는 개념이라고 생각을 했는데, uiswitch를 on -> off로 바꾼상태에서 셀을 추가하게되면 cell이 꼬이는걸 확인하고 어떻게 해볼까 스스로 고민을 하다가 결국 튜터님을 찾아가서 해결을 했었다. 보이는부분도 일종의 cache개념이 남는다는걸 생각하지 못했다.
  1. SideViewController 구현 WWDC의 자료도 보고 했지만, 스스로 하기엔 아직까지 부족함이 많아 결국 복사해서 붙여넣기하는 방법을 선택하고 말았다. 선호하지 않는 방법인데 워낙 구현하고 싶었던 기능이라 어쩔수없이 하고야 말았다. 주말에 해당부분은 별도로 연습을해서 내것으로 만들어야겠다는 생각이 들었다.

  2. DB에서 변경이 생겼을때 전체 DB가 다시보여지던 현상. 어떤 값을 소팅한 상태에서, DB의 내용에 변경이 생겼을경우 (CRUD) 이때 전체 값이 다보이는 문제가 발생하였다. 우선 임시조치로, 값이 변경될때 전체탭이 활성화 되게는 했지만, 이부분은 조금 더 공부를 해야하지 않을까 라는 생각이 들었다.

  3. Code로 UI를 구성했을때 Autolayout문제로 tableview가 안보이던 문제 tableview 제외하고 3개를 구현했는데, bottom부분을 주지않은상태에서 잘되어서 그대로 tableview도 해보았지만 보이지 않았다. 혼자서 별 시도를 다하다가 결국 튜터님께 찾아갔고, TableView의 Bottom부분을 주지않아서 보이지 않았던 문제라고 하셨다. 기본적인걸 망각했었다.

  4. 디자인 문제 확실히 구현하면서 나의 미적감각은 좋지 않다라는것을 다시한번 인지할수있는 계기가 되었다. 그러다보니 디자인 보다는 최대한 기능을 여러개 만들어보자는 생각으로 구현을 하려 노력했다. 디자인이 제일 어려운것같다.

2. 기술 질문 1 - 모든 View Controller 객체의 상위 클래스는 무엇이고 그 역할은 무엇인지 아는대로 작성해보세요.

상위 클래스는 UIViewController이다.

역할은 데이터 변화에 따라 view 컨텐츠 업데이트 view와의 사용자 상호작용에 응답 view를 리사이징하고 전체적인 인터페이스의 레이아웃 관리 앱 내에서 (다른 view controller를 포함한) 다른 객체와의 조정

3. 기술 질문 2 - 옵셔널과 옵셔널 해제에 대해 아는대로 작성해보세요.

옵셔널 : 값이 있을수도 없을 수도 있다는 의미.

옵셔널 해제 :

  1. 강제 옵서녈 해제
    • ! 를 붙여 옵셔널타입을 강제로 해제하는 방법으로 사용하기는 편리하나, 예외처리가 안되어있는 경우 App Crash발생으로 인한 치명적인 단점이 존재
  2. 옵셔널 바인딩
    • if let 을 사용하여 해당 값이 존재하는 경우, 없는 경우를 통해 (1)의 방법의 위험성에서 벗어나, 안전하게 진행이 가능.
  3. 옵셔널 체이닝
    • 일부 속성이나 메서드에 접근을할때 ?를 붙여 접근을 한다. 하나라도 nil이 있다면 리턴값 또한 nil이 된다.
  4. 옵셔널 병합연산자 사용
    • ?? 를 사용하여 nil인 경우 default값을 설정 해두어 nil을 방지한다.

4. 기술 질문 3 - UIKit에서 스토리보드로 UI 구현하기와 코드로 UI 구현 시의 각각의 장단점을 설명하시오

[Storyboard]

  • 장점
    1. 내가 구현하고자 하는 UI를 직관적으로 알 수 있다.
    2. Component를 간편하게 추가 할 수 있다.
  • 단점
    1. AutoLayout을 설정할때 조금이라도 벗어나면 알람이 뜬다.
    2. 일일이 Code에 링크를 해줘야한다.

[Code]

  • 장점
    1. 코드 구성에 대해 심도있는 공부가 가능.
    2. 여러 프로퍼티에 대해 바로바로 원하는대로 설정이 가능.
  • 단점
    1. 코드로 되어있다보니 이해가 필요
    2. Autolayout이 잘못될경우 아예 보이지 않는다.
    3. preview를 사용하지 않으면 어떤 화면인지 내가 실행해 보지 않는 이상 알 수 없다.

5. 이번 챕터에서 학습을 하며 알게된 기술, 지식이 있다면 어떤 것이 있는지 작성합니다. (1)

화면 전환시 상황에 맞는 데이터 전달 방식을 다시한번 리마인드하게 되었다. 그전에 해당 내용에 대해 정리를 하면서는 그냥 이런게 있고, 내가 이런걸 공부했구나 라는 정도 였다면, 이번에 내가 자기주도적으로 코드를 구성하면서 공부했던 부분을 더 확고히 다질수있었다.

예를 들면 Database로 부터 값을 전달 받을때는 Delegate를 통해서 VC에서 전달을 받게 하였고, A VC 에서 B VC로 화면전달이 될때는 프로퍼티를 통해서 데이터 전달을 하였는데, 왜 이런 상황에서 써야하는지 뭔가 판단을 나 스스로 할 수 있었다.

  • Delegate를 통한 데이터 전달 보통 Delegate로 데이터를 전달하려는 주체가 어디로 내가 값을 보낼지 모르는 상태일때 사용을 하는데, 이때 프로토콜을 데이터를 보내려는쪽에 만들고, 데이터를 받는쪽에서 해당 프로토콜을 채택하면서 delegate를 통해 데이터를 받게 된다. 받는 쪽에서는 delegate = self를 통해 vc가 위임을 받는 주체임을 명시 해줘야한다.

  • 프로퍼티를 통한 데이터 전달 위의 경우와 달리 현재 VC가 화면전환시 어느 VC로 갈지를 이미 아는 상태에서 사용을 한다. 목적지 VC를 객체화 하고, VC의 프로퍼티에 직접적으로 값을 전달하여 화면전환하면서 값을 넘겨받는 형태로 이루어진다.

두 방법의 공통점은 데이터 전달이지만, 가장 큰 차이점은 두 Class간의 관계이다. 첫번째는 서로 모르는 상태이고, 두번째는 한 클래스는 무조건 상대 클래스에 대해 알고있다.

6. 이번 챕터에서 학습을 하며 알게된 기술, 지식이 있다면 어떤 것이 있는지 작성합니다. (2)

DataBase를 사용하면서 누가 작성한 것을 참고하기보다, 제공해주는 Docs를 통해서 쿼리문을 작성해보았다. 값을 가져오는 부분에 있어서는 크게 문제가 없었으나, 쿼리문에 하나도 해당하지 않을 경우에 대한 예외처리를 하는것이 문제였다. 이때 하나하나 의심가는 위치에 print를 붙여 실행하기를 반복, 일종의 역추적으로 최하위 부분에서 상단으로 올라가는 Bottom to Top방식을 사용했는데, 결국 어느 위치에서 예외처리를 해야할지 알게 되었다.

셀에 남아있는 일종의 Cache를 리셋해주는 prepareForReuse를 배웠다. 해당부분은 튜터님을 통해 알게된 내용인데, 해당부분에대해 들으면서 VC의 생명주기에 대해서는 강의와 공부를 통해 알고있었던 부분인데 Cell의 생명주기도 있다는것은 생각지도 못했다.

어떤 프로젝트를 하던지 TableView 반드시 사용할수밖에 없을것 같다는 생각이 드는데, Cell의 생명주기에 대해 새로 배우다보니, Initialization이 얼마나 중요한지 다시한번 생각하게 된다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.