atirit
atirit

Reputation: 1574

Error: Ambiguous reference to member 'subscript' in Swift 3

I downloaded the Xcode 8 beta and converted my syntax to Swift 3. When I did, I got the eponymous error with this code (this didn't happen before):

Swift 3:

do {
    let fileAttributes = try FileManager.default().attributesOfItem(atPath: fileURL.path!) // Error here
    let fileSizeNumber = fileAttributes[NSFileSize] as! NSNumber
    fileSize = fileSizeNumber.longLongValue
} catch _ as NSError {
    print("Filesize reading failed")
}

Swift 2:

do {
    let fileAttributes = try NSFileManager.defaultManager().attributesOfItemAtPath(fileURL.path!)
    let fileSizeNumber = fileAttributes[NSFileSize] as! NSNumber
    fileSize = fileSizeNumber.longLongValue
} catch _ as NSError {
    print("Filesize reading failed")
}

Is this a bug in Swift 3, or am I missing something?

I know there are many questions about the same error, but those don't fix my problem. I'm happy to edit for clarification.

Thanks in advance!

Upvotes: 4

Views: 11935

Answers (3)

Eric Aya
Eric Aya

Reputation: 70119

I think something like this should work:

do {
    let fileAttributes = try FileManager.default().attributesOfItem(atPath: file.path!)
    if let fileSizeNumber = fileAttributes["NSFileSize"] as? NSNumber {
        let fileSize = fileSizeNumber.int64Value

    }
} catch let error as NSError {
    print("Filesize reading failed: \(error.debugDescription)")
}

Since NSFileSize was just a constant string I've replaced it by its raw value. It seems ok - but it would be better to find the official equivalent, of course (which I didn't manage to for now, so don't take this solution for granted, it's just a workaround).

Update for Xcode 8 GM:

Using FileAttributeKey.size is better than using the hardcoded constant (thanks @rudy for the reminder). Here's an updated example:

do {
    let attributes = try FileManager.default.attributesOfItem(atPath: file.path)
    if let size = attributes[FileAttributeKey.size] as? NSNumber {
        let fileSize = size.int64Value
        print(fileSize)
    }
} catch {
    print(error.localizedDescription)
}

Upvotes: 7

Bjoern Kriews
Bjoern Kriews

Reputation: 51

This works on the Dictionary as returned from the call:

fileAttributes[FileAttributeKey.size.rawValue]

(Swift 3 as of XCode8 WWDC)

Upvotes: 1

stef
stef

Reputation: 1012

This works in Swift 3:

var fileSize: UInt64 // size in bytes

do {
    let fileAttributes: NSDictionary? = try FileManager.default().attributesOfItem(atPath: fileURL.path!)
    if let fileSizeNumber = fileAttributes?.fileSize() { fileSize = fileSizeNumber }
} catch let error as NSError {
    print("Filesize reading failed: \(error.debugDescription)")
}

By casting the attributes into NSDictionary, many built-in methods become available including .fileSize():

  • .fileGroupOwnerAccountName()
  • .fileModificationDate()
  • .fileOwnerAccountName()
  • .filePosixPermissions()
  • .fileSize()
  • .fileSystemFileNumber()
  • .fileSystemNumber()
  • .fileType()

It's easy to discover their return data types by inspecting them with option-Click in Swift.

Upvotes: 1

Related Questions