15

Is there a way to get the file size on disk of a PHAsset without doing requestImageDataForAsset or converting it to ALAsset? I am loading in previews of a user's photo library - potentially many thousands of them - and it's imperative to my app that they know the size before import.

Ryan Daulton
  • 1,159
  • 1
  • 11
  • 22

4 Answers4

30

You can grab the fileSize of a PHAsset and convert it to human readable form like this:

      let resources = PHAssetResource.assetResources(for: yourAsset) // your PHAsset

      var sizeOnDisk: Int64? = 0

      if let resource = resources.first {
        let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong
        sizeOnDisk = Int64(bitPattern: UInt64(unsignedInt64!))
      }

Then use your sizeOnDisk variable and pass it into a method like this...

func converByteToHumanReadable(_ bytes:Int64) -> String {
     let formatter:ByteCountFormatter = ByteCountFormatter()
     formatter.countStyle = .binary

     return formatter.string(fromByteCount: Int64(bytes))
 }
Ryan Daulton
  • 1,159
  • 1
  • 11
  • 22
4

SWIFT 5.0 Light & Easy:

private static let bcf = ByteCountFormatter()

func getSize(asset: PHAsset) -> String {
    let resources = PHAssetResource.assetResources(for: asset)

    guard let resource = resources.first,
          let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong else {
              return "Unknown"
          }

    let sizeOnDisk = Int64(bitPattern: UInt64(unsignedInt64))
    Self.bcf.allowedUnits = [.useMB]
    Self.bcf.countStyle = .file
    return Self.bcf.string(fromByteCount: sizeOnDisk)
}
Joshua Hart
  • 772
  • 1
  • 21
  • 31
2

A safer solution:

[asset requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput * _Nullable contentEditingInput, NSDictionary * _Nonnull info) {
    NSNumber *fileSize = nil;
    NSError *error = nil;
    [contentEditingInput.fullSizeImageURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:&error];
    NSLog(@"file size: %@\nerror: %@", fileSize, error);
}];

Swift version:

asset.requestContentEditingInput(with: nil) { (contentEditingInput, _) in
    do {
        let fileSize = try contentEditingInput?.fullSizeImageURL?.resourceValues(forKeys: [URLResourceKey.fileSizeKey]).fileSize
        print("file size: \(String(describing: fileSize))")
    } catch let error {
        fatalError("error: \(error)")
    }
}

Inspired by How to get an ALAsset URL from a PHAsset?

qiz
  • 869
  • 1
  • 9
  • 14
2

Please try this.

let resources = PHAssetResource.assetResources(for: YourAsset)
var sizeOnDisk: Int64 = 0

if let resource = resources.first {
   let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong
   sizeOnDisk = Int64(bitPattern: UInt64(unsignedInt64!))

   totalSize.text = String(format: "%.2f", Double(sizeOnDisk) / (1024.0*1024.0))+" MB"
}
Anna K.
  • 61
  • 4