[iOS] File System

Hyunndy·2023년 2월 24일
2

iOS-Data

목록 보기
1/2

🐸

최근에 회사에서 동영상을 다운로드해서 저장해주세요. 라는 요구사항을 받았는데, 생각해보니 iOS FileSystem에 대해 잘 모르는것 같아서 정리해보겠습니다.

iOS File System Basics


개요

파일 시스템은 운영체제에서 제공하는 파일 시스템 구조로, 데이터 파일, 앱, 운영체제 파일 등을 저장하고 관리하는 역할을 합니다.
파일 시스템은 모든 프로세스에서 필요로 하며, 이를 통해 다양한 작업을 할 수 있습니다.
파일 시스템은 앱 및 운영체제의 성능 및 안정성을 유지하는데 매우 중요한 역할을 하며, 이를 통해 파일 및 데이터를 효율적으로 저장하고 관리할 수 있습니다.

iOS, macOS에서는 APFS라는 기본 파일 시스템을 사용합니다.
(Apple File System 인 것 같져?)

파일의 포맷과 상관없이 iOS 기기에 연결되어 있는 모든 디스크(물리적으로 꼽혀있는 USB라던지, 네트워크를 통해 연결된 저장소 던지 모두)는 하나의 파일 Collection을 만들기 위해 쌓입니다.
이런식으로 계속 쌓이면 너무 많아지겠죠..? 정리가 필요하겠죠?
그래서 APFS은 디렉토리라는 개념을 사용해서 계층 구조를 만듭니다.

APFS에 접근하는 코드를 짜기전에, 개발자는 APFS의 조직 및 코드에 적용되는 규칙을 이해하고 있어야 합니다.
앱은 적절한 보안 권한이 없는 디렉토리에 파일을 쓸 수 없으며, 적절한 위치에 파일을 놓아야 합니다.
(이 '놓는다'는 표현이.. 디렉토리에 파일을 저장한다는 의미겠죠?? 🤔)

파일을 정확히 어디에 놓을지(어느 디렉토리??)는 플랫폼에 따라 다르지만,
전반적인 목표는 2가지 입니다.

  • 사용자의 파일이 쉽게 찾을 수 있도록 유지하고
  • 코드에서 내부적으로 사용하는 파일이 사용자의 방해를 받지 않도록 하는 것

iOS File System

iOS 파일 시스템은 독립적으로 실행되는 앱을 위해 최적화 되어있습니다.
시스템을 심플하게 유지하기 위해 iOS 기기 사용자는 파일 시스템에 직접적으로 접근할 수 없습니다.
이런 규칙을 애플이 세웠기 때문에, 앱 또한 이 규칙을 따라야합니다.

iOS Standard Directories: Where Files Reside(파일이 놓이는 위치)

파일 시스템과 iOS 앱의 상호작용은 보안상의 이슈로 앱의 SandBox 디렉토리 안에 있는 내부 디렉토리로 제한됩니다.
App을 설치할 때, installer는 SandBox 디렉토리 내부에 앱을 위한 여러 Container 디렉토리를 생성합니다.
각 Container 디렉토리는 각자 역할이 있습니다.

  1. Bundle Container Directory
  • App Bundle을 보관합니다.
  1. Data Container Directory
  • 앱과 사용자 둘 다 사용할 수 있는 데이터를 보관합니다.
  • 앱이 데이터를 정리하고 구성하는 데 사용할 수 있는 여러 하위 디렉토리로 더 나눌 수 있습니다.

앱은 런타임에 추가적인 Container 디렉토리에 대한 액세스 권한을 요청할 수 있습니다.
(Ex. iCloud 컨테이너 같은)
이 Container 디렉토리들은 앱이 파일 시스템을 볼 수 있는 주요한 영역입니다.

그니까 제가 알고있던 파일 시스템 영역들은 다 Data Container Directory 였군요!


iOS 앱은 일반적으로 앱 자신의 Container 디렉터리 외부에 파일을 생성하거나 접근하는것이 금지되어있습니다.
하지만! 예외적으로 앱이 사용자의 연락처나 음악 같은 것에 접근하려는 경우, System 프레임워크는 Helper(??)를 사용해서 해당 데이터 스토어(연락처, 음악이 있는)에서 읽거나 수정하는데 필요한 파일 관련 작업을 처리할 수 있게 합니다.

👩‍💻 다음 표는 SandBox 디렉토리 내의 일부 중요한 하위 디렉토리들을 설명합니다. (이 글의하이라이트)

Commonly used directories of an iOS App

DirectoryUsage접근
AppName.appApp의 Bundle 입니다. App과 App의 모든 리소스가 들어있습니다.
주로 앱에서 사용하는 이미지, 음악 파일, 앱 아이콘 등 입니다.
이 디렉토리는 write 할 수 없습니다.
조작을 방지하기위해 Bundle 디렉토리는 install time에 서명됩니다.
이 디렉토리에 write하면 서명이 변경되어 앱을 시작할 수 없습니다.
그러나 앱 번들에 저장된 모든 리소스에 대한 read-only 접근은 가능합니다!
이 디렉토리의 내용은 iTunes, iCloud에 의해 백업되지 않습니다.
하지만 iTunes는 앱 스토어에서 구매한 앱의 초기 동기화를 수행합니다 (??)
write 불가
모든 리소스에 read-only 가능
Documents/사용자가 앱에서 생성한 컨텐츠를 저장하는 데 사용됩니다.
주로 사용자가 앱에서 생성한 문서, 이미지, 동영상 등의 파일을 저장합니다.
이 디렉토리의 내용은 파일 공유를 통해 다른 사용자에게 공유 될 수 있으므로,
다른 사용자에게 노출하고자 하는 파일만 포함해야 합니다.
이 디렉토리의 내용은 iTunes, iCloud에 백업 됩니다.
write, read, sharing 모두 가능
Documents/Inbox외부 Entity가 앱에서 열도록 요청한 파일에 엑세스하는데 사용됩니다.
특히, 메일 프로그램은 앱과 관련된 이메일 첨부 파일을 이 디렉토리에 놓습니다. 문서 상호작용 컨트롤러도 이 디렉토리에 파일을 놓을 수 있습니다.
앱은 이 디렉터리의 파일을 read, delete할 수 있지만 create 나 edit 할 수는 없습니다.
사용자가 이 디렉터리의 파일을 edit 하려고 시도하면, 앱은 파일을 수정하기 전에 파일을 디렉터리에서 먼저 이동시켜야 합니다.
이 디렉터리의 내용은 iTunes 및 iCloud에 의해 백업됩니다.
read, delete 가능
create, edit 불가
Library/사용자의 데이터 파일이 아닌 다른 모~든 파일의 파일의 최상위 디렉토리입니다.
예를들어 Cache, Preferences, 앱 데이터베이스 등을 저장합니다.
iOS 앱에서는 Application Support 및 Cashes 하위 디렉토리를 자주 사용하지만, 사용자의 데이터 파일에는 이 디렉토리를 사용하면 안됩니다!!!!
Cashes 서브디렉토리를 제외한 라이브러리 디렉토리의 컨텐츠는 iTunes 및 iCloud에 의해 백업됩니다.
tmp/앱이 실행되는 동안에만 필요한 일시적인 파일들을 저장하는데 사용됩니다.
앱이 종료되면 이 디렉토리의 내용은 자동으로 삭제됩니다.
하지만 시스템은 앱이 실행중이 아닐 때 이 디렉토리를 정리할 수 있습니다.
이 디렉토리의 내용은 iTunes나 iCloud에 백업되지 않습니다.

iOS 앱은 Documents, Library, temp 디렉토리에 추가 디렉토리를 생성할 수 있습니다.

Where You Should Put Your App’s Files

저장하려는 파일을 어느 디렉토리에 저장해야 할까요?

앱에서 큰 파일을 저장하는 경우 백업 작업(iTunes, iCloud)이 느려질 수 있으며 사용 가능한 저장 공간을 많이 소비하여 사용자가 앱을 삭제하거나 iCloud에서 해당 앱의 데이터 백업을 비활성화 할 가능성이 있습니다.
따라서 이 지침을 따라야 합니다!

1️⃣ Documents/ 디렉토리

사용자 데이터를 Documents/ 디렉토리에 저장하세요!!

👩‍💻 사용자 데이터란..?
개발자가 사용자에게 노출시키고 싶은 파일로, 사용자가 create, import, delete, edit 할 수 있는 모든 파일을 의미합니다.
예를 들어 drawing 앱의 경우, 사용자 데이터는 사용자가 만든 그래픽 파일이 포함됩니다. Text Editor의 경우엔 text 파일이 포함되고, 비디오, 오디오 앱은 사용자가 다운로드한 파일을 포함할 수 있습니다.

👩‍💻 잠깐!
하지만 "앱에서 다운로드한 비디오를 사용자가 본다" 라고 했을 때
사용자가 파일앱에 들어가서 비디오를 찾을까요? 갤러리에 들어가서 찾을까요?
전 일단 갤러리에서 찾습니다.

근데 제가 만든 앱과.. 갤러리 앱은 다른 앱이잖아요?
SandBox 개념으로 봤을 때 제가 만든 앱에서 갤러리 앱에 직접적으로 파일을 "추가" 할 수는 없을 것 같단말이죠.
그럼 어떻게 해야할까요?

이론적으로 본다면
1. URL을 통해 네트워크로부터 비디오 파일을 다운로드 받는다.
2. 다운로드가 완료되면 그 파일을 Documents 디렉토리에 저장한다.
3. PHPhotoLibrary를 사용하여 앱의 Documents 디렉토리에 저장된 비디오 파일을 갤러리에 저장한다!
요런식으로 진행하면 됩니다.

import Photos

// ... 비디오 다운로드 코드 ...

// 다운로드가 완료되면 호출되는 함수
func downloadDidFinish(url: URL) {
    // 저장할 asset 생성
    PHPhotoLibrary.shared().performChanges({
        PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url)
    }) { saved, error in
        if saved {
            print("비디오가 갤러리에 저장되었습니다.")
        } else {
            print("비디오 저장 중 오류가 발생했습니다: \(error?.localizedDescription)")
        }
    }
}

코드로 본다면 이런식이 되겠네요.
까먹기 쉬운 한 가지 철칙은

iOS 보안 모델은 앱 간 데이터 공유를 금지하며, 앱은 자체적으로 파일을 다룰 수 있는 지정된 디렉토리에만 접근 할 수 있다

는 것입니다.!!

2️⃣ Library/Application Support 디렉토리

Library/Application Support 디렉토리에 app-created(앱에서 생성된) 지원 파일을 넣으세요.
일반적으로 이 디렉토리는 앱이 실행하는 데 필요하지만 사용자에겐 숨겨야 하는 파일이 포함됩니다.
예를들면 데이터 파일, 구성 파일, 템플릿 및 앱 번ㄴ들에서 로드된 리소스의 수정 버전도 들어갑니다.

👩‍💻 불필요한 백업을 막기위해 Documents/ 와 Library/Application Support에 저장되는 파일들은 기본적으로 백업이 된다는걸 기억해야 합니다.
재생산되거나 다운로드 가능한 파일이라면 백업에서 제외하는 것이 좋습니다. 이는 특히!! 큰 크기의 미디어 파일에 대해서 중요합니다.
NSURLIsExcludedFromBackupKey 속성을 이용해서 백업 대상에서 제외할 수 있습니다.

3️⃣ tmp/ 디렉토리

temp/ 디렉토리에 일시적인 데이터를 저장하세요.
일시적인 데이터는 오래 지속되지 않아도 되는 모든 데이터를 의미합니다.
iOS는 앱이 실행 중이지 않을 때 주기적으로 이 디렉터리의 파일을 제거하므로, 앱이 종료되면 이런 파일들이 지속되지 않을 수 있습니다.

4️⃣ Library/Caches/ 디렉토리

Library/Caches/ 디렉토리에 데이터 cache 파일을 저장하세요.
cache 데이터는 temp 데이터보다는 오래 지속되어야 하는 데이터에 사용할 수 있습니다.
일반적으로 앱은 cache가 필요하진 않지만, cache를 통해 성능을 향상시킬 수 있습니다.
cache 데이터의 예시로는 DB Cache 파일이나 일시적으로 다운로드한 컨텐츠 등이 있습니다.
단, 시스템이 디스크 공간 확보를 위해 Caches/ 디렉토리를 삭제할 수 있으므로 앱은 필요에 따라 다시 만들거나 다운로드할 수 있어야 합니다.

How the System Identifies the Type of Content in a File

파일 시스템은 어떻게 File 안에 컨텐츠의 유형을 식별할 수 있을까요?
파일의 컨텐츠 유형을 식별하기 위한 2가지 스킬이 있습니다.

  • Uniform Type Identifiers (UTIs)
  • FileName Extensions

UTI(Uniform Type Identifier)는 타입(Type)을 가진 entity 클래스를 식별하는 고유 식별자 문자열입니다.
UTI는 모든 앱과 서비스에서 인식&의존할 수 있는 데이터에 대한 일관된 식별자를 제공합니다.
파일과 디렉토리 뿐만 아니라 모든 유형의 데이터를 나타내는데 쓸 수 있습니다.
예시)

  • public.text - 텍스트 데이터를 식별하는 공개 타입
  • public.jpeg - JPEG 이미지 데이터를 식별하는 공개 타입
  • com.apple.bundle - 번들 디렉토리를 식별하는 Apple 타입
  • com.apple.application-bundle - 번들화된 앱을 식별하는 Apple 타입

음 근데 iOS에서 UTIS는 붙여넣기 type에서만 사용된다고 합니다(뭔말이지)

Security: Protect the Files You Create

모든 유저 데이터와 시스템 코드가 디스크 어딘가에 저장되어있기 때문에 파일과 파일시스템의 무결성을 보호하는것은 매우 중요한 작업입니다.
다른 프로세스로부터 컨텐츠를 보호할 수 있는 방법들이 있습니다.

Sandboxes Limit the Spread of Damage

SandBox는 앱이 쓰지말아야할 파일 시스템의 일부에 쓰는것을 방지합니다.
각 SandBox 앱은 하나 이상의 컨테이너를 받아들일 수 있으며 해당 컨테이너에만 쓸 수 있습니다.

앱은 다른 앱의 컨테이너나 SandBox 외부의 대부분의 디렉토리에 쓸 수 없습니다.
iOS 개발자들은 iOS가 앱을 설치할 때 자동으로 앱을 SandBox에 두기 때문에 명시적으로 앱을 SandBox에 넣을 필요가 없습니다.

Permissions and Access Control Lists Govern All Access to Files

iOS 앱에서 파일 시스템에 접근하기 위해서는 그에 맞는 접근 권한이 필요합니다.
iOS 앱은 항상 SandBox 내부에서 실행되기 때문에 시스템은 각 앱에의해 생성된 파일에 ACLS나 허가 파일을 할당할 수 있습니다.

Files Can Be Encrypted On Disk

디스크에 있는 파일들은 모두 암호화 될 수 있다.
iOS앱은 디스크에 암호화된 파일을 지정할 수 있으며 사용자가 암호화된 파일이 있는 기기를 잠금해제하면, 시스템은 앱이 암호화된 파일에 접근할 수 있도록 복호화된 키를 생성한다. 근데 사용자가 다시 기기를 잠그면 복호화된 키는 파괴된다.

Files, Concurrency, and Thread Safety

파일, 동시성, 스레드 안정성

파일 관려 작업은 하드 디스크와의 상호작용을 필요로 하기 때문에 느립니다.
따라서 iOS는 대부분의 파일 관련 인터페이스를 동시성을 고려해서 설계했습니다.
몇 가지 기술은 비동기 작업을 설계에 통합하고 있으며, 대부분의 다른 기술은 디스패치 큐나 보조 스레드에서 안전하게 실행할 수 있습니다.

NSFileManager

FileManager는 대부분의 경우 여러 백그라운드 스레드에서 동시에 사용해도 안전합니다.
하지만 FileManager의 delegate로 작업할 때는 고유 인스턴스 생성하고 하나의 스레드에서만 사용하세요.

(원본에 다른 테크닉들이 있는데... 정리 안하겠습니다)

아무튼 이렇게 스레드 안정성을 위한 인터페이스를 사용해도 같은 파일에 여러 스레드나 프로세스가 동시에 접근하면 문제가 생길 수 밖에 없습니다. 이럴 때는 File Coordinators를 사용해서 파일에 대한 액세스를 관리해야 한다고 합니다.


마무리

애플 공식문서를 읽는건 언제나 참 힘드네요...

그래도 앱이 SandBox내에 크게
1. Bundle Container 디렉토리 2. Data 컨테이너 디렉토리 3. iCloud 컨테이너 디렉터리 etc
가 있고
Data 컨테이너 디렉토리 안에 익숙한
Documents, Library (App Support, Cache), tmp 가 있는건 확실히 알았네요.

왜 동영상 파일을 직접 갤러리에 다운받지못하고 도큐먼트에 저장 후에 그걸 다시 이동시켜야 하는지도 이해됐습니다!

profile
https://hyunndyblog.tistory.com/163 티스토리에서 이사 중

0개의 댓글