✧ 소개
프로젝트 기간: 2024.02 ~ 2024.04 (약 2.5개월)
BoxOffice 리팩토링 프로젝트.
영화진흥위원회 Open API, Daum 검색 API를 활용해 선택한 날짜의 일일 박스오피스 목록과 선택한 영화의 포스터 이미지 및 상세 정보를 확인할 수 있는 앱
💻 개발환경
항목
사용기술
Actor의 프로퍼티 / 메서드에 접근할 때 await 키워드를 사용해야 하는 이유
야곰의 말씀대로, Actor는 비동기 환경에서 공유자원을 안전하게 사용하기 위해 나온 타입입니다.
공식 문서(Actors - Swift Language Guide)에 따르면 actor는 클래스와 마찬가지로 참조타입입니다. 하지만 클래스와 다르게 한 번에 오직 하나의 task만이 actor의 mutable state에 접근할 수 있도록 하여 비동기 환경에서 공유 시 발생할 문제점을 예방합니다.
Actor protocol의 공식문서를 보면 Actor protocol은 Sendable protocol을 상속받는 것을 확인할 수 있습니다.
Sendable protocol을 준수하기 위해서는 4가지 조건이 있었습니다.
Value types
Rowan changed 2 years agoView mode Like 1 Bookmark
Result type
Result type은 swift standard library에 구현되어있는 열거형 데이터타입이다. success와 failure 두 가지 경우로 나뉘어(switch와 잘 맞음) value를 저장한다.
@frozen enum Result<Success, Failure> where Failure : Error
공식 문서에 정의된 내용을 살펴보면, Failure는 Error 프로토콜을 채택하고있어 do-catch문과 유사하게 오류처리가 가능하다는 특징이 있다.
<br/>
💭 예제를 활용한 이해
enum ValueError: Error {
Rowan changed 2 years agoView mode Like 5 Bookmark
안녕하세요 여러분!
제가 은행창구 매니저 프로젝트를 진행했을 때 해결하지 못했던 문제를 이번에 해결하게 되어서 여러분들께 도움이 될까 하여 공유해봅니다.
야곰닷넷의 Concurrency Programing 코스 GCD 예제를 보면 비동기 코드 테스트는 플레이그라운드를 활용할 것을 권장하고 있습니다. CLT 환경에서는 마지막 코드가 끝나면 프로그램이 종료되기 때문이라고 하고, CLT 환경에서 비동기 코드를 테스트하려면 어떤 코드들이 추가로 필요할 것이라고도 나와있죠.
직접 Xcode의 CLT project에서 비동기 코드를 테스트해보면 실제로 잘 작동하지 않는 경험을 할 수 있습니다. 아래 사진처럼 말이죠......
이런 현상은 왜 일어나는 걸까요? CLT는 한 번 실행되고 나면 프로그램이 종료되는 Top-down approach를 사용하고 있다고 합니다. 따라서 main.swift 파일에 실행할 코드가 더 이상 없다면 프로그램이 종료가 되어버립니다. 비동기로 넘긴 코드들은 main 스레드에서 실행되지 않기 때문에 실행할 코드가 없어지겠죠?!
그러면 CLT 환경에서 비동기 코드를 실행하려면 어떻게 해야할까요?
Rowan changed 2 years agoView mode Like 2 Bookmark
https://help.apple.com/xcode/mac/11.4/#/devc8c2a6be1
위 문서에서 아래의 용어 또는 내용에 대해 알아보고 내 프로젝트에는 어떻게 적용되어 있는지 확인해보고 오세요.
Project
Apple 플랫폼용 앱, 라이브러리 및 기타 소프트웨어를 구축하는 데 사용하는 코드와 리소스를 관리하는 곳.
Bundle ID / App ID
번들이란? 실행가능한 결과물이 되는 리소스를 포함한 모든 파일
안녕하세요 줄라이!
해리, 로웬 조 Diary 프로젝트 첫 PR 보내드립니다 🙌
이번 프로젝트 동안 잘 부탁드립니다!!
고민한 점
DateFormmater.locale
Diary 작성일자가 사용자의 지역 포멧에 맞게 표현될 수 있도록 DateFormatter의 locale 프로퍼티를 설정하였습니다.
dateFormatter.locale = Locale(identifier: Locale.current.identifier)
30 (금)
Protocol
🔎 간단한 개념정리
프로토콜은 타입의 청사진이라고 할 수 있다. 프로토콜을 이용해 특정 역할을 수행하기 위한 요구사항(메서드, 프로퍼티, 이니셜라이저)을 구현해줄 수 있다.
구현한 프로토콜은 타입이 채택할 수 있고, 이를 해당 타입이 프로토콜을 준수한다고 표현한다.
프로토콜에서 정의한 코드는 채택한 타입 내부에서 반드시 구현해야 한다.
프로토콜은 class, struct, enum 모두 채택할 수 있고 다중 채택이 가능하다.
protocl정의 후 extension을 사용하여 protocol내부의 아직 구현되지 않은 프로퍼티, 메서드의 내용들을 구현할 수 있다.
CoreData 저장 위치 관리 객체
CoreData를 활용하기 위해서는 먼저 CoreDataModel을 생성하고 Core Data Stack을 준비해야한다.
iOS 10 이전 버전에서는 NSPersistentContainer 클래스가 없었기 때문에 Core Data Stack을 구성하는 ManagedObjectModel, ManagedObjectContext, PersistentStoreCoordinator를 직접 설정해야 했지만 PersistentContainer의 등장으로 해당 과정이 캡슐화되었다.
ManagedObject를 PersistentStore에 저장하고, 해당 경로를 관리하는 객체는 NSPersistentStoreCoordinator 인스턴스이다.
NSManagedObjectModel : 관리 객체 모델로 .xcdatamodeld 파일을 나타내는 프로그래밍적인 표현입니다.해당 타입의 인스턴스에 접근해 모델을 변경하거나 수정하는 등의 기능을 수행할 수 있다.
NSManagedObjectContext : 관리 객체 컨텍스트로 관리 객체가 존재하는 영역입니다.
Part 1
The system is going to do most of the work so you don't have to.
다양한 폼팩터, 크기가 있고 가로든 세로든 여러 조합에 대해 적응형 앱을 사용자 정의할 수 있다.
다른 기기, 다른 화면 모드에 따라서 앱의 뷰들이 표시되는 방법을 정해줄 수 있다. (wChR..)
약 300가지 이상의 조합이 있음..
하지만 각 300가지 조합을 모두 생각할 필요가 없다! 대응하고자하는 조합에 대해서 사용자 정의 하면된다.
Fundamental trait System
영화진흥위원회, Daum 검색 OPEN API를 이용하여 박스오피스 목록을 조회하고 영화 상세 정보를 확인할 수 있는 앱입니다.
CalendarView에서 목록 조회 날짜를 선택할 수 있습니다.
사용자 선택에 따라 박스오피스 순위 CollectionView를 목록/아이콘의 형태로 볼 수 있습니다.
주요 개념: URLSession, NSCache, UICollectionView, Modern CollectionView Implementation ,UICalendarView, AutoLayout
프로젝트 기간: 2023.04.03 ~ 2023.04.14
⭐️ 팀원
Rowan
Moving or removing another view that was partially obscuring your view
https://s3.ap-northeast-2.amazonaws.com/media.yagom-academy.kr/resources/usr/633bdcb0324ce85b6f34f99e/20230410/6433704f324ce85b6f359d4c.png
Making a previously hidden view visible again by setting its hidden property to NO
Scrolling a view off of the screen and then back onto the screen
코드에 직접 breakpoint를 걸고 확인해본 결과 호출되지 않음.
Explicitly calling the setNeedsDisplay or setNeedsDisplayInRect: method of your view
lldb에서 draw 메서드가 호출되던 이유 🤔
draw 메서드는 trigger가 발생했을 때 일정 조건 아래에서 callback되는 함수입니다. 공식문서 상의 4가지 트리거 중에서 명시적으로 setNeedsDisplay가 호출되는 경우를 제외하면 일반적으로는 호출되지 않습니다.
Q1 : Responder Chain이란 무엇입니까?
발생한 touch event를 처리할 수 있는 responder의 계층 구조
Q2 : Responder Chain과 Gesture Recognizer는 이벤트 제어에서 상호간 상관관계일까요? 별개관계일까요? 그렇게 생각한 이유는 무엇인가요?
Responder Chain과 Gesture Recognizer는 상관관계이다.
Responder Chain은 계층 구조를 따라 이벤트를 처리할 수 있는 responder를 찾는데, 각 responder에 Gesture Recognizer와 같은 이벤트를 처리할 수 있는 방법이 있다면 해당 responder에서 이벤트 처리가 일어나기 때문이다.
Q3 : UIResponder 클래스의 역할은 무엇인가요? 클래스의 설명 An abstract interface for responding to and handling events.이 무엇을 뜻하는지 설명해주세요.
UIResponder - Responder Chain 관리 및 하드웨어의 입력에 따라 이벤트를 처리해주는 객체
API 호출해보기
한국영화진흥위원회의 오픈 API(https://www.kobis.or.kr/kobisopenapi/homepg/main/main.do)를 활용합니다.
Postman 앱(https://www.postman.com)을 통해 영화목록 API를 호출하여 결과를 확인해봅니다 (GET 메서드 활용)
API 문서에 표시된 다양한 매개변수를 적용하여 호출 결과를 확인해봅니다
Postman이 우리를 대신해서 만들어준 URL의 모습은 결과적으로 어떘나요?
http://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.xml?directorNm=봉준호&key=d975f8608af0d9e5a16e79768ca97127
URL에서 매개변수는 어떻게 표현하나요?
스위프트의 옵셔널처럼 기본 요청 URL뒤에 ?를 붙인 뒤 Param의 key = value(string)로 표현하고 연속되는 Param이 있을 경우 &으로 연결하여 나타난다.
Request - HTTP 요청의 핵심요소에 대해서 알아봅시다.
문제점 확인
이번 은행 창구 매니저 console App의 main 파일에서 concurrent DispatchQueue를 통해 async하게 Task를 넘기면 실행되지 않고 종료되는 것을 확인할 수 있었다.
또한, Brody와 실험해본 결과 DispatchGroup의 메서드인 notify도 정상적으로 동작하지 않는 것도 확인했다.
(DispatchGroup.notify(queue: .main)일 경우)
Playground에서와는 전혀 다른 실행 양상을 보이는 이유를 알아보기 위해 Run Loop에 대해 공부해보도록 하자!
Run Loop
Apple 개발자 문서에 RunLoop라는 클래스가 있다!!
Rowan changed 2 years agoView mode Like 1 Bookmark
아래 여러 상황에서 각각의 상황에 맞는 방법을 클래스의 상속과 프로토콜 기본 구현 중 골라서 직접 코드로 구현해보세요.
상황 1 : 야곰 아카데미 구성원 각각의 역할을 표현하고 싶을 때 (ex : 캠퍼, 크루, 리더, 매니저, 서포터, 리뷰어 등 / 멤버의 역할은 디스코드에서 확인할 수 있습니다)
상황 2 : 각종 도형(삼각형, 사각형, 정사각형, 직사각형, 평행사변형 등등)을 타입으로 표현하고 싶을 때
상황 3 : 탈것(자동차, 승용차, 버스, 트럭, 기차, 보트, 비행기, 오토바이, 자전거, 퀵보드 등등)을 표현하고 싶을 때
상황 4 : 포켓몬(피카츄, 라이츄, 파이리, 꼬부기, 또가스, 또도가스, 잉어킹, 갸라도스 등등)을 표현하고 싶을 때
4개 중 3개 선택하여 진행
각각의 상황에서 해당 방식을 택한 이유는 무엇인가요?
ViewGenerator 위치
새로운 뷰를 생성하는 기능을 View가 갖도록 할지, ViewController가 갖도록 할지 고민했습니다.
View를 관리하는 ViewController가 가져야할 기능이라고 판단하여 ViewController에 ViewGenerator 인스턴스를 프로퍼티로 갖도록 변경하였습니다.
이에 따라 CalculateItemScrollView의 didAddSubview 메서드의 위치도 ViewController 메서드 내부로 변경되어 IBAction의 기능을 더 명확하게 파악할 수 있는 코드가 되었다고 생각합니다.
추가적으로, CalculateItemStackView가 다른 View들의 IBOutlet을 알아야 할 필요가 없게 되었습니다! 👍
// before