11

Here is my code in Swift:

currentUserFirebaseReference.observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in
        let UID = snapshot.key
        let pictureURL = snapshot.value!["pictureURL"] as! String
        let name = snapshot.value!["displayname"] as! String
        let currentUser = Person(name: name, bio: "", UID: UID, pictureURL: pictureURL)
        self.currentUserInfo = currentUser
            })

I just updated to Xcode 8 / Swift 3, which seems to have caused the following error message:

"Type 'Any' has no subscript members"

I call snapshot.value!["insert something here"] in many places in my code, I'm getting this error and I can't run my code.

The following code works:

let pic = (snapshot.value as? NSDictionary)?["pictureURL"] as? String ?? ""

However, I don't see what changed or what makes this necessary now versus how it was before.

The only thing that has changed as far as I'm aware is the syntax of the observe, but I don't understand why this caused my code to stop working.

WonderWorker
  • 8,539
  • 4
  • 63
  • 74
user6820041
  • 1,213
  • 2
  • 13
  • 29
  • Possible duplicate of [Type 'Any' has no subscript members (firebase)](http://stackoverflow.com/questions/39136026/type-any-has-no-subscript-members-firebase) – J. Cocoe Sep 16 '16 at 15:25
  • Thanks for correcting it Eric. There was a remaining reference to Objective C that I replaced with Swift too. – WonderWorker Jan 03 '17 at 10:01

2 Answers2

30

J. Cocoe's answer is absolutely correct, but for those who need a code example this is how you do it:

instead of

let name = snapshot.value!["displayname"] as! String

try

let snapshotValue = snapshot.value as? NSDictionary
let name = snapshotValue["displayName"] as? String

The idea is that you need to cast the type of snapshot.value from Any to an NSDictionary.

Edit:

As Connor pointed out, force unwrapping snapshot.value or anything from a backend system is a bad idea due to possibly receiving unexpected information. So you change as! NSDictionary to as? NSDictionary.

Aylii
  • 525
  • 4
  • 10
  • 1
    Particularly with communicating with a backend like Firebase, I'd recommend not force unwrapping, in case that value isn't what you expect and you don't want your app to crash: `if let snapshotValue = snapshot.value as? NSDictionary, name = snapshotValue["displayName"] as? String { \\ do stuff }` – Connor Neville Sep 17 '16 at 22:57
  • 3
    Please don't use `NSDictionary` in Swift unless you have no choice. The native dictionary `[String:Any]` type is preferable because it provides type information. – vadian Sep 18 '16 at 19:02
8

In FIRDataSnapshot, value is of type id.

In Swift 3, id is imported as Any.

In the Firebase documentation, it says value can be any of NSDictionary, NSArray, NSNumber, or NSString -- clearly, subscripting doesn't make sense on all of these, especially in Swift. If you know it's an NSDictionary in your case, then you should cast it to that.

J. Cocoe
  • 881
  • 1
  • 10
  • 22