IOS/개발일지

개발 일지(3) - ListenApp

hyukji 2023. 2. 3. 02:26

 

 

 

< 지난 포스팅 >

 

2023.01.27 - [개발일지] - 개발 일지(2) - ListenApp

 

개발 일지(2) - ListenApp

지난 포스팅 2023. 1. 18 로 부터 1주일이 지났다! 이번 주에는 설날이 끼어 있어서 생각보다는 진도가 늦어졌다. 하지만 그 덕에 기능들과 UI/UX에 대한 많은 고민을 할 수 있었고 더 좋은 방향으로

hyukji.tistory.com

 

 

 

 

 

벌써 2월달이라니.. 시간이 참 빠르다ㅎ

 

 

이번주에는 지난 포스팅에서 말한 데로 먼저 PlayerView 재구성을 했다.

 

 

 

주황색과 파란색 부분으로 View를 나누어서 구현했다.

 

먼저 하단의 주황색 부분은 PlayerController과 관련이 있다. 단순히 Player의 시간을 변경해주거나 재생/일시정지에 관여한다.

 

구현에 있어 난이도가 있었던 부분의 상단의 남색 부분이었다.

 

 

먼저 timer를 설정을 해주었다. 해당부분에서는 Player의 시간에 맞추어 WaveForm의 진행과 slider 진행을 보여주어야 한다. 따라서 timer을 설정해 Player 재생시에 0.01 단위로 뷰를 업데이트 해주도록 설정해 주었다. NotificationCenter를 통해 player의 상태 변화를 감시해 timer 활성화 여부를 판단하게 해주었다. 

 

 

두번째는 waveForm의 진행이다. 시간에 맞추어 waveForm이 진행되어야 했고 스크롤 작동이 가능해야했다. 따라서 UIScrollView와 UIStackView를 활용했다. 따라서 timer 활성화되었을 때 scrollView의 x좌표를 이동시켜 주었고, 스크롤할 경우 Player의 currentTime에도 변화를 주었다.

 

 

해당 wave의 생성은 오픈소스를 활용했다. 하지만 파일의 크기가 클수록 음성파일을 분석하고 그리는 데 상당한 시간이 소요되었다. 따라서 AudioData를 매번 분석하는 것이 아닌 사전에 미리 분석해 저장시켜 둘 필요가 있었다. 필자는 분석한 결과를 CoreData를 활용 저장해 두기로 했다. 매번 오디오를 분석하지 않고 선택된 파일에 맞추어 분석된 결과를 가져오도록 구현했다. 이를 위해서 Document에 있는 음성파일에 맞추어 Coredata에 저장된 값들을 정리하는 메서드를 만들었고 특정상황(앱 부팅, wifiFile 공유 시 등등)에서 호출되도록 구현했다.

 

 

 

분석한 결과를 바로 이미지화 시키지 않고 분석한 값들을 저장한 이유는 이미지를 생성하고 저장하는 데 너무 오랜 시간이 걸리기 때문이다. 필자는 30분짜리 음성파일을 가지고 이미지를 생성했는 데 4분 정도가 걸렸다. 내가 사용자라면 해당 시간을 기다리진 않을 것 같다ㅎㅎㅎ 따라서 분석한 결과를 세분화 해 필요한 부분들을 이미지화 시키려고 한다. UITableView의 prefetch 처럼 scrollView와 currentTime를 통해 필요한 부분들을 이미지화하고 deque로 관리할 생각이다.

 

 

 

 

 

 

 

이번 주에도 물론 열심히 삽질을 했다ㅎㅎㅎ 삽질한 내용도 같이 포스팅하겠다.

조언과 지적은 언제든지 환영입니다.

 

 

 

CoreData에 해당 오디오파일의 url을 같이 저장해 주려고 했다. 하지만 url이 실행할 때마다 달라졌다. 아래는 Test1.mp3의 url을 두번에 나누어 실행하면서 출력한 값이다. 파란색으로 칠한 부분이 다름을 확인할 수 있었다. 

 

.../CoreSimulator/Devices/C27B1A4D-450C-4A3B-8C66-0AC63013E820/data/Containers/Data/Application/5891A616-36CF-4085-B3C5-385CF2230C06/Documents/Test1.mp3

 

.../CoreSimulator/Devices/C27B1A4D-450C-4A3B-8C66-0AC63013E820/data/Containers/Data/Application/C8A021B8-66EB-44E9-8863-FE564D479A7F/Documents/Test1.mp3

 

 

따라서 url을 저장하지 않았고 url은 filemanager로 가져온 데이터로 만든 DoucumentItem 구조체에 저장해주었다.

 

 

 

 

 

또한 CoreData에 분석한 데이터를 저장할 때, 해당 데이터가 어떤 파일을 분석한 결과인지에 대한 identifier를 같이 저장해주어야 한다. 하지만 filemanager에는 이런 identifier에 대한 값이 없었다. 그래서 필자는 NSFileSystemFileNumber와 creationDate를 사용해 identifier를 구상했다. 

 

https://stackoverflow.com/questions/5690628/will-nsfilesystemfilenumber-in-ios-always-be-unique

 

will NSFileSystemFileNumber in iOS always be unique?

When using attributesOfItemAtPath:error:, is NSFileSystemFileNumber always guaranteed to be unique for the device? For example, I have a file with a certain NSFileSystemFileNumber, but a few days ...

stackoverflow.com

 

 

NSFileSystemFileNumber 는 해당 파일이 저장된 위치를 나타낸다. 따라서 해당 파일이 사라지고 그 위치에 새로운 파일이 저장되지 않는 이상 NSFileSystemFileNumber는 unique한 값이다. 따라서 해당 위치의 파일이 변경되었을 경우를 체크하기 위해 NSFileSystemFileNumber만이 아닌 creationDate도 같이 비교하도록 구현했다.

 

 

 

 

 

 

마지막으로 waveAnalysis 즉 분석한 결과를 저장할 때 발생한 에러이다. fileManager로 가져온 파일 중 분석된 결과가 저장되지 않은 것이 있다면 분석 후에 결과 값과 같이 save하도록 구현했다. 애석하게도 The operation couldn’t be completed. (Cocoa error 133021.) 에러가 발생했고 stackOverFlow에서 해답을 찾을 수 있었다.

 

 

https://stackoverflow.com/questions/37850818/the-operation-couldn-t-be-completed-cocoa-error-133021-swift-2

 

The operation couldn’t be completed. (Cocoa error 133021.) + swift 2

I am currently using core data in my application. I have the following entities : Notification (to-1), People (to-many). The entities are as follows: schema for Notification entity schema for Peo...

stackoverflow.com

 

 

Duplication creation 에러였고, tranditional 해결법은 해당 entity를 미리 save를 해둔 뒤에 특정 값을 따로 update해야 했다. 

 

 

 

 

또한 파형을 분석중일 때 재생을 할 수 없기에 현재 분석 중임을 알려주어야 했다. (참고로 30분짜리 음성데이터를 분석하는 데 대략 5초 정도의 시간이 걸린다.) 따라서 그 시간 동안 reflashController를 사용해 다음과 같이 파형을 분석하고 있음을 보여주고자 했다.

 

 

 

따라서 분석을 해야하는 파일 개수를 static 변수 shouldUpdateCount에 저장해 두었고 업데이트 후에 불려질 @escaping completion 클로저를 설정했다. 만일 저장해야 하는 파일 개수가 4개라면 shouldUpdateCount에 4를 대입해주고, 하나가 저장될 때마다 completion을 호출해 shouldUpdateCount-=1 을 해주었다. shouldUpdateCount가 0 이 되는 시점 즉 모든 분석이 끝났을 때에 endRefreshing을 호출해 분석이 완료되었음을 알려주었다.

 

 

 

 

 

 

 

 

 

 

돌아오는 주에는 재생화면에서의 기능들을 구현할 계획이다.

위에서 말한 scrollview에서의 prefetch와 어절단위의 시간 변화 등을 할 계획이다.