[iOS] 내 사진 관리 애플리케이션
in iOS on iOS, BoostCourse, Retrospective
나는 부스트코스 에이스 2019 1기로 활동중이다. 이 글은 그 중에서 iOS의 네번째 프로젝트인 기상정보 애플리케이션에 대한 회고이다.
아직 리뷰어가 지정이 안 돼서 답변은 받지 못해 내가 남긴 질문들을 정리했다😂
Q. FetchResult vs Model
프로젝트에서 fetchResult를 활용해서 collection view에 정보들을 표시해주었다. 그런데 프로젝트를 진행하다보니까 이 방식에서 불편함을 느낀 부분이 몇 가지 있었다.
그래서 AlbumModel
처럼 Model을 만들어서 앨범 이름이나, 에셋개수, [PHAsset] 등을 저장하고 이를 전반적으로 사용하는 것을 생각해봤었다.
Model을 만들어서 Asset들을 저장하는 것과 fetchResult를 활용한 방법 중 어떤 것이 더 효율적인지 궁금했다.
A. 편한 방법으로!
별도의 모델과 매니저를 만들어 관리할 경우 프로젝트 전반적으로 중복될 여지가 있는 코드들을 크게 줄일 수 있다. 그렇지만 실제 시스템의 asset과 항상 동기화를 꼼꼼히 신경써줘야 하는 문제를 떠안고 가게 됩니다. (매니저에서 무언가 변동사항이 생기면 시스템과 연동 작업을 하는게 필수가 되는 경우)
fetchResult를 사용하게 되면 중복 코드가 크게 늘어난다. 그렇지만 별도의 클래스에 해당 내용들을 저장하고 불러오고 하는 작업이 없기 때문에 동기화를 해줘야 하는 문제가 해결된다.
이 부분은 느끼기에 더 편한 방법으로 구현을 하시면 될 것 같습니다 :)
Q. 콜렉션 뷰 reload 시 requestImage()
콜렉션 뷰의 cellForItem에서 requestImage() 메서드를 호출해 받아온 이미지를 이미지 뷰에 세팅해준다.
이렇게 되면 ` collectionView.reloadData` 를 할 때마다 셀의 개수만큼 이미지를 요청하는 데, 이런 방식이 비효율적이라는 생각이 들었다.
- 아직 리뷰는 못 받았지만
NSCache
등을 통한 이미지 캐싱을 통해 콜렉션뷰를 세팅할 수도 있을 것 같다.🧐
A. 지금 같은 방법 ok
target size를 섬네일 사이즈로 잡아주셨기 때문에 이미지를 불러오는 연산 작업은 그리 큰 공수가 들지 않는 작업
둘째로 cell for item의 경우 실제 화면에 보여진/보여지게 될 cell 들을 dequeue하는 과정이기 때문에 메모리에서 큰 부분을 차지하고 있지 않다.
- 예를 들어 한 화면에 3개의 cell이 나타나는 경우라면 item의 갯수가 10억개여도 실제 메모리에 올라가있는 cell의 갯수는 많아야 7~8개 사이
즉 cell for item에서 request image를 호출하여도 크게 부담가지 않는 작업이며 사용자가 스크롤을 빠르게 할 경우에도 이전 작업이 취소되고 새로운 작업이 수행되기 때문에 지금과 같이 작성해주셔도 무방합니다 :)
Q. Operation Queue vs. Dispatch Queue
이번 프로젝트에서는 Operation Queue를 활용한다. 그런데 기존에 알고 있던 Dispatch Queue와 이 Operation Queue를 언제 어떤 기준으로 사용하는지 궁금했다. 이번에 프로젝트를 진행하면서 queue 관련 내용을 공부해봤는데
- Operation Queue는 조작(?)이 가능하기 때문에 복잡한 작업에 사용한다.
- Dispatch Queue는 간단한 작업에 사용한다. 로 대충 정리가 됐다.
그런데 아직 Concurrency 프로그래밍 관련 내용들이 어렵고 와닿지가 않아서 아직 잘 이해를 못하고 있는 것 같다.
그래서 어떤 상황에 이 큐들을 사용하는지 궁금했다.
A.
일반적으로 복잡하지 않고 성능 향상을 위해서는 DispatchQueue를 사용한다.
반면 복잡하고 작업의 정지나 취소가 필요할 때는 OperationQueue를 사용한다.
만약 성능이 중요하지 않은 앱이라면 사용의 편의성 때문에 OperationQueue가 좋고, 성능이 우선시 되는 앱은DispatchQueue를 사용하면 될 것 같다.
- https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch
- 만약 여러개의 동영상을 다운로드 기능을 만든다고 한다면, 메모리 문제로 동시에 많은 영상을 받을 수 없다. 그런 경우 작업을 나누어서 수행하게 되는데 갑자기 앱이 백그라운드로 간다던지 종료된다던지 실제로 작업을 정지한다던지의 문제가 발생한다. 이런 경우 중단이나 취소가 필요하게 됩니다.
- 이런 경우도 사실 DispatchQueue로 해결할 수도 있지만 OperationQueue에서 좀 더 손쉽게 처리가 가능하다.
질문외에도 프로젝트 리뷰를 해주셨는데
레이아웃 위치를 계산하기 위한 별도의 로직을 만든 점 좋습니다. (콜렉션뷰의 레이아웃을 계산하기 위해
LayoutCalculator
라는 구조체를 만들었다.)별도 로직은 Struct로 만든 것도 좋긴하지만 CollectionViewFlowLayout의 Extension으로 했을 때 장점은 무엇인지도 고민해주세요.
오,, 저 로직은 collection view의 flow layout만을 위해 만들어진 로직이기 때문에 extension으로 확장을 시켜도 좋았을 것 같다. 그렇게 되면 다른 곳에서 재활용할때도 flowlayout의 기본 계산로직처럼 사용하고, 매번 생성을 하지 않아도 될 것 같다.
강제 언래핑은 지양해주세요.
강제 언래핑은 많은 오류의 근원입니다.
특히 swift에서 옵셔널을 지원하는 이유를 생각해보시면 강제언래핑은 꼭 필요한 경우가 아니고서는 사용하시면 안됩니다.
강제 언래핑은 정말 꼭 필요한 경우에만 사용해야하는 것 같다. 이 강제 언래핑때문에 크래시도 났었다..ㅎㅎ.
강제 언래핑을 사용하는 경우는 IBOutlet처럼 이건 초기화 시점에만 없는 값인데 무조건 들어올거야! 라는 것을 컴파일러에게 알려주는 경우! 라고 기준을 정했다. 하나 효과적인(?) 부분은 협업을 하게 된다면 다른 개발자나 미래의 나에게 명확하게 이 값은 있는 것이야 라는 것을 전해주기 좋을 것 같다.
PhotoLibrary사용시 최적화 부분에 아쉬움이 있습니다.
실제로 변경된 정보만 바꿔주시는 것이 좋습니다.
https://developer.apple.com/documentation/photokit/phphotolibrarychangeobserver
링크를 참조해주세요.
dateLabel과 timeLabel은 대부분 같은 속성을 공유하고 있습니다.
이런 경우 UILabel은 사용하는 별도의 커스텀 Label을 만들어 사용하는 것이 좋습니다.
커스텀 lable을 만들어서 재활용하자!
현재 MVC구조로 프로젝트를 작성하고 있습니다.
한가지 아쉬운 점은 Model에 대한 정보가 제대로 표현되고 있지 않습니다.
일반적인 MVC에서 Model은 자료구조뿐 아니라 비지니스 로직도 담당하고 있습니다.
현재 ViewController에 있는 기능 중 어떤 부분이 Model로 오면 좋을지 고민해주세요.
이전 프로젝트에서는 비즈니스 로직을 많이 빼냈(?)었는데, 이번 사진 프로젝트에서는 그런 부분을 많이 못한 것 같다. 추후에 ViewController에 있는 기능을 Model로 구분하는 작업을 해봐야겠다.
인상적인 부분은 주석으로 궁금한 점을 기록한 것입니다.
이렇게 궁금한 사항을 직접 물어봐주시면 리뷰어가 더 많은 정보를 전달드릴 수 있습니다.
프로그래밍에 대한 관심도 높아보여서 보기 좋았습니다.
이번 프로젝트에서 앱 크래시 때문에 리뷰를 두 번이나 받았다..
가로화면은 생각지도 못했어서 크래시가 있는 줄도 몰랐다. 강제 언래핑 함부로 사용하지 말자는 생각 두번 세번..백번..
포토!! 재밌었지만 어려웠고 리뷰도 오래걸려서 힘들었던 프로젝트…그래도 하고 나니 뿌듯하다ㅎㅎ