TECH RAFA
/
All Posts
Search
Share
All Posts
Gallery
List
Search
프로젝트를 진행하면서 WeatherKit을 사용해야될 상황이 와서 Minimum Deployment를 15.0에서 16.0으로 업그레이드 했다. 하지만 iOS Deployment Target도 자동으로 16.0으로 변경될 줄 알았는데 15.0인 것을 발견하였다. 애플은 왜 번거롭게 두 개로 나누어서 버전을 설정하도록 했을까?
iOS Deployment Target
과
Minimum Deployment
의 차이
먼저, 간단하게 두 개념을 정리해보자.
•
iOS Deployment Target
은 앱을 개발할 때
테스트
와
빌드
에서 사용할
최소 iOS 버전
이다. Xcode에서 프로젝트나 각 타겟별로 이 버전을 설정하게 되며 이 설정에 따라 해당 버전 이상의 iOS에서 앱이 실행될 수 있다. 즉, 개발 과정에서 이 버전을 기준으로
앱이 정상 동작하는지 테스트
하게 된다.
•
Minimum Deployment
는 앱이
배포
될 때 실제로
최소 요구되는 iOS 버전
을 정의하는 설정이다. 이 값은 앱이 앱 스토어에 올라가면 그 버전 이상의 iOS 기기에서만 앱을 다운로드하고 실행할 수 있도록 하는 제한을 걸어준다. 보통 이 값은
Info.plist
나 프로젝트 설정 파일에 기록된다.
왜 두 개로 나누었을까?
iOS Deployment Target을 따로 설정함으로써 개발자가 더 낮은 iOS 버전을 지원하는 코드 작성과 테스트가 가능하다. 예를 들어, 앱이 새로운 기능을 위해 iOS 16.0을 필요로 하더라도
iOS 15.0에서의 호환성을 유지하고 싶은 상황
이 있을 수 있다. 이때, Xcode에서는 iOS 15.0에서도 정상적으로 빌드가 되게끔 처리하면서 실제 배포 시에는 16.0 이상의 버전만 지원하도록 제어할 수 있다.
이렇게 하면 새로운 API나 기능을 도입하면서도 기존의 더 낮은 iOS 버전을 지원하는 코드를 유지하거나
조건부 코드
(
if #available(iOS 16.0, *)
)를 추가하여 iOS 버전별로 동작을 다르게 구현할 수 있다.
프로젝트 안에 여러
타겟(Target)
이 있을 수 있다. 예를 들어, 동일한 코드베이스에서
일반 사용자용 앱
과
테스트용 앱
을 따로 빌드할 때 각각의 타겟에 따라 지원하는
최소 iOS 버전
이 다를 수 있다.
이때, 각 타겟마다
iOS Deployment Target
을 따로 설정하여
타겟별 맞춤 설정
이 가능하게 만들 수 있는 것이다. 즉, 타겟마다 테스트 환경이나 지원 버전을 다르게 설정할 수 있어 유연성을 극대화할 수 있다.
iOS Deployment Target vs Minimum Deployment
TIL
Xcode
Git에서 파일 크기 제한으로 인해
fatal: the remote end hung up unexpectedly
오류가 발생한 문제를 해결한 방법을 정리해보았습니다.
문제 상황
git push
를 실행했을 때,
fatal: the remote end hung up unexpectedly
오류가 발생했습니다. 이는 원격 저장소에서 허용하는 최대 파일 크기 또는 전체 push 크기 제한을 초과했기 때문에 발생한 오류였습니다.
해결 방법
이 문제를 해결하기 위해 Git의
http.postBuffer
설정을 변경하여 push 데이터를 압축하고 크기를 줄였습니다. 이 설정은 Git이 HTTP 프로토콜을 통해 데이터를 push할 때 사용하는 버퍼 크기를 조정해줍니다.
위 명령어를 실행하면 버퍼 크기가 500MB로 설정되어 push할 수 있는 데이터의 크기가 늘어나게 됩니다.
이 설정을 적용한 후, 다시
git push
를 시도했을 때 오류 없이 성공적으로 원격 저장소에 데이터를 push할 수 있었습니다.
교훈
Git에서 대형 파일을 push할 때는 파일 크기 제한을 염두에 두고, 필요시
http.postBuffer
설정을 조정하여 문제를 해결할 수 있다는 점을 배웠습니다. 또한, 대형 파일을 자주 관리해야 한다면
Git LFS
와 같은 도구를 사용하는 것이 장기적으로 더 좋은 방법일 수 있습니다.
Git Push 시 파일 크기 제한 초과 오류 해결하기
TIL
Error
Git
Just
just
연산자는 단일 요소를 방출한 다음 완료되는
Observable
을 생성한다. 매우 간단하고 직관적인 방식으로 단일 값을 Observable로 변환할 수 있게 해준다.
출력 결과
장점
•
단일 요소를 방출하기에 매우 간단한 연산자임. 이를 통해 특정 값 하나를 방출해야 할 때 직관적으로 사용할 수 있음.
•
단일 값을 방출하고 완료한다는 명확한 목적을 가지고 있기 때문에 코드를 읽기 쉬움.
•
항상 동일한 값과 동일한 순서로 동작하기 때문에 예측 가능성이 높아 테스트와 디버깅에 용이함.
단점
•
단일 값만 방출할 수 있기 때문에 여러 값을 방출해야 하는 경우에는 다른 연산자를 사용해야 함.
•
고정된 값만 방출할 수 있기 때문에 동적 데이터나 조건에 따른 데이터 방출에는 적합하지 않음.
Of
of
연산자는 여러 개의 요소를 순차적으로 방출하는 연산자이다. 주로 짧은 시퀀스를 테스트하거나 특정 값들을 한 번에 방출해야 할 때 유용하다.
RxSwift Operators #1: Creating Operators
TIL
RxSwift
Subjects
Subjects는 Observable이자 Observer 역할을 한다. 따라서 Subject는 데이터를 방출(emit)하고 다른 Observable에서 데이터 이벤트를 받아들일 수 있다. RxSwift에서 제공하는 주요 Subject는 다음과 같다.
1.
Publish Subject
2.
Behavior Subject
3.
Replay Subject
4.
Async Subject
Relays
Relays는 RxCocoa에 포함되어 있으며 기본적으로 Subjects와 비슷하게 동작하지만 onCompleted나 onError 이벤트를 방출하지 않는다.
Publish Subject
Publish Subject는 새로운 구독자가 기존에 발행된 이벤트를 받을 수 없고 구독한 시점 이후의 이벤트만 받을 수 있다.
출력 결과
Publish Subject는 구독 시점 이후의 이벤트만 구독자에게 전달한다. 따라서 “Hello” 이벤트는 구독자가 없어서 아무도 받지 못했다. “World” 이벤트는 첫 번째 구독자가 수신했고 두 번째 구독자는 “World” 이벤트 이후에 구독했기 때문에 “RxSwift” 이벤트만 수신했으며 “RxSwift” 이벤트는 모든 구독자가 수신했다.
장점
Subject와 Relay
TIL
RxSwift
Decodable과 Encodable
Swift에서 데이터를 쉽게 처리할 수 있도록
Decodable
과
Encodable
프로토콜이 제공됩니다. 이 두 프로토콜은 외부 데이터 형식과 Swift 데이터 타입 간의 변환을 단순화하며
Codable
은 이 두 프로토콜을 모두 포함하는 타입 별칭입니다. 이번 글에서는
Decodable
과
Encodable
의 개념을 설명하고 왜 Codable을 사용하지 않고
Decodable
을 사용했는지에 대해 예제 코드와 함께 살펴보겠습니다.
Decodable
JSON, XML 또는 다른 데이터 형식에서
Swift 타입으로 데이터를 변환하는 데 사용
됩니다. 데이터를 받아와서 내부 모델로 변환하는 작업에서 활용됩니다.
예를 들어, 유튜브를 사용할 때 수많은 비디오 데이터를 서버로부터 불러와야 합니다. 유튜브 서버는 비디오 제목, 설명, 조회수 등의 정보를 JSON 형식으로 앱에 보냅니다. 이때, 앱은 이 JSON 데이터를 받아 내부에서 사용할 수 있는 데이터 모델로 변환해야 합니다. 이 과정에서
Decodable
프로토콜이 사용됩니다.
Encodable
Swift 타입을 JSON이나 XML 등의
외부 데이터 형식으로 변환하는 데 사용
됩니다. 데이터를 외부에 전송하기 전에 필요한 형식으로 만드는 작업에서 활용됩니다.
예를 들어, 메모 앱에서 사용자가 메모를 작성하면 이 메모 데이터를 JSON 형식으로 인코딩하여 서버에 전송해야 합니다. 이 과정에서
Encodable
프로토콜이 사용됩니다.
Codable은 언제 사용하나요?
Codable은 Decodable과 Encodable을 모두 합친 타입 별칭으로, 한 데이터 모델에 대해 동시에 디코딩과 인코딩을 모두 수행해야 할 때 사용됩니다. 그래서 디코딩만 필요하거나 인코딩만 필요한 경우에는 굳이 사용할 필요가 없습니다. 만약 디코딩 또는 인코딩만 필요한데 Codable을 사용한다면 코드의 목적을 저해시키고 코드의 가독성이 떨어지게 됩니다. 예를 들어, 설정 앱에서 설정을 변경하고 이를 서버에서 저장해야 할 때 사용됩니다.
따라서 이번 프로젝트에서 GitHub Api로부터 저장소를 불러오는 기능만 들어갔기 때문에 Decodable을 사용하였고 MVVM 패턴을 적용하였습니다. 모델 코드부터 보도록 하겠습니다.
Model
깃허브 앱 만들기(with. RxSwift)
RxSwift
CodingKey
MVVM
Swift에서 API로부터 JSON 데이터를 받아와 앱 내에서 사용하기 위해 우리는 종종
Decodable
프로토콜을 구현하는 모델을 정의한다. 오늘은
Decodable
구현 시에 매우 유용한
CodingKeys
열거형에 대해 자세히 알아보고자 한다.
CodingKey란?
CodingKey
는
Decodable
또는
Encodable
프로토콜을 사용할 때 JSON 키와 Swift 모델의 프로퍼티가 서로 일치하지 않을 경우 이를 연결하기 위해 사용하는 열거형이다. 예를 들어, 서버로부터 받은 JSON 데이터 내에는
stargazers_count
라는 키가 있지만 Swift 코드 내에서는
stargazersCount
라는 프로퍼티로 사용하고 싶은 경우가 이에 해당한다.
사용 예시
Repository
라는 구조체를 정의하고 이를
Decodable
프로토콜에 따라 구현해보자. 이 구조체는 GitHub의 리포지토리 정보를 담고 있으며 다음과 같이 구성된다.
여기서
CodingKeys
열거형은 JSON 키 값인
stargazers_count
를 Swift 모델의
stargazersCount
프로퍼티에 할당하도록 명시한다. 이런 방식은 데이터의 키와 프로퍼티 이름이 다를 때 유용하게 사용된다.
CodingKey 사용의 이점
•
명확성
•
유지보수성
•
타입 안정성
데이터와 모델 간의 연결이 명확해지므로 다른 개발자가 코드를 볼 때 이해하기 쉬우며 모델의 프로퍼티 이름이나 JSON 키가 변경되어도 쉽게 대응할 수 있다. 또, 컴파일 시점에 프로퍼티 매핑 오류를 발견할 수 있어 런타임 에러의 가능성을 줄여준다.
결론
Swift에서 JSON 키와 모델 프로퍼티 매핑하기 - CodingKey
TIL
CodingKey
부산에서 iMac으로 코딩할 수 있는 무료 강좌 이벤트가 개설되어 바로 부울경 iOS 단톡방에 공유했다 ㅋㅋ
그리고 레벨 1과 레벨 2가 있었는데 레벨 1은 기초적인 내용으로 초보자도 쉽게 들을 수 있는 레벨이었고 레벨 2는 배운 내용들을 토대로 나만의 명함을 만들 수 있다. 나는 둘 다 할 수 있다고 해서 모두 참여하기로 했다. 난이도가 굉장히 쉬워보였지만 참가하는 첫 번째 이유는 그곳에서 많은 사람들과 친해지고 싶었고 이야기를 나누고 싶어서이다. 두 번째는 나도 언젠간 부산, 울산, 경남권 지역에서 iOS 개발 커뮤니티를 크게 키우고 싶고 이런 교육이나 컨퍼런스도 주최해보고 싶기 때문이다. 세 번째 이유는 iMac을 사용해보고 싶었다 ^^
도착!! 앨리스랩에서 장소를 후원 받았다고 한다. 내부는 굉장히 깔끔했고 입구 오른쪽이 프로그래밍존이다. 오거나이저분이 왼쪽 광장 같은 곳에서 잠깐 대기하라고 하셨다.
빨리 들어가고 싶어요.. 기다리면서 리이오도 봤다. 인터넷 강의에서만 보던 분을 실제로 보니 신기했다. 10분 정도 기다리니 입장하라는 안내와 함께 짐을 챙겨 입장했고 가장 앞자리에 어떤 분 옆에 바로 착석했다:)
옆에 분과 간단히 인사를 나누고 어디서 왔는지, 대학생인지 등등 이것저것 물어봤다. 이 분은 수원에서 오셨고 입사한지 6개월된 신입이라고 하셨다. 그렇게 레벨 1 섹션이 시작되고 Playground에 있는 바이트라는 캐릭터를 이용해서 간단한 코딩하는 시간을 가졌다. 코드를 짜는데 옆에 분은 너무 쉬웠는지 금방금방 하셨고 조금 더 나아가 더욱 고도화된 코드를 작성하고 계셨다. 이 분도 나와 같이 네트워킹 목적으로 오신 것 같았다. 레벨 1이 끝나고 쉬는 시간을 가진 뒤 레벨 2가 시작되었다. 레벨 2는 레벨 1에 비해 더 난이도가 있었고 여기저기서 질문하는 소리가 들리기 시작했다. 그래도 코딩을 어느정도 한 경험이 있다면 쉽게 풀 수 있는 난이도였다. 모든 강좌가 끝나고 명함 만드는 시간이 찾아왔다. 나는 나의 강아지 사진을 프로필 사진으로 설정하였고 백그라운드 색은 인스타그램 느낌이 나도록 그라데이션 효과를 넣었다. 아래는 결과물이다.
코드를 작성하면서 가장 먼저 느낀 점은 iMac 정말 이쁘고 화질도 좋았다 ㅋㅋㅋ(선 뽑아서 집에 들고 가고 싶었다ㅎ) 그리고 텍스트를 커스텀하면서 중복되는 코드가 많았는데 UIKit처럼 함수로 만들어 코드의 중복을 줄이고 싶었지만 아직 SwiftUI를 잘 알지 못해 에러가 계속 떴다. 옆 분에게 물어보니 리턴 타입으로 some View를 작성하니 문제가 해결되었다. 나는 그 자리에서 바로 박수쳐주니 굉장히 쑥스러워 하셨다 ㅋㅋㅋㅋ 프로그래밍존을 벗어나 입구 왼쪽에 있는 광장? 같은 곳에서 자리를 잡고 네트워킹 시간을 가졌다. 다양한 지역에서도 오셨고 다양한 분야의 개발자들도 모인 자리였다. 시간 가는 줄도 모르고 즐겁게 이야기를 나눴고 서로 명함도 교환했는데 다들 잘 만드셨다. 아쉬운 점은 명함이 3장뿐이어서 모든 분들께 나누지 못해 아쉬웠다. 마지막으로 단체 사진을 찍고 그곳에서 만난 사람들과 함께 지하철역으로 이동했다. 교통카드를 찍으려는 순간 어떤 분께서 시간 괜찮으면 저녁 같이 먹자고 해서 바로 옆에 있는 신세계 백화점으로 향했다.
파스타, 피자, 샐러드, 스테이크를 시켰는데 스테이크가 너무 맛있었다. 밥을 먹으며 개발 이야기를 끊임없이 나눴고 내 옆 자리에 앉았던 분도 오셨는데 자신이 한 프로젝트를 소개해주었다. 대학교 셔틀버스가 언제 오는지 알려주는 프로그램을 만들었는데 엄청 잘 만들었고 지금도 정류장 뒤에 운영 중이다! 보면서 한국은 땅은 좁은데 천재들은 많다는 것을 느낄 수 있었다.
‘iMac으로 코딩 첫 걸음’ 회고
Retrospect
기본 설정 및 UISearchController 구성
•
searchResultsUpdater 프로퍼티를 현재 클래스(self)로 설정하여 사용자가 검색 바에 입력할 때마다 결과 업데이트
•
검색 중에 배경을 흐리게 하지 않음
•
내비게이션 바를 숨기지 않음
•
자동 대문자 비활성화
•
자동 수정 비활성화
•
맞춤법 검사 비활성화
검색 모드
이 계산 속성은 사용자가 검색 중인지 아닌지를 파악하여 해당 상태에 따라 테이블 뷰에 표시될 데이터를 결정한다.
inSearchMode가 true일 때 사용자는 검색을 활성화하고 검색어를 한 글자 이상 입력한 상태이다. 이 경우, SearchController는 filteredUsers 배열을 사용하여 테이블 뷰를 채운다. 이 배열에는 사용자의 검색 조건에 부합하는 사용자 데이터만 포함되어 있다.
사용 이유
이 속성을 사용하는 이유는 사용자가 어떻게 데이터를 보고 싶어하는지, 즉 전체 목록을 보고 싶은지 아니면 특정 조건을 만족하는 항목만 보고 싶은지를 파악하기 위함이다. 이를 통해 앱은 사용자 경험을 개선하고 필요한 정보만을 효율적으로 제공할 수 있다.
isSearchMode를 활용한 동적 테이블 뷰 데이터 처리
검색 및 필터링 기능 구현하기
TIL
UISearchController
filtering
MVVM
Firestore를 통한 비동기적 사용자 데이터 로딩
Firestore 데이터베이스에서 사용자 데이터를 비동기적으로 가져오는 역할을 한다. 이 메서드는 완료 핸들러를 파라미터로 받아 데이터베이스에서 데이터를 성공적으로 로드한 후 필요한 동작을 실행할 수 있게 해준다.
•
타입 메서드(static)로 정의함으로써 UserService의 인스턴스를 생성하지 않고도 호출할 수 있다.
•
COLLECTION_USERS.getDocuments
는 Firestore에서 ‘users’ 컬렉션의 모든 문서를 가져오는 비동기적으로 가져온다.
•
guard let
구문을 사용하여 snapshot 객체가
nil
인 경우 함수를 더 이상 진행하지 않고 종료한다. 이는 데이터가 없거나 조회에 실패했을 때의 안전한 처리를 위함이다.
•
snapshot.documents.map
을 사용하여 각 문서를 User 모델 객체로 변환한다. 여기서
User(dictionary: $0.data())
는 Firestore 문서의 데이터를 이용하여
User
객체를 초기화한다.
•
completion(users)
는 변환된 사용자 배열을 완료 핸들러를 통해 반환한다. 이를 통해 함수를 호출한 곳에서 사용자 데이터를 사용할 수 있게 된다.
다음 코드는 UserService를 통해 사용자 데이터를 가져오고 UI를 업데이트한다.
fetchUsers 메서드는 UserService를 통해 사용자 데이터를 비동기적으로 가져온다. 이 과정에서 몇 가지 주요 단계를 거친다.
•
데이터 로딩 시작: fetchUsers는 네트워크를 통해 사용자 데이터를 요청한다. 이때 users 배열은 초기 상태에서 빈 배열로 시작된다.
•
데이터 로딩 완료: 비동기적으로 데이터가 로딩 완료되면 이 데이터는 users 배열에 저장된다. 배열은 비어 있던 상태에서 새로운 사용자 정보로 채워진다.
•
UI 업데이트: 데이터가 users 배열에 성공적으로 저장되면 reloadData를 통해 UI를 최신 상태로 갱신해야 한다.
사용자 데이터 처리 및 표시 방법
TIL
@escaping
UITableView
MVVM
delegate는 다른 클래스에 특정 이벤트가 발생했을 때 알리기 위해 사용된다. 예를 들어, LoginController와 RegistrationController 클래스에서 사용자 인증 관련 이벤트를 처리한 후, 이를 앱의 다른 부분에 알리는 데 delegate가 사용된다.
weak 키워드는 객체를 참조할 때 참조 카운트를 증가시키지 않아 강한 순환 참조를 방지하는 데 유용하다. 강한 순환 참조란 두 객체가 서로를 강하게 참조하면서 서로가 메모리에서 해제되지 못하는 문제를 발생시키는 것이다. 따라서 weak로 선언된 delegate는 더 이상 필요하지 않을 때 자동으로 nil이 되어 메모리 누수를 방지할 수 있는 것이다.
1.
신규 회원 등록 화면 전환
회원가입 버튼을 눌러 RegistrationController로 이동할 때 두 컨트롤러는 같은 delegate 객체를 사용하게 되어 회원가입 완료와 로그인 성공와 같은 인증 관련 이벤트를 같은 delegate를 통해 관리할 수 있게 된다. 예를 들어, 어느 한 컨트롤러에서 사용자 인증이 완료되면 설정된 delegate를 통해 앱의 다른 부분에게 이를 알리고 필요한 조치를 취할 수 있다. 이렇게 delegate가 공유되면 코드의 중복을 줄이고 유연성을 제공하며 각 컨트롤러의 관리를 더욱 효율적으로 할 수 있다.
2.
인증 완료 알림
위 메서드에서 사용자가 성공적으로 로그인을 마친 경우, authenticationDidComplete 메서드를 호출한다. 이는 delegate를 통해 다른 컨트롤러에게 인증이 완료되었다는 것을 알린다. 예를 들어, 다음 코드와 같이 메서드를 통해 사용자를 앱의 메인 화면으로 이동시키는 등의 동작을 할 수 있다.
로그인이나 회원가입 등의 인증 과정이 성공적으로 마무리되면 authenticationDidComplete 메서드가 호출된다.
•
이 메서드 내에서 첫 번째로 실행되는 것은 fetchUser 함수를 호출하는 것이다. 이 함수는 서버나 데이터베이스로부터 최신의 사용자 데이터를 불러오는 역할을 수행한다.
•
사용자 정보를 갱신한 후, dismiss를 통해 현재 표시된 로그인 창을 닫고 메인 인터페이스로 돌아간다.
delegate의 역할과 중요성
TIL
delegate
MVVM
1.
FormViewModel 프로토콜
UI 요소가 데이터 변화에 맞춰 어떻게 갱신될지 정의한다. 예를 들어, 다음과 같이 사용 가능하다.
로그인 버튼의 활성화 상태나 배경 색상을 사용자가 입력한 데이터의 유효성에 따라 업데이트할 때 사용하다.
2.
AuthenticationViewModel 프로토콜
인증 관련 뷰 모델의 기본 구조를 정의한다. 이 프로토콜은 로그인이나 회원가입 폼의 유효성을 판단하고 버튼의 배경 색상과 텍스트 색상을 결정하기 위한 속성을 포함한다.
LoginViewModel은 이메일과 비밀번호의 입력 여부에 따라 폼의 유효성을 판단하고 해당 유효성 결과에 따라 버튼의 색상을 변경한다.
3.
AuthenticationDelegate 프로토콜
이 프로토콜을 통해 인증 과정이 성공적으로 끝난 후에 어떤 동작을 할지를 결정할 수 있다. 예를 들어, 사용자가 로그인 버튼을 누르고 인증이 성공적으로 완료되면 authenticationDidComplete 메서드에가 호출되어 앱에서는 해당 사용자를 메인 화면으로 이동시킬 수 있다.
프로토콜의 역할 이해하기
TIL
protocol
MVVM
오늘은 앞으로 시작할 프로젝트를 위해 미리 탭 바와 다크 모드만 간단하게 구현해 봤다. 그동안 MVC 패턴만 사용해 왔지만 최근에 MVVM 패턴을 공부하면서 프로젝트가 커질수록 View의 코드가 너무 복잡해지고 무거워지는 것을 느꼈다. 이에 MVC 패턴처럼 View를 다시 View와 Controller로 나누어
MVC with VM
아키텍처 패턴을 시도해 봤다. 인터넷에서 이 아키텍처 패턴에 관한 글을 찾을 수 없었지만 어쩌면 많은 사람들이 이미 이 패턴을 생각했을지도 모른다. 아마 그럴만한 이유가 있어서 채택되지 않았겠지만 내 성격상 직접 부딪쳐보지 않고서는 알 수 없고 이 과정에서 또 새로운 무언가를 발견하고 탄생시킬지도 모른다고 생각한다. 그리고 아직 아키텍처 패턴에 익숙하지 않은 나에겐 좋은 공부법이 될 거라고 생각한다. 또, UserInterfaceStyle을 토글 버튼으로 제어하고 UserDefaults를 활용하여 앱을 재시작해도 설정값과 버튼 상태가 유지되도록 구현하는 방법에 대해 공부했다.
Model
앱의 다크 모드 활성화 여부를 저장하고 불러오는 역할을 담당한다.
get
절에서는
UserDefaults.standard.bool(forKey: "DarkModeEnabled")
를 호출하는 것을 볼 수 있다. 이는
DarkModeEnabled
라는 키를 사용하여 다크 모드가 활성화 되어 있는지의 여부를 Bool 값으로 불러온다. 만약, 해당 키에 대한 값이 설정되어 있지 않으면
false
를 반환하는 코드이다.
set
절에서는
UserDefaults.standard.set(newValue, forKey: "DarkModeEnabled")
를 호출하는데 이는
newValue
로 전달된 값을
DarkModeEnabled
키에 연결하여
UserDefaults
에 저장한다. 이 값은 앱을 종료하고 다시 시작해도 유지된다.
View
코드의 간결성을 위해 CocoaPods을 통해 SnapKit을 들고왔다.
UISwitch()
클래스로 스위치 버튼을 쉽게 만들 수 있었다. View 코드는 딱히 볼게 없으니 패스.
ViewModel
Properties: 다크 모드의 활성화 상태를 관리하는 모델 인스턴스를 설정하고 이 모델 인스턴스의
isDarkModeEnabled
값을 가져와
isDarkModeEnabled
라는 변수에 저장한다. Initialization: ViewModel을 초기화할 때 모델의 인스턴스를 내부 속성으로 설정한다. Actions: 사용자가 다크 모드 버튼을 토글할 때
toggleDarkMode
메서드가 호출된다.
isDarkModeEnabled
속성 값을 토글하고
updateInterfaceStyle
메서드를 호출하여 UI 스타일을 업데이트한다. Helpers:
updateInterfaceStyle
메서드는 연결된 모든 뷰의 UI 스타일을 현재 모드 설정에 맞게 압데이트한다. 그리고 애니메이션 적용 여부는 매개변수를 통해 결정할 수 있도록 했다.
이렇게 뷰 모델은 모델과 뷰 사이에서 데이터를 관리하고 전달하는 역할을 해준다.
Controller
마지막으로 이 코드는 사용자의 다크 모드 설정을 실시간으로 반영하여 앱의 모든 뷰에 적용하여 보여준다. 애니메이션을 통해 부드러운 전환을 제공하여 사용자 경험을 개선시켰다. 그리고 Controller와 View를 분리함으로써 프로퍼티가 가벼워져 코드가 더 깔끔해 보인다.
다크 모드 토글 버튼 + MVCVM 패턴?
TIL
overrideUserInterfaceStyle
MVCVM
애플 공식 문서 보면서 공부하는 SwiftUI 2편
SwiftUI
오늘은 메모리 구조에 대해 비전공자도 이해할 수 있게 정리하고자 합니다! 바로 가보시죠.
메모리 구조의 이해
먼저, 메모리에 대해서 알고 계신가요? 메모리는 사람의 뇌처럼 어떠한 정보를 저장하고 관리하는 곳이죠. 메모리의 구조로 4 종류가 있어요.
코드(Code) - 데이터(Data) - 힙(Heap) - 스택(Stack)
으로 구성되어 있죠. 먼저, 코드 영역부터 보겠습니다.
코드 영역
코드 영역은 컴퓨터가 실행할 코드를 저장하는 곳이에요. 이를 쉽게 이해하려면 여러 레시피들을 모아둔 레시피 책과 같아요. 코드는 레시피가 되겠죠. 레시피 책에는 다양한 요리법이 적혀 있듯이 코드 영역에는 프로그램이 실행할 작업들이 명령어로 적혀 있어요.
프로그램이 실행될 때 컴퓨터는 이 코드 영역에 있는 명령어들을 차례로 읽고 실행해요. 여기서 중요한 것은 이 명령어들이 얼마나 효율적으로 작성되었느냐예요. 효율적인 명령어란, 컴퓨터가 더 적은 자원(시간, 메모리 등)을 사용하여 더 빠르고 정확하게 작업을 할 수 있는 코드를 말해요.
이 과정에서 컴파일러의 역할도 중요하죠. 컴파일러는 프로그래머가 작성한 코드를 컴퓨터가 이해할 수 있는 기계어 코드로 변환해요. 이 과정에서 컴파일러는 코드를 최적화하여 프로그램이 더 효율적으로 실행될 수 있도록 도와줘요.
요약하자면, 코드 영역은 프로그램이 실행될 때 필요한 명령어들이 저장되는 곳으로 이 명령어들의 효율성과 컴파일러의 최적화 작업이 프로그램의 실행 속도와 성능에 중요한 영향을 미친답니다.
데이터 영역
데이터 영역은 전역 및 정적 변수를 안정적으로 저장하고 관리하는 영역이에요. 예를 들어, 프로그램을 전기를 공급하는 콘센트로 비유를 하자면 전역 변수와 정적 변수는 전기를 공급 받는 물체가 될 수 있겠죠. 전기를 공급 받는 동시에 작동하고 전기가 끊기면 그들은 작동하지 않죠. 즉, 데이터 영역은 프로그램을 실행하는 동시에 각각의 변수들이 메모리에 할당되고 종료되면 함께 소멸됩니다.
힙 영역
힙 영역은 프로그램이 실행되는 동안 메모리를 동적으로 할당하는 영역이에요. **'동적 할당'**이란, 프로그램이 실행되는 도중에 필요한 메모리의 양을 결정하고 할당하는 것을 의미해요. 이는 프로그램이 컴파일될 때 메모리의 크기가 결정되는 스택 영역과는 대비되죠?
예를 들어볼게요. 사용자가 입력한 데이터의 크기에 따라 메모리가 필요할 경우나 프로그램이 실행되는 동안 생성되는 데이터가 불규칙적이거나 크기를 예측하기 어려운 경우 힙 영역이 사용돼요. 즉, 사용자가 몇 개의 데이터를 입력할지 모르는 상황에서는 힙 영역에 메모리를 할당하여 그 데이터를 저장할 수 있어요.
또한, 힙 영역은 관리가 중요해요. 메모리가 더 이상 필요하지 않게 되었을 때 적절하게 해제하지 않으면 메모리 누수가 발생할 수 있어요. 이는 원자력 발전소에서 안전 관리가 중요하듯 프로그램에서도 메모리 관리가 매우 중요하다는 것을 의미해요.
메모리 구조
Computer Science
예전부터 공식 문서를 보면서 공부해보고 싶은 생각이 많았는데요. 막상 공식 문서에 들어가면 영어로 빼곡히 적혀 있어 거부감이 들었어요..그래도 저의 로망이자 목표는 외국에서 일해보는 것입니다..!ㅋㅋㅋ미라클은 하기 싫은 데에서 일어난다는 말이 있죠. 그래서 이제부터라도 영어 글을 읽는 것에 익숙해지기 위해서 SwiftUI는 공식 문서로 공부해보기로 결심했어요. 또, 최근에 외국인과 SwiftUI 스터디를 시작했는데 기본적으로 영어를 사용해서 제가 설명하고 싶은 부분이 있어도 설명이 안되니 정말 답답하더군요. 개발은 커뮤니케이션이 중요한 만큼 영어를 공부해야겠다고 결심했습니다..
1편은
SwiftUI 튜토리얼
에 있는 섹션 1부터 섹션 6까지 다룰 거예요. 누구나 이해할 수 있도록 최대한 쉽게 풀어서 정리하고자 합니다! 혹시나 틀린 부분이 있다면 따끔하게 지적부탁드려요!(지적 대환영
)
목차
1.
🐣 SwiftUI 생성 방법 및 코드 구조
2.
3.
4.
5.
6.
7.
SwiftUI 생성 방법 및 코드 구조
애플 공식 문서 보면서 공부하는 SwiftUI 1편
SwiftUI
팀 프로젝트 회고록
잘한 점
프론트엔드팀은 체계적으로 일관된 작업 방식을 구축하는 데 중점을 두었다. 가장 먼저, Swift 코드 컨벤션을 정해서 코드의 가독성과 유지 보수성을 향상시킨 것이다. 이를 통해 코드 리뷰 과정이 수월했다.
또한, 깃 커밋 컨벤션을 통일함으로써 프로젝트의 변경 사항을 추적하고 이해하는 데 큰 도움이 되었다.
더 나아가 PR 템플릿을 생성한 것도 중요한 성과였다. 이 템플릿 덕분에 팀원들이 수행한 작업을 더욱 명확하고 체계적으로 기술할 수 있었고 리뷰어가 PR을 더 빠르고 정확하게 평가할 수 있었다. 템플릿에는 PR 유형(기능 추가, 기능 삭제, UI 변경 등등), 작업 사항, 이슈 번호가 있었는데 이는 팀 내 커뮤니케이션의 효율성을 높이는 데 큰 도움이 되었다.
의사소통의 중요성
프로젝트 진행 중, 우리는 의사소통의 중요성을 절실히 깨닫게 된 사건을 경험하였다. 내가 생각했던 것보다 훨씬 더 많은 의사소통이 필요하다는 것을 이번 프로젝트를 진행하면서 깨달았다.
기획자, 디자이너, 개발자 간의 의사소통이 충분히 이루어지지 않은 상태로 나는 일주일 동안 메인 화면 UI를 완성시켰지만 일주일 간의 작업이 잘못된 방향으로 진행되었다. 이로 인해 거의 모든 UI를 처음부터 다시 해야 하는 상황에 놓였고 하늘이 무너지는 것 같았다..
우리는 긴급 회의를 가졌다. 각자의 입장을 허심탄회하게 나누고 문제의 근본 원인을 파악하는 데 집중했다. 문제점은 구현해야될 UI에 대한 요구사항을 명확하게 소통하지 않은 것이 결국 서로 간의 큰 오해와 실수로 이어졌던 것이었다.
이 문제를 해결하기 위해 우리는 몇 가지 해결책을 마련하였다. 첫 째, 이전에는 큰 단위의 변화에 대해서만 정기적으로 보고를 했다면 이번에는 작은 단위의 변화에 대해서도 지속적인 보고하여 진행 상황을 바로바로 점검하는 것이다. 둘 째, 피그마 디자인을 더 꼼꼼히 점검하여 이해되지 않는 부분이나 구현하기 힘들 것 같은 부분은 즉시 질문하기로 약속하였다.
그 결과, 프로젝트의 전반적인 의사소통이 크게 개선된 것을 느꼈고 빠른 피드백과 수정 작업을 통해 개발 속도가 크게 증가되었고 더 나은 결과물을 만들어냈다고 생각된다. 그리고 팀원들 사이의 신뢰도와 협력도가 강화되었다.
이 경험을 통해 의사소통의 중요성은 팀워크와 결과물에 큰 영향을 끼친다는 것을 깨달았고 그 가치의 깊이를 다시 한 번 이해하게 되었다. 앞으로는 프로젝트 초기부터 명확한 의사소통을 확립하고 정기적인 점검을 통해 이러한 문제를 예방할 것이다.
성장과 도전
나는 MVC 패턴은 처음엔 낯설고 복잡하게만 느껴졌었다. 하지만 이번 프로젝트를 통해 MVC 패턴에 대해 확실하게 감을 잡을 수 있는 발판이 되었다.
첫 번째 팀 프로젝트 회고록
Retrospect
인상 깊은 글귀
일상의 반복과 사회적 문법
옷 사면 사람 만나야 하고, 사람 만나면 술 마셔야 되고, 술 마시면 실수하고, 실수하면 후회하게 되리란 걸 알았지만. 그런 패턴조차 내가 사회적인 문법에서 크게 벗어나지 않은 삶을 살고 있다는 안도감을 주었다. [ p. 10, ll. 10 - 13 ]
나의 생각
인생의 반복되는 패턴들이 우리에게 어떤 의미를 가질 수 있는지를 생생하게 보여준다. 일상의 소소한 순간들이 겹쳐져 하나의 큰 삶의 리듬을 만드는 것이다. 옷을 사고, 사람들을 만나며, 때로는 술을 마시고 실수를 하는 것은 평범해 보일 수 있지만 사실은 우리 각자의 삶에서 중요한 부분을 차지하고 있다.
특히 이 문장에서
'사회적인 문법'
이라는 표현은 너무나도 공감이 간다. 우리 모두 일정한 패턴이나 규칙 속에서 살아가고 있는 것이다. 가끔은 이런 일상의 반복이 지루하고 무의미하게 느껴질 수도 있지만 이 문장은
그 반복 속에서도 안정감과 소속감을 찾을 수 있다는 것
을 상기시켜 준다. 마치 우리가 어느 정도 예측 가능한 세상 속에서 살고 있다는 것, 그리고 그 안에서 자신의 자리를 찾고 있다는 것에 대한 위안을 주는 것 같다.
이런 패턴들이
우리 삶의 일부임을 인정하는 건 자기 자신과 사회에 대해 더 깊이 이해하고 받아들이는 과정
이다. 그래서 이 글이 인상 깊었던 거 같다. 우리 모두가 누군가의 삶 속에서 작은 역할을 하고 있고
그 자체로 의미가 있다
는 걸 느끼게 해주니까.
소박한 것에서 의미 찾기
나는 황토색 인조가죽 가방을 가리키며 투덜댔다. 당시 내게 하나밖에 없던 가방이라 아무 옷에나 줄기차제 들고 다닌 거였다. "난 저 가방 때문에 이 사진이 좋은데." 선배가 모니터를 응시하며 말했다. "에? 왜요?" 선배가 나지막하게 중얼거렸다. "이 여자의 '생활'이 보여서." [ pp. 23-24, l. 19 - p. 24, l. 4 ]
나의 생각
선배가 그 가방을 보고
"이 여자의 '생활'이 보여서."
라고 말한 부분이 인상 깊다. 선배는 그저 황토색 가방 하나를 봤을 뿐인데 그 안에 숨겨진 미영의 일상과 감정을 읽어냈다. 이 말은 단순히 가방이 아니라, 우리가 어떻게 작은 것들을 통해 서로를 이해하고 그 안에서 뜻깊은 연결을 찾을 수 있는지 보여준다. 마치 친구와 오랜 추억을 공유하듯, 그
소박함 속에 깊은 의미
가 숨겨져 있는 것 같다.
절실한 바람과 그것을 이룰 수 없는 아픔
[비행운] 너의 여름은 어떠니
Book
헌혈 앱(기간: 1일)
Project
Codebase
CocoaPods
MVC
SnapKit
Then
GitHub - UMC-HowsTheWear/HowsTheWear-iOS at develop
Contribute to UMC-HowsTheWear/HowsTheWear-iOS development by creating an account on GitHub.
온도에 맞춰서 추천 아이템 실시간으로 변경
About
•
사용자 위치의 날씨 데이터에 따른 실시간 옷 추천 + 다양한 패션 정보 제공
•
CoreLocation과 WeatherKit 사용
사용된 오픈소스라이브러리
•
SnapKit
•
Then
사용된 프레임워크
•
CoreLocation
•
WeatherKit
주요 코드
Hows The Wear(기간: 54일)
Project
Codebase
CocoaPods
MVC
CoreLocation
WeatherKit
SnapKit
Then
About
•
SwiftSoup를 이용해서 웹 사이트의 텍스트를 크롤링 해옴
•
SF Symbols의 이미지를 랜덤으로 표시하고 5개의 문항 중 정답 선택하면 다음 문제로 넘어가고 오답이면 진동 + 화면 흔들리는 애니메이션 + 빨간색 배경색이 등장 후 사라짐
사용된 오픈소스라이브러리
•
SwiftSoup
•
SnapKit
•
Then
주요 코드
[ JSON 인코딩을 활용한 데이터의 로컬 저장 처리 ]
•
[Symbol] 배열을 받아서 JSON 형태로 인코딩하고 로컬 디바이스의 ‘Documents’ 디렉토리에 저장한다.
•
JSONEncoder.encode(symbols)
를 통해 ‘Symbols’ 배열을 JSON 데이터로 변환하고 이 데이터를 ‘filePath’ 위치에 ‘automic’ 옵션으로 쓴다.
•
‘catch’문을 통해 오류가 발생하면 그 오류를 콘솔에 출력한다.
Codable이란? Swift에서 데이터 모델을 JSON이나 다른 외부 표현 형식으로 쉽게 변환할 수 있도록 하는 프로토콜이다. 실제로는 ‘Encodable’과 ‘Decodable’ 두 프로토콜의 조합인 타입 별칭이다. ‘Encodable’은 Swift 타입을 외부 표현(ex. JSON)으로 변환할 수 있게 해주고 ‘Decodable’은 외부 표현에서 Swift 타입으로 변환할 수 있게 해준다. 따라서 서버에서 JSON 형태의 데이터를 받아와 Swift의 구조체나 클래스로 변환할 때 매우 유용하다.
SF Symbols 퀴즈 앱(기간: 7일)
Project
Codebase
CocoaPods
MVC
SwiftSoup
SnapKit
Then
MADC에서 발견한 모바일 앱 개발의 미래
MADC(Mobile App Developer's Conference)에 참석한 후, 모바일 앱 개발의 최신 트렌드에 대한 깊은 인사이트를 얻을 수 있었다. 특히, 선언형 UI에 대한 강조가 두드러졌다. 선언형 UI는 개발자가 UI의 상태와 동작을 선언적으로 표현하는 방식으로 코드의 가독성과 유지 보수성을 높이는 데 큰 도움을 준다.
선언형 UI의 본질과 SwiftUI의 역할
SwiftUI는 Apple의 최신 프레임워크로써 선언형 UI를 보여준다. SwiftUI를 통해 개발자들은 UI의 상태와 동작을 선언적으로 표현할 수 있으며 이는 기존 명령형 UI 접근 방식과는 확연히 대비된다. 명령형 UI에서 개발자는 UI의 각 변경 사항을 명시적으로 관리해야 했지만 선언형 UI에서는 UI 요소가 상태의 변화에 따라 자동으로 업데이트 된다.
[ UIKit 예제 ]
[ SwiftUI 예제 ]
위 두 코드를 비교하면 SwiftUI가 얼마나 간결하고 직관적인지 명확하게 알 수 있다. SwiftUI에서는 @State를 사용해 count라는 정수 상태를 관리하며 버튼을 터치할 때마다 count가 1씩 증가하면서 뷰가 자동으로 업데아트 된다.
선언형 UI의 장점
선언형 UI의 가장 큰 장점은 개발 과정을 단순화하고 코드의 가독성을 높인다는 것이다. 이는 더 적은 코드로 더 많은 작업을 할 수 있게 해주고 앱의 유지 보수를 용이하게 만든다. 또한, UI와 로직을 분리함으로써 테스트와 디버깅이 더 용이해진다.
컨퍼런스 참여 후 느낀 점
MADC(Mobile App Developer's Conference)
Retrospect
About
•
AVFoundation을 이용해서 버튼에 햅틱 효과를 추가함
•
문자열에 Timer를 이용해서 각 문자에 타이핑 효과를 넣음
사용된 오픈소스라이브러리
•
ViewAnimator
사용된 프레임워크
•
AVFoundation
주요 코드
[ 타이핑 효과 및 특정 문자 커스텀 ]
•
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)
를 사용하여 메인 스레드에서 0.5초의 지연 후에 블럭 내의 코드를 실행한다. → 애니메이션 시작 전에 짧은 지연을 제공하여 뷰가 자연스럽게 이어지도록 함
•
var charIndex = 0.0
은 문자의 인덱스를 추적하기 위한 변수이다. 이 인덱스는 각 문자에 대한 타이머의 시작 시간을 결정하는데 사용된다.
•
for letter in text
를 사용하여 ‘text’ 변수에 있는 각 문자를 반복 실행한다.
•
Timer.scheduledTimer(withTimeInterval: 0.1 * charIndex, repeats: false) { timer in
은 0.1초 x 문자의 인덱스만큼 지연된 타이머를 생성한다. → 각 문자가 하나식 차례대로 나타내기 위해서
인용구 앱(기간: 7일)
Project
Codebase
SPM
AVFoundation
ViewAnimator
출처: https://namu.wiki/w/%EB%A6%AC%EC%B2%98%EB%93%9C%20%ED%8C%8C%EC%9D%B8%EB%A7%8C
오늘은 리처드 파인만(Richard P. Feynman)에 대해 간단하게 작성하고자 합니다. 그는 미국의 물리학자로, 그의 독특한 학습 방법과 강의 스타일로 유명합니다. 그는 항상 호기심을 갖고 새로운 주제를 탐구했고 복잡한 개념을 단순하게 설명하는 데 능숙했으며 문제를 해결하기 위해 실험과 실패를 통해 배우는 것을 즐겼습니다. 여기서 중요한 것은 즐거움을 느꼈다는 것입니다.
그리고 그는
무언가의 이름을 아는 것과 그것을 아는 것은 다르다.
라는 말을 남겼습니다.
예를 들어, 어느 코드를 보고 이것이 객체지향프로그래밍을 적용한 코드라는 것은 알지만 어떤 특징을 가지고 있는지, 어떤 장•단점을 가지고 있는지에 대해 설명하지 못한다면 객체지향프로그래밍에 대해 잘 안다고 할 수 없다는 것입니다.
즉, 그것에 대해 간단하게 설명할 수 있어야 합니다.
그의 공부법은 아래와 같습니다.
파인만 기법
1.
현재 자신이 공부하고 있는 주제나 관심 있는 주제를 골라 그 주제에 대해 학습합니다.
2.
학습한 내용을 아무것도 모르는 어린아이에게 가르친다고 생각하고 최대한 쉽고 단순하게 설명합니다.
3.
왜?라는 질문을 던졌을 때 답변을 하지 못하거나 어려운 단어가 들어간 내용들을 골라냅니다.
파인만 기법
Motivation
Swift는 Apple에서 개발한 현대적이고 강력한 프로그래밍 언어로,
객체지향프로그래밍
패러다임을 완벽하게 지원합니다.
객체지향프로그래밍(Object-Oriented Programming)
객체지향프로그래밍은 프로그램을 독립된 단위인 객체(Object)들로 나누고 이 객체들의 상호작용을 통해 프로그램을 설계하고 구현하는 패러다임입니다. 각 객체는 속성과 메서드를 가지며 클래스라는 틀을 사용하여 객체를 생성합니다.
객체지향프로그래밍의 장점
•
모듈성과 재사용성
- 객체는 독립적이고 재사용 가능한 단위로 구성되므로 코드를 모듈화 하고 재사용하기 용이합니다. 이로써 코드의 유지보수가 편리해지며 생산성을 높일 수 있습니다.
•
유지보수 용이성
- 코드의 변경이나 구현에 대한 영향을 최소화할 수 있습니다.
객체지향프로그래밍의 단점
•
복잡성
- 객체지향프로그래밍은 강력한 도구지만 복잡한 클래스 계층 구조나 다양한 객체 간의 관계를 다루는 것은 어려울 수 있습니다. 잘못된 설계나 사용 시 의도하지 않은 문제가 발생할 수 있습니다.
•
용량
- 객체지향프로그래밍은 클래스와 객체를 사용하므로 코드의 구조가 복잡해질 수 있습니다. 클래스 정의, 객체 생성 및 관리를 위한 코드 등이 추가되므로 컴파일된 바이너리 파일의 크기가 증가할 수 있습니다. 더 많은 메모리 공간이 필요하게 되며 이는 앱의 다운로드 크기나 메모리 사용량 측면에서 고려해야 할 요소가 될 수 있습니다.
•
실행속도
- 객체지향프로그래밍은 객체 간의 상호작용과 메서드 호출 등의 오버헤드를 동반합니다. 이로 인해 프로그램의 실행 속도가 조금 느릴 수 있습니다. 예를 들어, 객체의 생성과 소멸, 메서드 호출 등은 함수 호출보다 약간의 추가 작업이 필요하므로 작은 규모의 작업에서는 큰 문제가 되지 않을 수 있으나 대규모의 반복적인 작업에서는 성능 저하를 불러올 수 있습니다.
객체지향프로그래밍 특징
객체지향프로그래밍은
캡슐화
,
상속
,
추상화
,
다형성
이라는 4가지 특징을 가집니다.
1. 캡슐화(Encapsulation)
캡슐화는 변수와 함수를 하나의 단위로 묶는 것을 뜻합니다. 이렇게 하면 데이터에 직접 접근하는 것을 제어하고 데이터의 변경이나 조작이 오로지 해당 객체의 메서드를 통해서만 이루어지도록 합니다. 이로써 외부에서의 무작위 접근을 방지하고 안정성을 높일 수 있습니다.
Object-Oriented Programming(OOP)
Computer Science
About
•
Kingfisher를 이용해서 원격 저장소에서 이미지 다운로드 후 캐싱하여 앱의 반응 속도와 데이터 관리 효율성을 증가시킴
•
ViewAnimator를 이용해서 사용자에게 보다 매력적인 인터페이스를 경험할 수 있도록 함
사용된 오픈소스라이브러리
•
Kingfisher
•
ViewAnimator
주요 코드
[ 이미지 다운로드 및 캐싱 ]
•
DownsamplingImageProcessor
를 사용하여 ‘backgroundImageView ‘의 크기에 맞게 다운샘플링하였고 이를 통해 메모리 사용을 줄이고 앱의 성능이 향상된다. → 특히, 대용량 이미지를 다룰 때 유용함
•
.scaleFactor(UIScreen.main.scale)
은 이미지를 현재 디바이스 스크린 스케일에 맞게 조정한다. 이를 통해 다양한 해상도를 가진 디바이스에서 이미지가 깨지지 않고 선명하게 보일 수 있도록 도와준다.
•
.transition(.fade(0.2))
를 사용하여 이미지가 로드될 때 사용자에게 부드러운 시각적 경험을 제공하였다.
•
.cacheOriginalImage
는 ‘Kingfisher’기 이미지를 다운로드한 후 원본 이미지를 캐시에 저장하게 한다. 나중에 같은 이미지를 다시 요청할 때 캐시에서 빠르게 로드할 수 있어서 네트워크 사용을 줄이고 더 빠른 이미지 로딩을 가능하게 한다.
두뇌 게임(기간: 7일)
Project
Storyboard
SPM
Kingfisher
ViewAnimator
About
•
닉네임, 한 줄 프로필과 자기소개 입력 및 유효성 검사
•
이전 뷰 컨트롤러에 데이터 전달 및 저장 → UserDefaults
사용된 오픈소스라이브러리
•
PanModal
사용된 프레임워크
•
SafariServices
새로 배운 것들
•
SFSafariViewController
•
UserDefaults
SFSafariViewController
•
웹 뷰를 띄우는 방법 세 가지
1.
UIWebView
2.
WKWebView
프로필 설정(기간: 7일)
Project
Storyboard
SPM
SafariServices
PanModal