클라우드 Mac에서 iOS 문서 가져오기의 권한과 파일 수명 주기 검증하기

클라우드 Mac에서 iOS 문서 가져오기의 권한과 파일 수명 주기 검증하기

클라우드 Mac에서 iOS 앱을 디버깅할 때 흔히 하는 오판이 있다. ‘파일’ 앱에서 PDF를 선택해 미리보기가 열리면 가져오기가 끝났다고 생각하는 것이다. 하지만 앱이 외부 파일을 잠시 읽었을 뿐일 수 있다. 다음 실행 때 원래 경로에 접근할 수 없으면 읽기 기록도 열리지 않는다. 검증해야 할 것은 파일 선택기가 열리는지가 아니라, 외부 제공자의 파일을 받은 뒤 앱의 접근 권한, 파일의 소유 위치, 파일 수명 주기가 어떻게 처리되는지다.

이 글에서는 ‘PDF를 가져와 계속 읽기’를 예로 든다. 개발용 Mac에는 원격으로 접속할 수 있지만, 파일 접근 규칙은 실행 중인 앱이 있는 iOS 기기에서 결정된다. 가져오기 구현과 자동화 테스트를 먼저 구분하자. 구현은 실제 파일 선택기가 전달한 URL을 처리하고, 테스트는 앱이 소유한 사본과 실패 경로를 검증한다.

가져오기 완료 기준부터 정의하기

파일을 열 수 있다는 것과 파일을 소유한다는 것은 다르다. UIDocumentPickerViewController(forOpeningContentTypes: [.pdf], asCopy: false)를 사용할 때 콜백의 URL은 파일 선택기가 제공한 위치를 가리킨다. 이 URL을 영구 경로인 것처럼 읽기 기록에 바로 저장해서는 안 된다. 다음 실행 때도 열어야 한다면 접근 권한이 유효한 동안 원본을 읽어 앱의 영구 저장 디렉터리에 복사하고, 기록은 새 사본을 가리키게 해야 한다.

먼저 관찰 가능한 결과 세 가지를 정해 두자. 선택을 취소하면 기록이 추가되지 않아야 한다. 복사에 실패하면 ‘성공’ 기록이 추가되지 않아야 한다. 가져오기에 성공한 뒤에는 원본을 이동하고 앱을 다시 실행해도 앱의 사본을 열 수 있어야 한다. 임시 디렉터리는 한 번의 가져오기 작업을 처리하기에는 적합하지만 장기 보관용 서고로는 적합하지 않다. 기록을 오래 보관해야 한다면 검증을 마친 임시 사본을 Application Support 같은 앱의 영구 저장 디렉터리로 옮긴다.

가져오기 성공 여부는 파일 선택기가 URL을 반환한 순간이 아니라, 사본을 기록하고 검증한 뒤에 판단해야 한다.

접근 권한이 유효한 동안 조정된 복사 수행하기

파일 선택기 콜백에서 URL을 받으면 먼저 보안 범위 리소스 접근을 시작하고, NSFileCoordinator로 읽기를 조정한다. 아래 함수는 작고 단일한 PDF를 임시 저장하는 단계만 보여 준다. 호출하는 쪽에서 콘텐츠 검증, 영구 디렉터리로의 이동, 기록 갱신 방법을 별도로 결정해야 한다. 이 예제는 asCopy: false로 여는 경우를 전제로 하며, 모든 출처를 외부 접근 권한이 필요한 파일로 간주하는 범용 복사 함수가 아니다.

func stagePickedPDF(_ url: URL) throws -> URL {
    guard url.startAccessingSecurityScopedResource() else {
        throw CocoaError(.fileReadNoPermission)
    }
    defer { url.stopAccessingSecurityScopedResource() }

    let destination = FileManager.default.temporaryDirectory
        .appendingPathComponent(UUID().uuidString)
        .appendingPathExtension("pdf")
    var coordinationError: NSError?
    var copyError: Error?

    NSFileCoordinator().coordinate(
        readingItemAt: url,
        options: [],
        error: &coordinationError
    ) { readableURL in
        do {
            try FileManager.default.copyItem(
                at: readableURL,
                to: destination
            )
        } catch {
            copyError = error
        }
    }

    if let coordinationError { throw coordinationError }
    if let copyError { throw copyError }
    return destination
}

coordinate는 동기 호출이므로 큰 파일을 복사하느라 UI 스레드를 오래 점유하지 않도록 한다. 실제 구현에서는 ‘접근 시작—조정된 읽기—접근 종료’ 전체를 백그라운드 작업에서 처리할 수 있다. 콜백에서 먼저 접근을 종료한 뒤 외부 URL만 백그라운드 작업에 넘겨서는 안 된다. 오류가 나도 접근은 종료해야 하며, 여기서는 종료 코드를 여러 곳에 직접 넣는 것보다 defer를 사용하는 편이 확인하기 쉽다.

임시 파일을 복구 가능한 기록으로 확정하기

복사가 끝나면 사본이 존재하는지, 크기가 타당한지 확인하고 PDF 파서로 열어 본다. .pdf 확장자만으로는 내용이 올바른지 알 수 없다. 검증에 성공하면 파일을 앱의 영구 저장 디렉터리로 옮기고, 앱이 생성한 식별자를 사용해 상대 경로를 저장한다. 검증이나 이동에 실패하면 임시 파일을 삭제하고 사용자에게 재시도할 수 있는 오류를 보여 주되, 읽기 목록에는 항목을 추가하지 않는다.

영구 저장 과정에서는 ‘파일은 기록됐지만 읽기 기록은 저장되지 않은’ 중간 실패도 고려해야 한다. 먼저 커밋 대기 상태의 기록을 만들고, 파일 이동을 마친 뒤 사용 가능 상태로 표시할 수 있다. 앱 시작 시에는 완료되지 않은 기록을 검색해 해당 파일을 확인하고 잔여 항목을 정리한다. 구체적인 트랜잭션 방식은 앱의 데이터 저장 방식에 따라 달라지지만, 목표는 같다. 목록에 존재하지 않는 파일을 가리키는 항목이 없어야 한다.

파일 선택기가 제공한 표시 이름을 대상 경로에 그대로 붙이지 않는다. 앱이 생성한 파일명을 사용하고 원래 이름은 표시용 필드에 저장하면, 이름이 같은 파일의 덮어쓰기를 피하고 경로 문자로 인한 문제도 줄일 수 있다. 사본을 보관하는 대신 언제나 외부 원본을 읽어야 하는 제품이라면 접근 방식 자체가 다르다. 재승인 절차와 원본을 사용할 수 없을 때의 화면을 별도로 설계해야 하며, ‘로컬로 가져오기 완료’ 상태를 그대로 사용해서는 안 된다.

클라우드 Mac에서 단계별로 검증하기

먼저 XCTest에서 앱 샌드박스 안의 PDF 샘플을 가져오기 후 로직에 전달한다. 파싱 성공 여부, 손상된 파일의 오류 처리, 같은 이름의 파일을 덮어쓰지 않는지, 임시 파일을 삭제해도 목록이 영구 사본을 가리키는지 확인한다. 이 단계에서 보안 범위 접근 권한까지 검증했다고 해서는 안 된다. 샌드박스 샘플에는 대개 실제 파일 제공자의 접근 조건이 없다.

다음으로 시뮬레이터에서 전체 UI 흐름을 확인한다. ‘파일’ 선택기에 표시되는 PDF를 준비해 선택과 취소를 각각 실행한다. 가져온 뒤 앱을 종료하고 다시 실행해 읽기 기록을 열 수 있는지 확인한다. 이어 선택기에서 원본 파일을 옮겨 보고 앱이 실제로 자체 사본을 읽는지 살핀다. 자동화로 안정적으로 제어할 수 없는 파일 제공자의 동작은 수동 검증 항목으로 기록하고, 불확실성을 감추기 위해 정해진 시간만큼 기다리는 방식에 의존하지 않는다.

마지막으로 대상 기기와 실제 사용할 파일 제공자에서 권한 및 다운로드 동작을 재확인한다. 선택 시점에 문서가 로컬에 완전히 저장되지 않은 경우도 있다. 읽기에 실패하면 빈 사본을 만드는 대신 오류를 표시하고 다시 선택할 수 있게 해야 한다. 여기서 검증하는 것은 오류 처리이지, 파일 제공자의 다운로드 소요 시간을 보장하는 일이 아니다.

실패 사례 매트릭스로 마무리하기

작업 기대 결과
선택 취소 읽기 목록이 그대로이고 임시 파일도 남지 않음
원본을 읽을 수 없음 오류를 명확히 표시하고 성공 기록을 만들지 않음
사본 검증 실패 임시 파일을 정리하고 재시도 경로를 남김
가져온 뒤 원본 이동 앱을 다시 실행해도 앱의 사본을 열 수 있음
가져오는 도중 앱 중단 다음 실행 때 완료되지 않은 기록을 찾아 처리할 수 있음

검증 기록에는 사용한 파일 유형, 원본의 출처 유형, 시스템 및 앱 빌드 버전, 각 작업의 실제 결과를 함께 남기는 것이 좋다. 그래야 원격 데스크톱에서 문제를 재현할 때 같은 파일을 반복해서 선택하는 대신, 접근 권한, 조정된 읽기, 복사, 검증, 기록 확정 중 어느 단계에서 실패했는지 먼저 판단할 수 있다.

자주 묻는 질문

문서 선택기에서 받은 파일 경로를 저장해 나중에 다시 열어도 되나요?

외부 파일 경로를 영구적인 참조로 취급하지 마세요. 장기 사용이 필요하면 접근 권한이 유효할 때 앱의 영구 저장소로 복사하고, 이후에는 그 사본을 여세요.

시뮬레이터 테스트만으로 문서 가져오기를 검증할 수 있나요?

복사와 파싱, 오류 처리는 검증할 수 있지만 충분하지 않습니다. 실제 문서 선택기와 파일 제공자를 통해 권한, 선택 취소, 원본 이동 상황을 별도로 확인하세요.

XCZone · 클라우드 Mac

원격으로 접속할 독점 물리 Mac이 필요하신가요?

M4 Start, M4 Work, M4 Pro의 사양과 노드, 결제 주기를 비교하고 작업에 맞는 플랜을 선택하세요.

클라우드 Mac 플랜 보기