멋쟁이사자처럼 iOS 앱 스쿨에서 최종 프로젝트로 단어장 앱을 만들면서, AVSpeechSynthesizer를 활용하여 TTS 기능을 구현하려고 했다. 하지만 구현 과정에서 예상치 못한? 오류를 만났고 생각보다 골머리를 썩였다. 코드 상으로는 전혀 문제가 없었는데 말이다. (진짜로? 문제 없는 거 맞아?) 그렇게 고민하던 중, 결국 View Memory Graph Hierarchy를 통해 오류를 해결할 수 있었다. 처음 써봤는데 정말 유용한 친구라는 걸 깨달았다. 아무튼 오늘은 메모리 관련 이슈가 있을 때 사용하면 정말 유용한 친구를 소개하고자 한다. 그 전에, AVSpeechSynthesizer는 어떻게 동작하는지에 대해 알아보도록 하자. AVSpeechSynthesizer의 동작 과정 코드로는 이렇게..
SwiftUI에서는 @ObservableObject 덕분에 ViewModel(역할을 하는?)을 쉽게 구현할 수 있다. 덕분에 실습을 진행하면서 대부분의 프로젝트에서 ViewModel로 분리는 했지만 문제가 많았다. 일단 SwiftUI가 View 자체적으로 Data Binding이 가능하기 때문에 이미 ViewModel이 녹아들어간 느낌이다. 하지만 이것보다도 하나의 ViewModel에서 여러 작업을 진행하다보니 Massive ViewModel이랄까? ViewModel이 비대해진 느낌이 들었고, 그래서 해커톤 때는 이런 것들을 걷어내고 아키텍쳐적으로 조금 더 괜찮은 앱을 구현하고 싶었다. 다행히도 팀원 중 한 분이 클린 아키텍쳐에 대해 잘 알고 계셔서 도움을 많이 받았고, 전보다는 어느정도 완성된 앱을 만..
23.01.13 - 앱을 처음 설치했을 때 현재 위치로 이동하지 않는 오류 해결 지난 번 프로토타입에 이어 이번 주부터는 MVP를 진행하고 있다. 기존에 더미 데이터로 구현했던 것들을 실제 FireStore와 연동하고 구현하지 못했던 부분들을 구현하는 것을 목표로 잡았다. 이번 주에 구현하려는 기능은 아래와 같다. 1. 사용자가 지도를 움직이면 움직인 좌표에 대한 도로명 주소를 실시간을 가져옴 2. 사용자가 지도를 움직이면 마커가 살짝 위로 올라가고, 움직임이 멈추면 마커가 다시 내려옴 3. 사용자의 현재 위치를 가져오고, 버튼을 클릭하면 현재 위치로 지도의 Focus를 변경함 하나씩 살펴보도록 하자. 1. 사용자가 지도를 움직이면 움직인 좌표에 대한 도로명 주소를 실시간으로 가져오기 말이 좀 길다. 간..
SwiftUI로 개발을 진행하다가 View 내부에서 직접적으로 프로퍼티에 접근할 때 onAppear를 한 번쯤은 사용한 경험이 있을 것이다. 가령, print(프로퍼티)처럼 View 내부에서 접근하면 이런 에러가 뜬다. View를 반환해달라는 에러다. 이런 에러와 마주치지 않기 위해 View 내부에서 직접적으로 접근하지 않고, onAppear 클로저 내부에서 접근하는 방식을 택한다. 아무튼 이럴 때 자주 사용하는 onAppear는 SwiftUI View Life Cycle에 속하고, 오늘은 Life Cycle에 대해 알아보려고 한다. SwiftUI에선 3개의 Life Cycle이 있고, 각각의 Appear, Update, Disappear 이다. 1. onAppear onAppear은 View가 보여지기..
22.11.21 json에 존재하는 key, value를 struct에서 정의하지 않을 경우에는 정상적으로 Decoding 반대로 json에 존재하지 않는 key, value를 struct에서 정의하는 경우에는 KeyNotFound Error가 발생 특정 value에 key-value가 부분적으로 존재할 때는 Optional을 적용 만약, key-value를 제대로 정의했는데 KeyNotFound Error가 발생하면 특정 key-value가 부분적으로 존재하는지 확인할 것 22.11.22 json에는 id가 없지만 identifiable을 만족시키기 위해 uuid를 넣어주는 경우 var이 아닌 let으로 선언 EnvironmentObject를 사용할 때, 최상단에서 인스턴스를 넣어주기에 뷰의 게층 구조..
오늘은 ScrollView와 LazyVStack을 활용하여 SwiftUI에서 무한 스크롤을 구현해보려고 한다. 사실, LazyVStack이 조금 생소할 수 있다. LazyVStack은 말 그대로 Lazy하게 VStack을 그린다는 느낌으로, VStack으로 보여줄 항목이 실제로 UI에 보여질 때 렌더링을 진행하는 View이다. Apple Developer Documentation developer.apple.com 그렇다면 기존에 사용하던 VStack과는 어떤 차이가 있을까? 평소에 사용하던 VStack은 뷰가 보여질 때(onAppear) 모든 항목을 렌더링한다. 그렇기에 ScrollView + VStack 조합으로 List를 나타낸다면 초기에 많은 리소스를 소모하게 된다. 적은 개수의 간단한 항목들을 ..
두근두근 렛어스고! 👋 지난 주에 렛어스고에 다녀왔다. 11월 5일에 다녀왔지만! 지금 회고를 쓰고 있다. 원래 회고는 일주일 뒤에 쓰는게 국룰! 😋 우선 렛어스고는 지금 하고 있는 멋사 앱스쿨에서 한 분이 정보를 공유해주셔서 알게 됐고, 운 좋게 티켓팅에 성공해서 참가하게 됐다. 티켓은 학생 티켓과 일반 티켓이 있다. 학생 티켓이 훨씬 저렴하지만 수량이 적어서, 학생 티켓 예매에는 실패했고 일반 티켓을 예매했다! 버스를 타고 서울까지 가야하는 상황이라 조금 고민이 많았지만, 그래도 iOS 세미나를 참가해보고 싶어서 아침 일찍 서울을 향했다. 발표 장소는 코엑스 앞에 있는 Finda였다. 30분 정도 일찍 도착했더니 운영진을 제외하고는 거의 없었다. 뒤에 계신 분과 얘기를 나눌까했지만 같이 오신 분이 있..
Swift로 문자열 문제를 풀다보면 오류를 자주 접하게 된다. (error: cannot convert value of type 'String.Element' (aka 'Character') to closure result type 'String) '이게 왜 안됨? ㅋㅋ' 라는 생각이 들 정도로 안된다. 아무튼 이런 오류를 자주 접했기에 글로 정리하면서 다시 한 번 복습하려고 한다. 1. 문자열 형 변환하기 1. String -> Int 다른 언어에서처럼 Int()로 형 변환을 진행한다. 이 때, String인지 SubString인지 Character인지 잘 살펴본다. (그렇지 않으면... error: cannot convert value of type 'String.Element' (aka 'Chara..
State와 Binding 지난 시간 @State와 @Binding 프로퍼티 래퍼에 대해 학습했다. 1. @State @State 프로퍼티 래퍼를 사용해서 상태 프로퍼티를 작성하면 해당 프로퍼티가 선언된 뷰와 바인딩할 수 있게 된다. 좀 더 쉽게 설명하자면 뷰와 바인딩이 되어 있는 상태프로퍼티에 변경이 일어나면 자동으로 뷰가 갱신된다는 말이다. 코드로 직접 살펴보자. 아래 코드는 버튼을 클릭하면 숫자가 1씩 증가하도록 구현한 앱이다. struct ContentView: View { @State private var number: Int = 0 var body: some View { VStack { Text("\(self.number)") Button(action: { self.number += 1 }) ..
SwiftUI Keyboard Dismiss 어제 구현한 팀 과제를 다시 한 번 구현하던 도중에 추가해보고 싶은 기능이 있었다. 사용자 입력을 소프트 키보드 혹은 버튼을 통해서 입력 받는데, 소프트 키보드로 입력 받은 경우에 Submit을 누르지 않고, 뷰의 클릭하더라도 소프트 키보드가 닫히도록 구현하고 싶었다. 1. Focused 우선 이 기능은 SwiftUI 3.0 (iOS 15) 이상부터 지원한다. 그런 탓인가 정말 간단하게 구현이 가능하다. var body: some View { @State private var input: String = "" @FocusState private var isFocused: Bool // 생략... VStack { TextField("PlaceHolder", $i..