photoPicker에서 AVAsset 추출하기

2026. 2. 16. 21:08·iOS/SwiftUI
반응형

👋 들어가기 전

 

포토피커를 통해, photosPickerItem을 가져와서 AVPlayer까지 재생하는데,

너무 오래 걸린다..

 

단, 30초 밖에 안되는 영상인데 말이다...

 

개선하는 과정이 너무 어이없어서, 남겨놓으려한다..


🏁 학습할 내용

  • 문제점
  • 개선 과정

🤬 문제점

 

🐌 너무 느린 로딩 속도

 

Gif 이미지를 보면, 4초 쯤에 영상을 선택했는데, 화면이동이 약 26 ~ 27정도에 진행됐다.

단, 32초 밖에 안되는 영상을 가져오는데 20초 가량이 걸린 것이다..


여기서 느낀 이상한 점은 크게 2개다.

 

  • 아니 왜이렇게 오래걸리는거야??
  • 갤러리에 접근하는데 왜, 권한을 안물어보지??

 

권한 문제는 해결 과정에서 알아보고, 일단 왜 이렇게 오래걸리는 지, 문제를 파악해보자.

 

1️⃣ PhotosPickerItem을 잘못쓰고 있었다.

 

photosPicker modifier를 사용하면, 다음과 같이 선택한 결과로
photosPickerItem 배열로 받는다.

  nonisolated public func photosPicker(
	selection: Binding<[PhotosPickerItem]>,
	..
)


PhotosPickerItem을 AVPlayer에서 재생하기 위해서는, URL 형태로 변환해야하는데

변환 과정을 찾아보니, Transferable 객체를 선언하고, PhotosPickerItem의 loadTransferable

메서드를 사용하라고 한다.

 

앞으로 PhotosPickerItem을 그냥 Item으로 부르겠다. (너무 김..)

 

2️⃣ URL을 얻기위한 복사

 

URL을 얻기 위해서, FileManager를 통해 임시로 복사하고, 그 URL을 사용했다.

  struct Video: Transferable {
    let url: URL

    static var transferRepresentation: some TransferRepresentation {
      FileRepresentation(
        contentType: .movie,
        exporting: { movie in
          SentTransferredFile(movie.url)
        },
        importing: { received in
          let copy = URL.documentsDirectory.appending(path: "movie.mp4")

          if FileManager.default.fileExists(atPath: copy.path()) {
            try FileManager.default.removeItem(at: copy)
          }

          try FileManager.default.copyItem(at: received.file, to: copy)
          return Self.init(url: copy)
        }
      )
    }
  }


  func transform(_ item: PhotosPickerItem) async throws -> URL {
    guard let video = try await item.loadTransferable(type: Video.self)
    else {
      throw PhotosPickerItemTransformerError.failedToLoadData
    }

    return video.url
  }

 

여기서 문제가 발생했다.. (해당 과정은 여러 구글 정보를 참고해서 만듬)

 

애초부터 뭔가 이상했다. 왜 PhotosPicker로 정보를 읽어왔는데 또 복사를 해야하는거지??

영상의 시간이 조금만 커져도, 복사 시간이 기하급수적으로 커졌다.

 

여기서 나는, 복사 없이 정보를 얻어와야한다고 생각했고, 판을 뒤집었다.


🧑‍🔧 개선 과정

 

1️⃣ Photos 이용하기

 

loadTransferable을 이용하지 말고, PHAsset으로 얻은 후, AVAsset으로 변환을 진행해보자.

이러면, 가장 문제였던 복사가 따로 필요가 없다.

 

여기서 두개의 브레이크 포인트가 발생한다.

  func getPHAsset(from item: PhotosPickerItem) async throws -> PHAsset {
    guard let identifier = item.itemIdentifier
    else {
      throw PhotosPickerItemTransformerError.failedToLoadData
    }

    let result = PHAsset.fetchAssets(
      withLocalIdentifiers: [identifier],
      options: nil
    )

    guard let asset = result.firstObject else {
      throw PhotosPickerItemTransformerError.failedToLoadData
    }

    return asset
  }

 

2️⃣ identifier 실종

 

getPHAsset함수에서 첫번 째 guard문에 걸렸다.

결과는 identifier가 nil로 오는데 이유는 굉장히 어이 없었다.

 

바로 photosPicker에 photoLibrary를 명시해주지 않았던게 이유였다.

    .photosPicker(
      isPresented: $viewModel.showPhotosPicker,
      selection: .init(get: {
        []
      }, set: {
        if let item = $0.first {
          viewModel.send(.didSelectVideo(item, router))
        }
      }),
      maxSelectionCount: 1,
      matching: .videos,
      photoLibrary: .shared() // 이게 없었음
    )

 

3️⃣ firstObject 실종

 

초반에 이상하게 느겼던, 권한 문제가 여기에 영향을 줬다.

권한을 물어보지 않았기 때문에, PHFetchResult<PHAsset>에 object 정보가 전달되지 못했다.

 

4️⃣ 변환

마지막으로 PHAsset에서 AVAsset으로 변환하면 끝

  public func transform(_ item: PhotosPickerItem) async throws -> AVAsset {
    let asset = try await getPHAsset(from: item)

    return try await withCheckedThrowingContinuation { continuation in
      let options = PHVideoRequestOptions()
      options.version = .current
      options.deliveryMode = .mediumQualityFormat

      manager.requestAVAsset(forVideo: asset, options: options) { avAsset, _, _ in
        if let avAsset = avAsset {
          continuation.resume(returning: avAsset)
        } else {
          continuation.resume(throwing: PhotosPickerItemTransformerError.failedToLoadData)
        }
      }
    }
  }

 

✅ 개선 결과

 

처음보다 3배는 긴 1분 30초 영상을 골랐을 떄, 20초는 커냥 3초도 안걸려서 로드에 성공했다..

그 말은, 영상 길이가 길어질수록 이번 개선의 영향을 더 받는 다는 뜻이겠지..

 

너무 어이없지만, 그 만큼 기억에 더 남을 것 같아 같은 실수를 안할 것 같다..


출처

반응형

'iOS > SwiftUI' 카테고리의 다른 글

onScrollGeometryChange  (0) 2026.02.09
[WWDC2024] Create custom visual effects with SwiftUI  (0) 2025.11.19
PhotoPicker  (0) 2025.11.02
[WWDC 2023] Wind your way through advanced animations in SwiftUI  (0) 2025.10.30
[WWDC2023] Explore SwiftUI animation  (0) 2025.10.29
'iOS/SwiftUI' 카테고리의 다른 글
  • onScrollGeometryChange
  • [WWDC2024] Create custom visual effects with SwiftUI
  • PhotoPicker
  • [WWDC 2023] Wind your way through advanced animations in SwiftUI
Hamp
Hamp
남들에게 보여주기 부끄러운 잡다한 글을 적어 나가는 자칭 기술 블로그입니다.
  • Hamp
    Hamp의 분리수거함
    Hamp
  • 전체
    오늘
    어제
    • 분류 전체보기 (339)
      • CS (30)
        • 객체지향 (2)
        • Network (7)
        • OS (6)
        • 자료구조 (1)
        • LiveStreaming (3)
        • 이미지 (1)
        • 잡다한 질문 정리 (0)
        • Hardware (2)
        • 이론 (6)
        • 컴퓨터 그래픽스 (0)
      • Firebase (3)
      • Programing Langauge (41)
        • swift (34)
        • python (6)
        • Kotlin (1)
      • iOS (134)
        • UIKit (37)
        • Combine (1)
        • SwiftUI (34)
        • Framework (7)
        • Swift Concurrency (22)
        • Tuist (6)
        • Setting (11)
        • Modularization (1)
        • Instruments (6)
      • PS (59)
        • 프로그래머스 (24)
        • 백준 (13)
        • LeetCode (19)
        • 알고리즘 (3)
      • Git (18)
        • 명령어 (4)
        • 이론 (2)
        • hooks (1)
        • config (2)
        • action (7)
      • Shell Script (2)
      • Linux (6)
        • 명령어 (5)
      • Spring (21)
        • 어노테이션 (6)
        • 튜토리얼 (14)
      • CI-CD (4)
      • Android (0)
        • Jetpack Compose (0)
      • AI (21)
        • 이론 (10)
        • MCP (1)
        • LangGraph (10)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    dispatch
    IOS
    CS
    GIT
    lifecycle
    SwiftUI
    concurrency
    UIKit
    AVFoundation
    백준
    dp
    프로그래머스
    Swift
    protocol
    투포인터
    Tuist
    Spring
    dfs
    boostcamp
    property
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.0
Hamp
photoPicker에서 AVAsset 추출하기
상단으로

티스토리툴바