Apple 플랫폼에서 Cloud Storage로 파일 업로드

Cloud Storage for Firebase를 사용하면 Firebase에서 제공하고 관리하는 Cloud Storage 버킷에 파일을 빠르고 손쉽게 업로드할 수 있습니다.

참조 만들기

파일을 업로드하려면 먼저 Cloud Storage에서 파일을 업로드할 위치를 가리키는 Cloud Storage 참조를 만듭니다.

Cloud Storage 버킷의 루트에 하위 경로를 추가하여 참조를 만들 수 있습니다.

Swift

// Create a root reference
let storageRef = storage.reference()

// Create a reference to "mountains.jpg"
let mountainsRef = storageRef.child("mountains.jpg")

// Create a reference to 'images/mountains.jpg'
let mountainImagesRef = storageRef.child("images/mountains.jpg")

// While the file names are the same, the references point to different files
mountainsRef.name == mountainImagesRef.name            // true
mountainsRef.fullPath == mountainImagesRef.fullPath    // false
    

Objective-C

// Create a root reference
FIRStorageReference *storageRef = [storage reference];

// Create a reference to "mountains.jpg"
FIRStorageReference *mountainsRef = [storageRef child:@"mountains.jpg"];

// Create a reference to 'images/mountains.jpg'
FIRStorageReference *mountainImagesRef = [storageRef child:@"images/mountains.jpg"];

// While the file names are the same, the references point to different files
[mountainsRef.name isEqualToString:mountainImagesRef.name];         // true
[mountainsRef.fullPath isEqualToString:mountainImagesRef.fullPath]; // false
  

Cloud Storage 버킷의 루트를 가리키는 참조로는 데이터를 업로드할 수 없습니다. 참조는 하위 URL을 가리켜야 합니다.

파일 업로드

참조가 만들어졌으면 2가지 방법으로 Cloud Storage에 파일을 업로드할 수 있습니다.

  1. 메모리 데이터에서 업로드
  2. 기기의 파일을 나타내는 URL에서 업로드

메모리 데이터에서 업로드

putData:metadata:completion: 메서드는 Cloud Storage에 파일을 업로드하는 가장 간단한 방법입니다. putData:metadata:completion:은 NSData 객체를 취하고 FIRStorageUploadTask를 반환하며, 이를 사용하여 업로드를 관리하고 업로드 상태를 모니터링할 수 있습니다.

Swift

// Data in memory
let data = Data()

// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")

// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putData(data, metadata: nil) { (metadata, error) in
  guard let metadata = metadata else {
    // Uh-oh, an error occurred!
    return
  }
  // Metadata contains file metadata such as size, content-type.
  let size = metadata.size
  // You can also access to download URL after upload.
  riversRef.downloadURL { (url, error) in
    guard let downloadURL = url else {
      // Uh-oh, an error occurred!
      return
    }
  }
}
    

Objective-C

// Data in memory
NSData *data = [NSData dataWithContentsOfFile:@"rivers.jpg"];

// Create a reference to the file you want to upload
FIRStorageReference *riversRef = [storageRef child:@"images/rivers.jpg"];

// Upload the file to the path "images/rivers.jpg"
FIRStorageUploadTask *uploadTask = [riversRef putData:data
                                             metadata:nil
                                           completion:^(FIRStorageMetadata *metadata,
                                                        NSError *error) {
  if (error != nil) {
    // Uh-oh, an error occurred!
  } else {
    // Metadata contains file metadata such as size, content-type, and download URL.
    int size = metadata.size;
    // You can also access to download URL after upload.
    [riversRef downloadURLWithCompletion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
      if (error != nil) {
        // Uh-oh, an error occurred!
      } else {
        NSURL *downloadURL = URL;
      }
    }];
  }
}];
  

로컬 파일에서 업로드

putFile:metadata:completion: 메서드를 사용하여 카메라의 사진 및 동영상과 같은 로컬 파일을 기기에 업로드할 수 있습니다. putFile:metadata:completion:NSURL을 취하고 FIRStorageUploadTask를 반환하며, 이를 사용하여 업로드를 관리하고 업로드 상태를 모니터링할 수 있습니다.

Swift

// File located on disk
let localFile = URL(string: "path/to/image")!

// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")

// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putFile(from: localFile, metadata: nil) { metadata, error in
  guard let metadata = metadata else {
    // Uh-oh, an error occurred!
    return
  }
  // Metadata contains file metadata such as size, content-type.
  let size = metadata.size
  // You can also access to download URL after upload.
  riversRef.downloadURL { (url, error) in
    guard let downloadURL = url else {
      // Uh-oh, an error occurred!
      return
    }
  }
}
    

Objective-C

// File located on disk
NSURL *localFile = [NSURL URLWithString:@"path/to/image"];

// Create a reference to the file you want to upload
FIRStorageReference *riversRef = [storageRef child:@"images/rivers.jpg"];

// Upload the file to the path "images/rivers.jpg"
FIRStorageUploadTask *uploadTask = [riversRef putFile:localFile metadata:nil completion:^(FIRStorageMetadata *metadata, NSError *error) {
  if (error != nil) {
    // Uh-oh, an error occurred!
  } else {
    // Metadata contains file metadata such as size, content-type, and download URL.
    int size = metadata.size;
    // You can also access to download URL after upload.
    [riversRef downloadURLWithCompletion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
      if (error != nil) {
        // Uh-oh, an error occurred!
      } else {
        NSURL *downloadURL = URL;
      }
    }];
  }
}];
  

업로드를 적극적으로 관리하려면 완료 핸들러를 사용하는 대신 putData: 또는 putFile: 메서드를 사용하고 업로드 작업을 관찰합니다. 자세한 내용은 업로드 관리를 참조하세요.

파일 메타데이터 추가

파일을 업로드할 때 메타데이터를 포함할 수도 있습니다. 이 메타데이터는 name, size, contentType(통칭 MIME 유형) 등 일반적인 파일 메타데이터 속성을 포함합니다. putFile: 메서드를 사용하면 NSURL 파일 이름 확장자에서 콘텐츠 유형이 자동으로 추론되지만, 메타데이터에 contentType을 지정하면 자동 감지된 유형을 재정의할 수 있습니다. contentType을 지정하지 않았고 Cloud Storage가 파일 확장자에서 기본값을 추론할 수 없는 경우에는 Cloud Storageapplication/octet-stream을 사용합니다. 파일 메타데이터에 대한 자세한 내용은 파일 메타데이터 사용 섹션을 참고하세요.

Swift

// Create storage reference
let mountainsRef = storageRef.child("images/mountains.jpg")

// Create file metadata including the content type
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"

// Upload data and metadata
mountainsRef.putData(data, metadata: metadata)

// Upload file and metadata
mountainsRef.putFile(from: localFile, metadata: metadata)
    

Objective-C

// Create storage reference
FIRStorageReference *mountainsRef = [storageRef child:@"images/mountains.jpg"];

// Create file metadata including the content type
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = @"image/jpeg";

// Upload data and metadata
FIRStorageUploadTask *uploadTask = [mountainsRef putData:data metadata:metadata];

// Upload file and metadata
uploadTask = [mountainsRef putFile:localFile metadata:metadata];
  

업로드 관리

업로드 시작 외에도 pause, resume, cancel 메서드를 사용하여 업로드를 일시중지, 재개, 취소할 수 있습니다. 이 메서드는 pause, resume, cancel 이벤트를 발생시킵니다. 업로드를 취소하면 업로드 취소를 알리는 오류와 함께 업로드가 실패합니다.

Swift

// Start uploading a file
let uploadTask = storageRef.putFile(from: localFile)

// Pause the upload
uploadTask.pause()

// Resume the upload
uploadTask.resume()

// Cancel the upload
uploadTask.cancel()
    

Objective-C

// Start uploading a file
FIRStorageUploadTask *uploadTask = [storageRef putFile:localFile];

// Pause the upload
[uploadTask pause];

// Resume the upload
[uploadTask resume];

// Cancel the upload
[uploadTask cancel];
  

업로드 진행률 모니터링

업로드 진행률을 모니터링하려면 FIRStorageUploadTask에 관찰자를 연결합니다. 관찰자를 추가하면 관찰자를 삭제하는 데 사용할 수 있는 FIRStorageHandle이 반환됩니다.

Swift

// Add a progress observer to an upload task
let observer = uploadTask.observe(.progress) { snapshot in
  // A progress event occured
}
    

Objective-C

// Add a progress observer to an upload task
FIRStorageHandle observer = [uploadTask observeStatus:FIRStorageTaskStatusProgress
                                              handler:^(FIRStorageTaskSnapshot *snapshot) {
                                                // A progress event occurred
                                              }];
  

이러한 관찰자를 FIRStorageTaskStatus 이벤트에 추가할 수 있습니다.

FIRStorageTaskStatus 이벤트 일반적인 용도
FIRStorageTaskStatusResume 이 이벤트는 업로드가 시작되거나 재개될 때 발생하며, 일반적으로 FIRStorageTaskStatusPause 이벤트와 함께 사용됩니다.
FIRStorageTaskStatusProgress 이 이벤트는 Cloud Storage에 데이터가 업로드될 때 항상 발생하며 업로드 진행률 표시기에 데이터를 입력하는 데 사용할 수 있습니다.
FIRStorageTaskStatusPause 이 이벤트는 업로드가 일시중지될 때마다 발생하며 일반적으로 FIRStorageTaskStatusResume 이벤트와 함께 사용됩니다.
FIRStorageTaskStatusSuccess 이 이벤트는 업로드가 정상적으로 완료되었을 때 발생합니다.
FIRStorageTaskStatusFailure 이 이벤트는 업로드가 실패했을 때 발생합니다. 오류를 검사하여 실패 원인을 파악하세요.

이벤트가 발생하면 FIRStorageTaskSnapshot 객체가 다시 전달됩니다. 이 스냅샷은 이벤트 발생 시점의 작업 상태로서 변경이 불가능합니다. 이 객체는 다음과 같은 속성을 포함합니다.

속성 유형 설명
progress NSProgress 업로드 진행률이 포함된 NSProgress 객체입니다.
error NSError 업로드 중에 발생한 오류입니다(발생한 경우).
metadata FIRStorageMetadata 업로드 중에는 업로드되는 메타데이터를 포함합니다. FIRTaskStatusSuccess 이벤트 후에는 업로드된 파일의 메타데이터를 포함합니다.
task FIRStorageUploadTask 스냅샷 대상 작업으로서 작업을 관리(pause, resume, cancel)하는 데 사용할 수 있습니다.
reference FIRStorageReference 이 작업이 유래된 참조입니다.

관찰자를 하나씩 삭제하거나, 상태별로 삭제하거나, 모두 삭제할 수도 있습니다.

Swift

// Create a task listener handle
let observer = uploadTask.observe(.progress) { snapshot in
  // A progress event occurred
}

// Remove an individual observer
uploadTask.removeObserver(withHandle: observer)

// Remove all observers of a particular status
uploadTask.removeAllObservers(for: .progress)

// Remove all observers
uploadTask.removeAllObservers()
    

Objective-C

// Create a task listener handle
FIRStorageHandle observer = [uploadTask observeStatus:FIRStorageTaskStatusProgress
                                              handler:^(FIRStorageTaskSnapshot *snapshot) {
                                                // A progress event occurred
                                              }];

// Remove an individual observer
[uploadTask removeObserverWithHandle:observer];

// Remove all observers of a particular status
[uploadTask removeAllObserversForStatus:FIRStorageTaskStatusProgress];

// Remove all observers
[uploadTask removeAllObservers];
  

메모리 누수를 방지하기 위해 FIRStorageTaskStatusSuccess 또는 FIRStorageTaskStatusFailure가 발생한 후 모든 관찰자가 삭제됩니다.

오류 처리

업로드 시 로컬 파일이 없는 경우, 사용자에게 원하는 파일을 업로드할 권한이 없는 경우 등 다양한 이유로 오류가 발생할 수 있습니다. 오류의 자세한 내용은 문서의 오류 처리 섹션을 참조하세요.

전체 예시

다음은 진행률 모니터링 및 오류 처리를 포함하는 업로드를 보여주는 예시입니다.

Swift

// Local file you want to upload
let localFile = URL(string: "path/to/image")!

// Create the file metadata
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"

// Upload file and metadata to the object 'images/mountains.jpg'
let uploadTask = storageRef.putFile(from: localFile, metadata: metadata)

// Listen for state changes, errors, and completion of the upload.
uploadTask.observe(.resume) { snapshot in
  // Upload resumed, also fires when the upload starts
}

uploadTask.observe(.pause) { snapshot in
  // Upload paused
}

uploadTask.observe(.progress) { snapshot in
  // Upload reported progress
  let percentComplete = 100.0 * Double(snapshot.progress!.completedUnitCount)
    / Double(snapshot.progress!.totalUnitCount)
}

uploadTask.observe(.success) { snapshot in
  // Upload completed successfully
}

uploadTask.observe(.failure) { snapshot in
  if let error = snapshot.error as? NSError {
    switch (StorageErrorCode(rawValue: error.code)!) {
    case .objectNotFound:
      // File doesn't exist
      break
    case .unauthorized:
      // User doesn't have permission to access file
      break
    case .cancelled:
      // User canceled the upload
      break

    /* ... */

    case .unknown:
      // Unknown error occurred, inspect the server response
      break
    default:
      // A separate error occurred. This is a good place to retry the upload.
      break
    }
  }
}
    

Objective-C

// Local file you want to upload
NSURL *localFile = [NSURL URLWithString:@"path/to/image"];

// Create the file metadata
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = @"image/jpeg";

// Upload file and metadata to the object 'images/mountains.jpg'
FIRStorageUploadTask *uploadTask = [storageRef putFile:localFile metadata:metadata];

// Listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Upload resumed, also fires when the upload starts
}];

[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Upload paused
}];

[uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Upload reported progress
  double percentComplete = 100.0 * (snapshot.progress.completedUnitCount) / (snapshot.progress.totalUnitCount);
}];

[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Upload completed successfully
}];

// Errors only occur in the "Failure" case
[uploadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
  if (snapshot.error != nil) {
    switch (snapshot.error.code) {
      case FIRStorageErrorCodeObjectNotFound:
        // File doesn't exist
        break;

      case FIRStorageErrorCodeUnauthorized:
        // User doesn't have permission to access file
        break;

      case FIRStorageErrorCodeCancelled:
        // User canceled the upload
        break;

      /* ... */

      case FIRStorageErrorCodeUnknown:
        // Unknown error occurred, inspect the server response
        break;
    }
  }
}];
  

이제 파일을 업로드했으니 Cloud Storage에서 파일을 다운로드하는 방법을 알아보겠습니다.