![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/bl1czj/btsGEUS2O4p/Gx1hwUsSBGUZ8dawozfGxK/img.png)
약 두달정도 사이드 프로젝트 팀 'WEAVE'에 들어가 열심히 프로젝트를 진행했다. 프로젝트 진행 중 예상치 못하게 그라데이션에서 고민했던 부분이 있어서 글로 남겨보려고 한다. 디자인 요구사항은 이러했다. 그라데이션이 이어지는 형태의 Stepper 다. 하지만 저 디자인을 코드로 옮기려니 그라데이션 부분에서 쉽지 않았다. 일단 Setpper 를 구현해보자. Stepper 구현 public struct WeaveStepper: View { let maxStepCount: Int let currentStep: Int public init( maxStepCount: Int, currentStep: Int ) { self.maxStepCount = maxStepCount self.currentStep = cur..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/Atmoc/btsC4t35YyL/Kb8r1yYL2mpjuetkRwRMo1/img.png)
담당하는 프로젝트에서는 Toast 메시지를 띄우기 위해 라이브러리를 사용하고 있었다. 이런 저런 이유로 기존 사용하던 라이브러리를 들어내기로 했고, 직접 만들지 혹은 다른 라이브러리를 찾아볼지 고민을 하다 새로운 느낌의 toast 라이브러리를 시범 적용해보기로 했다. release가 꾸준히 되고 있으며, 너무 레거시하지 않은 라이브러리를 찾고 있었다. 그렇게 찾은 라이브러리는 iOS 기본 스타일의 메시지를 띄워주는 "toast-swift" 라는 녀석이다. https://github.com/BastiaanJansen/toast-swift 그렇게 새로운 느낌의 toast를 적용했는데, 조그만 문제가 있었다. 토스트가 뜨는 버튼을 유저가 여러번 누를수도 있다. 그렇게 된다면 여러개의 토스트 뷰가 겹쳐서 뜨게..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/ncoKF/btsCUyMiy5X/yLayNbfKKF9OPOMltWHbC0/img.png)
연말에 전혀 예상하지 못한 오류가 보고되었다. 유저는 분명 2023년 12월 31일을 선택했는데, 2024년 12월 31일 로 나오는 이슈가 있었다. 시간이 바뀌거나 하루 단위면 UTC 관련 이겠구나 싶었는데, 다른 날짜들은 모두 정상이였고, 연도가 바뀌는 현상은? 아무런 생각도 들지 않고 감도 못잡았다. 결론부터 말하자면, 간단한 오타에 의한 이슈였다. DateFormatter DateFormatter는 서비스 영역에서 너무나 자주 만나게되는 고마운 녀석이다. "yyyyMMddHHmmss" 형식을 관례적으로 늘 자주 사용하다보니 dateFormat 이 문제일줄은 몰랐다. 눈을 씻고 기존에 (누군가) 작성해둔 코드를 찾아보니 yyyy가 소문자가 아닌 대문자 YYYY 로 되어 있었고, 여기서, yyyy 와..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/bQmC1Z/btsz91iTzaY/lF31UFM7FG9NUMQT9h21Jk/img.png)
최근 회사에서 Watch App을 만들게 되어 열심히 만들고 있다. Watch App을 간단히 살펴 보자면 - 이전에는 UIKit으로도 만들 수 있었는데, 이제는 SwiftUI로 안만들 이유가 없을 듯 하고, - 폰에서 데이터 전송이 대부분 필요할텐데, shared UserDefaults 가 아닌 Watch Connectivity를 통한 전달이 필요하다. UIKit만 바라보던 나는 미뤄두던 SwiftUI를 이참에 공부를 했고 (이건 신세계..) Watch Connectivity에 대해 공부를 했었다. 본 포스트에서는 개념보다는 WatchApp을 만들어 가면서 만났던 이슈에 대해 정리를 해보려고 한다. 1. Watch OS 버전 개발을 위해 회사에서 지급받은 워치5는 무려 9.6.3 버전이다. (23년 9..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/OejEP/btsyTrX90K7/94CRBaKKatqpKtI521ikY1/img.png)
내가 구현하는 FLO 앱의 두가지 뷰에는 모두 가사가 들어있으며, 시간에 맞춰 자동으로 스크롤된다. Player 뷰 에서는 두줄을 보여주며 스크롤 되며, 가사 영역을 터치할 경우 가사가 크게 나온다. 1. 기능 분석 플레이어 뷰(좌측) - 오토 스크롤 - 하이라이팅(흰 글씨) - 가운데 정렬 - 유저 터치시 가사뷰로 이동 가사 뷰(우측) - 오토 스크롤 - 하이라이팅(흰 글씨) - 좌측 정렬 - 유저 터치시 해당 영역으로 플레이어 이동 - 유저의 스크롤도 가능 - 가사 컨트롤 버튼 존재 플레이어 뷰의 기능에서 더 확장된 것이 가사 뷰 라고 할 수 있겠다. 동일한 클래스를 사용할 수 있도록 LyricTableView를 만들고, 각 뷰별로 해당하는 옵션을 넣어주도록 하자. 2. 모델 만들기 먼저 테이블 뷰에..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/bzDxHT/btsyMeDNARP/JNJmCNGks7sPSmK4Em8rU1/img.gif)
뮤직 플레이어 앱을 포함한 미디어 관련 서비스에는 유저가 재생중인 미디어의 타임라인을 조절하는 기능이 있다. Seekbar 라는 이름으로 많이 부른다. FLO 뮤직 플레이어 앱에서도 물론 Seekbar가 존재한다. 플레이어 컨트롤러 버튼들과 마찬가지로 MusicPlayer의 정보를 보여주며, 유저 인터랙션을 통해 싱글톤 객체를 컨트롤 하는 역할이다. 나는 PlayerSeekbar 클래스를 만들어서 각 뷰에 넣어주었다. 이번 글에서는 FLO 뮤직플레이어 앱에서 어떻게 Seekbar를 구현했는지 작성하고자 한다. 1. Seekbar의 기능 - MusicPlayer의 currentTime을 바인딩해 UI로 표시 - MusicPlayer의 currnetPlaybackRatio(재생 비율)을 바인딩해 해당 비율만..
FLO MusicPlayer 앱에서 사용하는 AVPlayer는 음악을 재생시키고, 컨트롤를 하는 핵심 요소로 사용된다. AVPlayer를 어떻게 사용했는지 알아보자 먼저, iOS의 프레임워크들에서 자주 사용했던 자연스럽게 delegate를 채택하려고 했지만, delegate가 AVPlayer에는 없다. 대신, KVO(Key-Value-Observing) 방식으로 AVPlayer의 상태값을 받아올 수 있다. KVO는 존재만 알고 있었던지라, 이번 기회에 공부를 해보았다. KVO 짧은 정리 KVO는 NSObject의 기능으로 willSet, didSet 과 유사하다고 볼 수 있음 프로퍼티의 상태 변화에 대해 '외부' 에서 옵저버를 추가할 수 있음 (willSet, didSet은 내부에서 추가 필요) 외부에서..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/eJl0gh/btsyulDaQWQ/RjY03q2FKy0WvguLksh3Hk/img.png)
음악 플레이어에서 가장 중요한 코어 기능은 음악을 제어하는 기능이다. (플레이어 컨트롤러) 아래 사진은 이전 글에서 설명했던 앱의 구조인데, 뷰에 들어가는 공통 기능 중 ControlButtons 에 대한 설명을 해보려고 한다. 1. 개요 FLO 앱을 포함한 음악 플레이어 앱의 컨트롤 버튼을 생각 해보면, 가장 큰 특징은 어느 곳에서나 같은 역할을 한다는 점이다. 재생, 일시정지, 앞으로가기, 뒤로가기 등.. 여러 기능들이 있지만, 뷰가 다르다고 하여 다른 역할을 하지 않으며 음악을 컨트롤 하는 같은 역할을 한다. 특히 나는 음악을 재생하는 MusicPlayer 객체를 싱글톤으로 만들어서 앱의 어느곳에서든 항상 존재하도록 구현했다. 즉, 생성하는 버튼이 하는 일은 MusicPlayer 싱글톤 객체를 제어..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/bQg5NI/btsyqvfWb92/nGJ2EUrFkOmglhIYK7Kak0/img.png)
그동안 궁금했었던 부분들에 대해 공부하는 시간을 가져보던 중 평소 관심있었던 부분인 뮤직 플레이어를 만들어 보고 싶었다. FLO의 플레이어 뷰를 보면 기능 요구사항은 다음과 같다. - 플레이어 컨트롤 버튼 - 시간에 따른 가사 자동 스크롤 - 가사를 탭 했을 때 해당 부분으로 이동 - 음악 정보(이미지, 곡 정보 등) 사용한 프레임워크와 앱의 구조를 살펴보자 1. AVFoundation AVFoundation은 [ CoreAudio / CoreVideo / CoreMedia / CoreAnimation ] 위에 있는 프레임워크다. Core 패밀리들은 iOS 혹은 MacOS 등에서 하드웨어와 함께 Low-Level 로 동작하는 프레임워크들이고(C 기반), AVFoundation은 Core 패밀리 위에서 멀..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/bLkWvO/btsyqxqZeIi/OIb0d9WWMNzyPkzDRe8T1K/img.png)
앱을 개발하다보면 URL이나 전화번호를 연결해줘야 할 경우가 많이 있다. URL은 링크로, 전화번호는 전화로 연결을 해주어야 한다. 그렇다면 링크와 전화번호를 UILabel에서 인식을 해야 하고, 하이라이트 등의 기능을 구현해야 하는데 .. 이 기능을 훌륭하게도 UITextView가 가지고 있다. 이번 포스팅에서는 UITextView를 이용해 링크와 전화번호 등의 인식과 연결을 구현하고, UILabel 처럼 사용하는 방법을 알아보려고 한다. 1. 샘플 뷰 먼저 스토리보드에서 다음과 같은 뷰를 후다닥 만들어주었다. 동일한 내용의 더미 데이터고, 위는 UILabel, 아래는 UITextView로 만들었다. 앞서 얘기했었던 URL과 전화번호를 인식하는 기능은 UILable 에서는 기본 제공하지 않는다. UIT..
- Total
- Today
- Yesterday
- 2024년
- KVO
- 애플워치 데이터 전송
- TextField
- openapi-generator
- Swift
- 소수점
- Xcode15
- SwiftUI
- avplayer
- DateFormatter
- 애플워치
- easy cue
- Xcode
- musicplayer
- 회고
- open-api-generator
- retry
- watch connectivity
- swift날짜
- flo
- 토큰
- keyboardtype
- OAS
- demical
- locale
- AVFoundation
- IOS
- auth
- watchOS
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |