[AVAsset]에서 duration load delay 이슈

2023. 2. 3. 14:26iOS/이슈

비디오 피드 리스트 스크롤에 버벅이는 이슈 발생

의심

case asset thumbnailGenerator

case asset duration

case video size

처음엔 썸네일과 비디오 사이즈 때문에 버벅이는 줄 알았는데 asset의 duration을 load하는 것 때문에 버벅였다.

duration load를 background queue로 돌리고 할당하는 부분을 main으로 줬는데도 load 부분에서 버벅임.

 

Try. Cell bind()에서 Background Thread로 로드하기

여전히 버벅임

Try. NSCache 이용하여 TableVIew/CollectionView에서 데이터 딜레이 없이 불러오기

아래 샘플 프로젝트를 참조하여 Image 대신 asset의 duration을 async하게 불러오고 NSCache에 저장하기

// TableView ViewController
// cellForItem() 부분에 해당 코드를 작성
DispatchQueue.global(qos: .background).async {
    if let urlString = model.contentVideo,
      let video = AwsImageUtil.loadVideo(title: urlString) {
      DurationCache.publicCache.load(url: video as NSURL) { timeString in
        if let timeString = timeString as? String {
          cell.updateUI(duration: timeString)
        }
      }
    }
}
func load(url: NSURL, completion: @escaping (NSString?) -> Void) {
    if let cachedDuration = duration(url: url) {
      completion(cachedDuration)
      
      return
    }
    if loadingResponses[url] != nil {
      loadingResponses[url]?.append(completion)
      return
    } else {
      loadingResponses[url] = [completion]
    }
    
    guard let blocks = loadingResponses[url] else {
      completion(nil)
      return
    }
    
    let asset = AVAsset(url: url as URL)
    var error: NSError? = NSError(domain: "duration", code: 1)
    
    // 배포 타겟이 14라 최근에 나온 load()를 적용 못 함
    asset.loadValuesAsynchronously(forKeys: ["duration", "tracks"]) {
      guard asset.statusOfValue(forKey: "duration", error: &error) == .loaded else { return }
      let seconds = Int(asset.duration.seconds)
      let videoDuration = NSString(format: "%02d:%02d", seconds / 60, seconds % 60)
      self.cachedDurations.setObject(videoDuration, forKey: url)
      
      for block in blocks {
        block(videoDuration)
        return
      }
    }

문제

NSCache가 자동으로 release되면서 불러오지 못하는 문제가 발생했다. 이 문제를 찾아보니 Local Storage에 저장하여 해결하였다고 한다. CoreData를 이용하여 비디오 메타데이터를 저장하던, 직접 파일에 쓰던해서 Memory -> Disk -> Network 순으로 작성해야겠다.

느낀점

썸네일 이미지 data보다 duration number 데이터가 cost가 클지 몰랐다. 

cell의 state는 cell이 아니라 List가 주체가 되어 관리해야한다.

async thread를 좀 더 잘 이해하게 되었다.

이제 serial과 concurrent로 세분화해서 사용해봐야 겠다.

 

[참고1] WWDC Create a more responsive media app
https://developer.apple.com/videos/play/wwdc2022/110379/

[참고2] duration load async하게 불러오기

https://ios-development.tistory.com/938#comment17702592

[참고3] 애플 도큐먼트 샘플 프로젝트 ListView에서 async하게 데이터 불러오기

https://developer.apple.com/documentation/uikit/views_and_controls/table_views/asynchronously_loading_images_into_table_and_collection_views

 

Apple Developer Documentation

 

developer.apple.com

[참고4] NSCache 설명 블로그

https://nsios.tistory.com/58