728x90
SMALL
일기를 작성하는 화면에서,
사용자가 사진 앱 뿐만 아니라 *파일 앱(파일 보관함)*에서도
이미지를 선택해서 첨부할 수 있도록 구현하는 기능을 만들었다.
하지만 파일 앱에서 png/jpg 파일을 선택하면 다음과 같은 문제가 발생했다.
❗️문제 상황
1) 파일을 선택하면 콘솔에 아래와 같은 에러가 출력됨
Failed to associate thumbnails for picked URL ...
QLThumbnailErrorDomain Code=102
Generation not found
2) 파일을 선택한 후 컬렉션뷰(UIImage 목록)에 아무것도 표시되지 않음
사진 앱에서 선택하면 잘 나오는데,
파일 앱에서 선택한 이미지는 전혀 안 나타나는 문제가 있었다.
🔍 문제 원인 파악
문제의 핵심은 여기였다.
let coordinated = url.startAccessingSecurityScopedResource()
defer { url.stopAccessingSecurityScopedResource() }
guard coordinated else { return } // ❗️여기 때문에 전체 코드가 실행되지 않음
- 파일 앱이나 iCloud Drive 내에 있는 파일은
종종 security-scoped resource 접근 권한을 정확하게 가져오지 못하는 경우가 있음.
- 그런 경우 startAccessingSecurityScopedResource()가 false를 반환한다.
- 그러면 guard coordinated else { return }에 걸려서
아래 코드(Data 로드, UIImage 변환, appendImage)까지 실행되지 않는다.
즉, 컬렉션뷰에 이미지가 안 나오는 이유는
이미지 로드 자체가 아예 실행되지 않았기 때문!
❗️그럼 QLThumbnailErrorDomain 에러는?
이건 부가적인 에러 로그일 뿐, 기능에 직접적인 문제는 아니다.
파일 앱이 내부적으로 파일 썸네일을 만들다가 실패하는 로그일 뿐이며,
이미지를 읽어오는 기능 자체는 여전히 문제없이 가능하다.
✔️ 해결 방법
startAccessingSecurityScopedResource()는
“되면 좋고, 안 돼도 괜찮은 옵션”이라고 보면 된다.
그래서 아래와 같은 패턴으로 변경해주어야 한다.
func documentPicker(_ controller: UIDocumentPickerViewController,
didPickDocumentsAt urls: [URL]) {
guard let url = urls.first,
let cell = currentPhotoCell else { return }
// security-scoped permission 요청 (실패해도 괜찮음)
let coordinated = url.startAccessingSecurityScopedResource()
defer {
if coordinated { url.stopAccessingSecurityScopedResource() }
}
do {
let data = try Data(contentsOf: url)
if let originalImg = UIImage(data: data),
let image = originalImg.resized(maxWidth: 1200) {
// 성공적으로 이미지 추가
cell.appendImage(image)
} else {
showInvalidFileAlert()
}
} catch {
print("파일 로드 실패: \(error.localizedDescription)")
showInvalidFileAlert()
}
}
🔑 핵심 포인트 요약
| Before (문제 발생) | After (문제 해결) |
| guard coordinated else { return } 때문에 파일 로드가 아예 안 됨 | coordinated는 실패해도 상관 없이 이미지 로드 시도 |
| 파일 앱의 이미지가 대부분 coordinated = false | coordinated 실패해도 Data(contentsOf:)는 정상 동작 |
| 컬렉션뷰가 업데이트되지 않음 | appendImage가 정상 실행되어 UI 업데이트됨 |
728x90
LIST
'감정일기(가칭)' 카테고리의 다른 글
| 📑 DiaryEditor 유효성 검사 설계부터 UI 처리까지 (0) | 2025.11.18 |
|---|---|
| 📘 DiaryContentCell 리팩토링 기록 — 단일 String 통합 방식에서 → 구조체 기반 다중 필드 관리로 개선하기 (0) | 2025.11.17 |
| 📘 텍스트뷰가 키보드에 가리지 않도록 자동 스크롤하는 방법 (0) | 2025.11.14 |
| 커스텀 캘린더 만들기 구조 설계 (0) | 2025.11.10 |
| 커스텀 캘린더 ViewModel, 이렇게 만들면 됩니다 (CalendarViewModel 완전 해부) (0) | 2025.11.10 |