일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 리프2기
- 파이썬중급
- 인프런파이썬
- 프로그래머스
- 우리를위한프로그래밍
- swift
- 스위프트
- 인프런오리지널
- Python3
- 카카오톡채팅봇
- rxswift
- 토플
- 파이썬웹크롤링
- 토플공부수기
- 파이썬중급강의
- 노드JS
- 인프런파이썬강의
- SwiftUI
- 파이썬
- JS
- uikit
- nodeJS
- 웹크롤링
- 인프런강의
- 인프런
- IOS프로그래밍
- 자바스크립트
- 유학토플
- 교환학생토플
- IOS
- Today
- Total
먹고 기도하고 코딩하라
[PhotiCase] 발단과 1주 본문
나는 얼마 전에 친구들 앞에서 약속을 했다.
"내가 8월 말까지 이거 못 만들면 너네 중에 한 명한테 피자 사준다."
그렇게 공개적으로 얘기한 건 그렇게 하지 않으면 내가 영원히 시작하지 않을 것 같은 느낌이 들어서였다.
일단 만들고 개선을 시키는 걸 목표로 해야 하는데 처음부터 너무 완벽하게 하고 싶은 마음에 계속 시작을 유예했다.
근데 더 이상은 그럴 수가 없어서 이제는 진짜 해야겠다는 마음으로 그렇게 지른 거였다.
근데 시작을 언제 했다?
8월 27일.
...
가보자고~
디자인
사실 프론트엔드를 할 때도 디자인을 그렇게 빡세게 한 편은 아니었다. 내가 디자인을 세밀하게 하는 경우는 2가지 정도인데, (1) 돈이 걸려 있는 문제이거나 (2) 팀 작업을 할 때 디자인을 공유해서 웹앱 디자인이 사람들의 머릿속이 아니라 결과물로 뚜렷하게 드러나야 하는 경우이다.
내 경우에는 돈을 받고 만드는 것이 아니며, 나 혼자 작업하는 것이기 때문에 헷갈릴 사람도 없다. 그래서 figma 디자인은 러프하게만 했고, 공책에 와이어프레임을 참고하면서 했다.
기능
내가 주기능을 짜 보니.. 4학년 때 졸업 작품하면서 서류를 엄청 많이 쓰게 시킨 게 이게 괜히 시킨 게 아니었구나 싶다. 그런 가이드라인 문서가 있으면 정말 좋다. 그 문서를 참고해서 어떤 기능이 필요하고, 어떻게 동작해야 하는지 등을 계획하면 꽤 그럴듯한 흐름도와 기능 명세서가 나온다.
주기능은 다음과 같다.
루트 뷰 컨트롤러는 탭바 컨트롤러로, 4가지 탭으로 분기된다.
(1) 홈
- 뷰에 달력이 표시되며, 위아래로 스크롤해서 이전과 미래로 갈 수 있다.
- 뷰의 날짜를 탭하면 그 날 관람한 작품을 추가할 수 있다.
- 작품을 추가하면 해당 날짜에 등록한 사진이 보이도록 한다.
(2) 검색
- 네이버 영화 API를 이용해 영화를 검색할 수 있다.
- 이 앱은 영화 추천이나 검색 자체가 목적이 아니기 때문에 정보는 제목, 년도, 감독, 별점 등 사용자가 자신이 관람한 영화가 이것이 맞는지 알 수 있을 정도로만 간단하게만 구성한다.
- 검색한 작품을 기록에 추가할 수 있다.
(3) 직접 추가
- 네이버 영화 API에서 검색되지 않는 영화나 드라마 등을 직접 추가할 수 있다.
- 제목, 평점, 본 날짜를 필수로 입력하도록 하고 그 외 평점, 같이 본 친구, 감상평 등 메모 등은 선택적으로 기록할 수 있다.
- 사용자는 갤러리에서 작품을 기억할 자신만의 사진을 선택해 간단히 편집할 수 있다.
- 이렇게 편집한 사진과 기록은 (1) 홈 화면의 해당 날짜에서 확인할 수 있다.
(4) 티켓북
- (1) 홈 화면에서는 사진만 볼 수 있는 반면, 티켓북 탭의 뷰에서는 대략적으로 어떤 내용을 썼는지도 보기 쉽게 구성한다.
- 타임라인, 목록, 갤러리 형식 등으로 표시 포맷을 구성하고, 최고 별점 등으로 정렬해서 볼 수 있도록 한다.
여기에 나중에 부차적으로 소셜 로그인, "보고 싶어요" 기능, 영화/드라마 외 책이나 공연, 기타 모임 등도 커스텀해서 달력에 집어넣을 수 있도록 부수적인 기능도 넣을 생각이다.
그래서 진행은?
8월 27일
- 프로젝트를 만들었다.
- 위 사이트에 방문해서 swift, mac, xcode 등을 입력해 .gitignore 파일을 받은 뒤 프로젝트 루트에 넣었다.
- 스토리보드를 사용하지 않는 프로젝트이기 때문에 main 스토리보드를 삭제하고, SceneDelegate에서 루트 뷰를 띄울 수 있도록 수정했다.
- 루트 뷰 컨트롤러가 될 탭바 컨트롤러 클래스가 담긴 파일을 생성한다. 이전까지는 탭바를 코드로 작성해본 적이 없었는데 이번에 새로 작성하게 됐다. 방법은 아주 쉽다. 탭바 아이템을 탭했을 때 연결할 뷰 컨트롤러 객체를 만들고, 탭바 아이템을 만든 다음 뷰 컨트롤러.tabBarItem에 바 버튼 아이템을 추가한 뒤, 그것들을 viewControllers에 배열로 추가하면 된다.
private func addViewToTabBar() {
let tabHome = UINavigationController(rootViewController: HomeViewController())
let tabHomeBarItem = UITabBarItem(title: "홈", image: UIImage(systemName: "house"), selectedImage: UIImage(systemName: "house"))
tabHome.tabBarItem = tabHomeBarItem
// code
viewControllers = [tabHome, tabSearch, tabAdd, tabRecord]
}
- 탭바의 "홈"을 탭했을 때 나타날 뷰에는 달력을 띄울 예정이었는데, collectionView로 직접 만드는 방법이 있었고 라이브러리를 쓰는 방법이 있었다. 달력은 어차피 홈 뷰에서만 띄울 거고 커스텀이 많이 들어가지도 않을 것 같다는 생각에 fscalendar라는 라이브러리를 쓰기로 했다. 참, 외부 라이브러리를 사용하는 데 있어서는 SPM을 썼다.
- 꽤 좋은 달력이 나오기는 했지만, 셀을 커스텀해서 사용해야 했다. 이 셀은 FSCalendarCell 클래스를 상속받아서 만들게 되는데, configureAppearance 메소드를 오버라이드해서 그 안에서 주로 외관을 바꿔주면 됐다.
- 사실 FSCalendarCell을 커스텀을 많이 해서 쓴 사례를 많이 보진 못 했다. 검색을 했는데도 별로 안 나와서 그냥 FSCalendar Jump to Definition 해서 이게 대충 뭐겠구나 싶어서 테스트를 많이 해봤다. 그 결과...
- 각 셀에 이미지를 삽입할 수 있게 됐다.
- placeHolder, 즉 이번 달은 아니지만 달력에 공간이 남아서 표시되는 이전, 다음 달 날짜들을 연하게 표시하고 이벤트 표시자를 숨길 수 있었다.
- FSCalendarCell을 따로 만들어서 register하니까 기존에 어떤 날짜를 탭(select)했을 때 날짜를 표시하는 둥그런 원이 나타나지 않아서 애를 먹었는데, 비슷하게 구현할 수 있었다. selectionLayer의 path를 UIBezierPath로 적절히 그려주면 됐다.
- 마찬가지로 오늘 날짜는 특별하게 표시되어야 했는데 그것마저 안 됐다. 위와 같이 해결했다.
- 뜻밖에 FSCalendar를 좀 잘 뜯어보게 된 것 같은데 나중에 fscalendar 글을 써도 좋을 것 같다. 헤더 설정, locale, 스크롤부터 폰트 설정, 글자 색상 설정, placeholder 표시 여부 등등 여러 가지 소득이 있었다. 그 중 제일 훌륭했던 소득은 주말 중 토요일은 파랑색, 일요일은 빨강색으로 표시할 수 있도록 바꾼 것이었다. 방법이 궁금하면 500원
- 탭하면 다른 달력이 나올 수 있도록(아직 그 기능을 구현한 건 아니지만) 버튼을 2개 만들었다. (그런데 이건 버튼도 좋지만, segmented control을 사용하는 게 더 나은 방법일 것 같다. 불과 1주일 전이지만 몰랐다..)
- 전혀 기대하지 않았는데 얻게 된 것 중 하나: inset, offset을 이제 헷갈리지 않고 이해하게 됐다.
- 결론적으로는 다음과 같은 뷰를 만들 수 있게 됐다. 날짜를 탭하면 ActionController가 actionSheet 스타일로 올라오면서 작품 추가를 할 수 있도록 했다. (물론, 그 기능은 아직이다)
8월 28일
- "검색" 탭의 뷰를 만들기 시작했다. 일단 searchController를 붙였다.
- 그런데 대체 어디서 검색을 할 것인가? 잠깐 컴퓨터를 재워두고 고민하기 시작했다.
- 네이버 영화 API : 가장 적합한 데이터를 제공하고 있다. searchController에 사용자들이 입력하는 문자열을 query로 넘기고, start 수를 조절하면 결과를 잘 가져올 수 있었다. 문제는 이 너무 좋은 API 응답에 줄거리가 포함되어 있지 않았다. 국내 영화 API는 네이버 영화, KOPIS API 정도를 쓸 수 있는데 둘 모두 줄거리가 포함되어 있지 않았다. 입맛은 쓰지만 별 수 없었다.
- KOBIS API : 저번 "동갑내기 영화 보기" 앱에서 사용했고, 재작년에 웹앱으로 만든 것에서도 사용했던 API이다. 이것도 역시 줄거리는 없는데, 영화 목록 API와 영화 상세 정보 API가 나뉘어져 있어서 대략적인 검색 결과 표시에는 네이버 영화 API를 쓰고, 영화를 나타낸 셀을 탭했을 때 나타낼 상세 정보로는 KOBIS API를 쓰는 게 좋아보였다.
- TMDB : 외국 영화 데이터베이스 API이고, 일단 규모가 크다는 게 장점이었지만 한국어 번역이나 그런 문제를 생각해보면 쓰지 않는 것이 더 좋겠다는 생각이 들었다. 더군다나 줄거리나 큰 포스터 이미지를 얻자고 이걸 쓰기에는 꽤 무거울 것 같은 느낌이라 사용하지 않았다. 나중에 규모가 커지면 사용을 고려할 수도 있지만 한마디로 not now
- 결론 : 네이버 영화 API 검색 결과를 목록으로 보여주고, 상세 페이지는 KOBIS API를 사용하자.
- KOBIS API key는 이미 갖고 있었으므로 네이버 검색 API만 신청했다. 신청은 무료이고, 검색 API는 일 25,000회까지 사용할 수 있다. 신청 방법은 따로 설명하지 않아도 괜찮을 정도로 쉬워서 그냥 넘어간다.
- searchController는 내비게이션 아이템에 추가해서 사용하는데, searchBar의 delegate를 뷰 컨트롤러가 맡아줘야 한다. 사실 별 거는 없으며 UISearchBarDelegate의 메소드 중 searchBarSearchButtonClicked, 즉 키보드의 "검색" 키가 눌렸을 때 어떤 것이 실행될지 적어주는 정도만 구현하고 그 외의 것은 추가적으로 구현하면 된다.
- 이 때만 해도 내가 어떻게든 말일까지 기능을 다 구현할 수 있으리라는 희망에 사로잡혀서 리팩토링은 뒷전으로 밀어놓고 파일을 마구잡이로 만들었다. 그런데 씬이랑 모델 정도는 구별을 해야겠기에 간단히 구별하고, Movie 모델을 만들었다.
- 모델을 만들 때 대충 만들 수가 없었다. 모델의 프로퍼티 이름이나 속성, 뭐 하나 틀리는 게 있으면 JSONDecoder로 해당 클래스로 decode할 때 문제가 생겼다. 여러 번 확인하는 게 필수였다. 하지만 한 번 제대로 만들고 나면 참 편하다.
- 검색 결과는 UITableView에 담기로 했다. TableViewCell은 다음과 같이 생겼다.
- 이 커스텀 셀 파일을 만들어주고 SnapKit으로 constraints를 잡아줬다.
- 네이버 영화 검색 결과를 받아와보니, 제목에 <b>, </b> 하면서 태그로 감싸져 있는 부분들이 있었다. 검색 API 명세를 참고하면, 응답에서 쿼리에 맞는 응답들이 그렇게 태그에 감싸져 있었다. 이런 것은 replacingOccurences(of:) 메소드로 해결할 수 있었다.
var title = movie.title?.replacingOccurrences(of: "<b>", with: "")
title = title?.replacingOccurrences(of: "</b>", with: "")
- 또한 감독 정보가 없는 경우도 꽤 많았는데 이런 경우는 "감독 미상"으로 표기할 수 있도록 바꿔주기도 했다.
- Alamofire를 이용할 수도 있었지만 URLSession을 사용했다. KOBIS에 요청할 때와는 다르게 네이버에 요청할 때는 요청 헤더에 네이버 클라이언트ID와 시크릿 키를 넘겨야 했다. 가만히 생각해보면 자바스크립트랑 비슷한 점이 있다. 역시 어디서 잘 배워놓으면 다른 데 가서도 잘 써먹는다.
- 이렇게 하니 searchBar에 텍스트를 입력하고 "검색"을 눌렀을 때 검색 결과를 잘 불러오긴 했다. 그런데 심각하다면 꽤 심각할 수 있는 문제가 있었다.
- (1) 네이버가 영화 목록 결과를 최신 순으로 정렬해서 주는 건지 2022년도부터 뒤로 갈수록 옛날 영화들을 반환하는 그런 식으로 응답을 주기 때문에 사용자가 영화 제목의 일부만 입력한다면 그 결과를 찾기까지 꽤나 오랜 시간이 걸릴 수 있었다. 예를 들어, "사랑도 번역이 되나요?" 라는 영화를 검색하고 싶어서 "사랑"을 입력했다면 "사랑"이 제목에 포함된 2022년 영화들부터 쭉쭉쭉 내려가야 했다.
- (2) 그러나 이것보다 더 큰 문제는... 그거 아는가? 한국에 합법적으로 등록되는 에로 영화가 꽤나 많다는 걸. 넷플릭스에 올라오는 핑크 무비를 보면서 고개를 절레절레 흔든 게 엊그제 일 같은데 이게 이렇게나 많이 등록되는 줄 몰랐다. 뭐 예를 들면 "그녀", "여자", "남자", "아내", "여자친구", "사랑" 등의 검색어를 친다면 행여나 지나가는 사람이 보고 오해할까 굉장히 걱정되는 앱으로 전락하게 될 처지였다. 위 검색어만 그런가? 나는 다른 검색어가 잘 동작하는지 확인하려고 머리에 떠오르는 아무 단어나 입력했는데 10개 받는 결과에 꼭!!! 에로 영화가 한 개씩은 있었다. 정말 질릴 정도였다.
- 그러나 나는 이 문제를 꽤 간단하게 해결했다. 정확히 말하면 완전히 해결한 건 아니지만 적은 노력을 들여 상당 부분 해결했다고 자부할 수 있다. 어떻게 했냐면... 이 역시 궁금하면 오백원.
- 2일차까지 마치고 난 다음의 결과는 이렇게 나왔다. 아직 상세 페이지로 넘어가지는 않고, 결과 역시 10개 이상 나오지 않지만 일단 검색 API에 잘 요청한다는 걸 확인하고 난 뒤라서 홀가분했다.
8월 29일
- 검색 결과가 10개만 나오게 할 수 없어서 display를 늘렸다. 그리고 기존 쿼리에 start도 넣어서 이미 앞에서 나온 결과들이 중복으로 나오지 않도록 처리했다.
- UIActivityIndicatorView를 붙여서 결과를 가져오는 동안 표시자가 뱅글뱅글 돌 수 있도록 했다. 이 정도는 센스!
- 사용자가 스크롤을 마치기 전에 미리 다음 결과를 가져오기 위해 UITableViewDataSourcePrefetching도 self로 해서 프로토콜을 준수했다. 이 때는 prefetchRowsAt 이 매개변수로 든 함수를 구현하면 되는데, 여기서 페이지든 뭐든 검사해서 fetch하는 함수를 호출하면 된다.
- @escaping 클로저에 대해 확실하게 이해할 수 있었던 날이었다. 그 동안은 그냥 표시자 돌게 하려고 무지성으로 쓰던 거였는데 왜 쓰는지 갑자기 궁금해져서 논이스케이핑, 이스케이핑 클로저가 뭐가 다른지 살펴볼 수 있는 좋은 기회가 됐다.
- 별 건 아니었지만 탭 간 이동이 일어날 때 뚝뚝 끊기게 화면 전환이 일어나는 게 아니라 부드럽게 화면 전환이 되도록 만들고 싶었다. 그래서 UIView를 extension해서 알파값을 이용한 간단한 애니메이션을 넣은 fadeIn, fadeOut 함수를 만들었다.
- 네이버 영화 API용 모델과 KOBIS API용 모델을 따로 만들었다.
- 문득 브랜드 컬러로 사용하는 컬러를 UIColor로 소숫점으로 갖고 있지 말고 Assets에 넣어야겠다는 생각이 들어서 Color set에 primary로 추가했다. 기존에 UIColor로 사용하던 코드들은 .primary로 간단하게 다 바꿔놨다. 이렇게 하면 만약 내가 나중에 색상을 바꿔도 코드상에서 추가로 처리할 작업이 없어서 편하다.
- 별점을 추가하는 서브 뷰를 위해 SF Symbols를 다운로드받아서 빈 별, 반만 찬 별, 꽉 찬 별 svg 파일을 받아 Assets에 추가했다.
- 드래그와 탭으로 별점을 부여할 수 있도록 UISlider의 beginTracking 메소드를 오버라이드했다. Star slider 이런 걸로 검색하면 자료가 조금이나마 나온다.
- 사실 이 별점 슬라이더와 별들을 겹치게 배치하는 게 어려웠는데, UIStackView로 감싸서 constraints를 맞게 설정해도 계속 깨진다고 에러가 났기 때문이다. 이 글을 쓰는 지금도 여전히 그런데, UIView로 감싸는 걸로 대체해야겠다. 어쨌든 정상 동작은 하지만 constraints 깨지는 건 해결해야 한다.
- 상세 페이지에서는 이전 뷰에서 탭했을 때 받아오는 영화 제목 정보로 KOBIS API에 검색을 해서 그 영화의 영화 코드를 알아내고, 그 코드를 사용해 또 영화 상세 정보를 검색해 그 정보를 뷰에 적절히 표시하는 것을 목표로 했다. 그러니까 서로 다른 API 2개를 호출하는 셈인데 그래서인지 약간 지연이 생겼고, 아직 해결하지 못한 상태이다. 서비스에 치명적인 단점이 되지는 않는다는 생각이 들어서 다가오는 주에 다른 중요한 기능들을 먼저 구현한 뒤 수정할 예정이다.
- 사실 여기서도 fetch를 하다 보니 겹치는 코드가 이제 파일마다 조금씩 생기게 됐는데 다가오는 주에 이것도 리팩토링이 될지 검토하려고 한다.
- "검색" 탭에서 searchBar에 검색했는데 그런 영화가 없거나 뭔가 사용자가 잘못 입력했거나 하는 경우에 검색 결과가 전혀 없을 수 있다. 이런 경우 빈 화면을 띄우면 사용자 입장에서는 아직 응답을 기다리는 건지 뭔가 잘못된 건지 알 수 없으므로 이런 경우 사용자에게 보여줄 레이블을 추가했다.
8월 30일
- 영화 상세 페이지에서 영화 제목이 1줄 이상으로 길어지면 뒤가 ...으로 생략되는 것을 보고 numberOfLines를 늘렸다.
- 사용자의 갤러리에서 사진을 불러올 수 있는 방법은 원래 다른 게 있었는데 이번에 PhotosUI의 PHPicker를 써보게 됐다. PHPicker의 제일 큰 장점은 사용자의 허가가 따로 필요하지 않다는 점이다. 게다가 사용하기도 아주 쉽다. Configuration도 별 게 없어서 편리했다.
- "직접 추가" 화면에서 사진을 추가할 수 있는 서브 뷰를 만들었다. 이 때 이미지를 적절히 편집할 수 있도록 하려고 ImageView에 UIGestureRecognizer 붙여서 핀치 받을 수 있게 했는데 원하는대로 잘 되지는 않았다. 이미지뷰가 수퍼 뷰 크기보다 더 크게 확대되는 것을 막아야 했는데 그게 안 됐다. 하루동안 방법을 고민하게 됐다.
- "직접 추가" 화면에서 사진을 선택할 수 있는 뷰로 넘어가기 전, 사용자는 직접 추가할 콘텐츠의 간단한 정보를 입력하게 된다. 제목, 평점, 날짜는 필수적이고 그 외 다른 것들은 선택적으로 입력할 수 있는 일종의 폼이 들어있는 뷰를 만들었다.
- 여기서 겹치는 코드도 많고 해서 Label, TextField, StackView 등은 아예 따로 만들어버렸다. 이렇게 하니까 코드 양을 많이 줄일 수 있는 데다가 뭔가 변경해야 하면 따로 만든 클래스로 가서 변경하면 되니까 편했다.
- segmented control을 사용해서 영화, 드라마 등 사용자가 콘텐츠의 유형을 직접 선택할 수 있도록 했다. 좀 더 세련된 디자인을 주고 싶었는데 나중에 여유가 되면 디자인을 개선하기로 했다.
- 스크롤뷰에는 touchesBegan을 붙여도 소용없다는 사실을 나중에 깨달았다. 대신에 UIGestureRecognizer를 스크롤뷰에 붙이고, action으로 view.endEditing(true)를 수행하는 @objc 메소드를 붙여주면 된다.
- 스크롤뷰로 바꿨음에도 화면 아래쪽에 있는 TextView인 메모 뷰에 뭔가를 입력하려면 키보드 때문에 뷰가 가려져서 보이지 않았다.
- 이 문제를 해결하려고 UIViewController extension해서 keyboardWillShowNotification, keyboardWillHideNotification에 대해 addObserver해서 키보드의 높이를 잰 다음, 키보드가 올라와서 보일 때는 그만큼 화면을 올리고 키보드를 내릴 때는 다시 그만큼 화면을 내려주는 메소드를 추가로 작성했다.
- 그런데 사실 이렇게 해도 문제가 시원하게 해결되지는 않는 게 왠지는 모르겠는데 스크롤뷰에서 이렇게 addObserver 붙여놓고 나니까 keyboardWillShowNotification이 2번 발생해서 화면이 훅 올라가게 되었다.
- 그래서 self.view.window.frame.origin.y가 0보다 크거나 같은지 확인해서 그런 경우에만 화면을 올릴 수 있게 했다.
- 사실... 근데... 그렇게 해도 뭔가 시원하지는 않았다. 왜냐하면 굳이 키보드를 올릴 필요가 없는 텍스트뷰나 텍스트필드를 편집할 때도 키보드가 올라오면 화면이 쑥 올라가서 사용자가 눈을 위로 쓱 굴려야 하기 때문이었다.
- 어쨌거나 좀 찝찝한, 반쪽짜리 해결을 했다. 완성된 뷰는 이렇다.
8월 31일
- 이 날 점심쯤 도저히 내가 마감을 맞출 수 없겠다는 생각이 들어서 친구에게 약속대로 피자를 보내줬다.
- 어쨌거나 불은 붙었고 개발은 계속됐다. "검색" 탭에서 검색 결과가 없을 때 미리 정해뒀던 레이블이 나타나지 않고 빈 화면이 나오던 에러를 잡아서 고쳤다.
- 또, 어찌 보면 텍스트 처리의 기본이라 할 수 있는 화이트스페이스 트리밍하는 걸 뒤늦게야 했다. ^^;
- "직접 추가" 탭에서 폼과 사진 추가를 하는 뷰 사이에 아직 연결 고리가 없는 상태였는데, 폼이 있는 뷰의 내비게이션 아이템 오른쪽에 "다음"이라고 적힌 바 버튼을 달았다. 이 바 버튼은 필수 항목은 제목, 날짜, 평점이 채워지면 자동으로 enabled되고, 셋 중 하나라도 비게 되면 바로 disabled되게 만들었다.
- 사실 날짜의 경우, datePicker는 자동으로 오늘 날짜를 선택하게 되어 있다. 그래서 날짜의 경우 굳이 건드리지 않아도 되도록 했다. 사용자가 직접 편집하는 항목은 적으면 적을수록 좋으므로 제목과 평점만 필수적으로 채울 수 있도록 했다.
- 실제로 레이블이 잘 채워졌는지에 대한 확인은 StackView에서 하고, 그 확인 여부에 따라 "다음" 바 버튼의 상태를 바꾸는 것은 스택뷰를 갖고 있는 UIViewController에서 하는 거라서 StackView에서 NotificationCenter로 post 해서 알림을 보내도록 했다. NotificationCenter. 따봉.
- 내비게이션 아이템에 넣는 바 버튼의 경우 이유를 모르겠는데 viewDidLoad 등의 뷰와 관련된 함수 내부가 아닌, 그냥 뷰 컨트롤러에서 선언하면 내비게이션 아이템에 들어는 가지만 탭했을 때 연결한 셀렉터 함수가 아예 호출되지 않는 이상한 현상을 보였다. 아직도 원인을 모르겠다. 그런데 viewDidLoad와 같은 뷰 생명주기 함수에서 생성해서 넣으니 셀렉터 함수가 잘 호출됐다. 원인은 여전히 불명. 뭘까?
- 사진을 추가해보다가 어떤 사진은 이상하게도 이미지뷰에 들어가지 않는다는 사실을 알았다. 왜 그런가 하고 보니 그 파일은 webp 확장자 파일이었다. 요즘은 구글이나 그런 데서 이미지를 저장하면 반드시 jpeg, png로 저장되지 않고 webp로도 많이 저장되는 것 같다.
- 어쨌든 그것도 사진의 일종인데 그걸로도 만들 수 있게 해야 했으므로 이미지뷰로 받을 수 있는 UTType들을 리스트로 묶어서 itemProvider가 해당 타입 중 하나에 해당되는지 확인하고 해당하면 이미지 뷰에 넣을 수 있도록 바꿨다.
- 결과는 성공. 에러 처리도 해주기는 해야 하는데 도대체 어떤 에러가 나는지 알 수가 없어서 어떻게 뷰 구성을 해야할지 모르겠다.
- 얼마 전에 사진 이동과 핀치 줌 등을 했을 때 수퍼 뷰를 벗어나는 이슈로 골머리를 앓았다. 그래서 검색을 오랫동안 하다가 답을 찾았다. 바로 스크롤뷰를 선언하고 그 안에 UIImageView를 서브뷰로 등록하면 된다는 거였다.
- 유레카다! 완전 꿀팁 아닌가? 횡방향, 종방향 스크롤 다 되는 데다가 수퍼 뷰를 절대 넘지 않는다. 천재가 따로 없다.
- 결과는 이렇게 됐다.
9월 1일
- 결국 나는 타협했다. 텍스트필드, 텍스트뷰 위치에 따라 화면을 올리고 내리는 것을 정교하게 하기에는 세상에 좋은 라이브러리가 너무 많다. 결론적으로, 나는 IQKeyboardManagerSwift라는 라이브러리를 설치했고 광명을 찾았다. 사용 방법도 아주 간단한데, AppDelegate.swift에서 import하고 didFinishLaunchingWithOptions 매개변수를 가진 application 메소드 내에 다음 한 줄을 추가해주면 된다.
IQKeyboardManager.shared.enable = true
- 사진 편집 뷰에도 우측 내비게이션 바 버튼 아이템을 추가해서 뒷면 편집을 하게 할지, 아니면 앞면 편집만 하게 할지를 결정할 수 있게 하려고 context menu를 띄우기로 했다. 이건 UIBarButtonItem을 생성할 때, init 함수 중에 menu가 있는 것을 골라 거기에 UIMenu를 추가하되, [UIAction]을 children으로 넘기면 된다. 그러면 탭했을 때 context menu가 나타난다.
- 이 날은 밀린 강의 복습을 하느라 프로젝트를 많이 하지 않았고, 리팩토링을 주로 했다. 이제 제법 파일이 많아져서 정리하지 않으면 보기가 불편하다. Scenes 안에서도 탭별로 폴더를 더 잘게 나누고, 필요 없는 코드들을 걷어냈다. (물론 걷어내고 문제가 없이 전과 같이 동작하는지 확인한 다음 걷는다)
- 더 이상 미친 듯이 빠르게 휘몰아칠 필요가 없다는 것을 깨닫고 나니(피자는 이미 줬으니까) 마음이 홀가분해져서 리팩토링할 여유도 생긴 것 같다.
- 나중의 나를 위해서 모호한 것들에는 주석도 남겼다. 평소 주석을 잘 남기지 않는데, 이해하기 어렵거나 어떤 라이브러리를 사용해서 커스텀했다면 그런 것들은 꼭 주석을 남겨야겠다는 생각을 한다. 주석을 위한 주석이 되지 않도록 주의는 해야될 것 같다.
- 그리고 각 뷰 컨트롤러별로 갖고 있는 뷰가 어떤 행동을 추가로 해야하는지, 아니면 수정해야 하는지 등을 MARK로 남겨놨다. 이것을 토대로 2주차 개발을 진행할 예정이다.
'개발일지' 카테고리의 다른 글
[PhotiCase] 3주 (0) | 2022.09.26 |
---|---|
[PhotiCase] 2주 (0) | 2022.09.11 |
2021 졸업 작품 소개 (4) | 2021.12.30 |
2021 졸업 작품 개발 일지 (0) | 2021.12.30 |
[인공지능] 로이터 뉴스 카테고리 분류 과제 (0) | 2021.02.22 |