2

I been getting errors on the snippet of code below. Every time I try to build it, the compiler complains:

Cannot subscript a value of type '[NSObject : AnyObject]' with an index of type 'String'

Here is the code, in all of its glory:

import Foundation
import MapKit

enum LocationKey: String {
    case Latitude = "lat"
    case Longitude = "long"
    case Title = "title"
}

extension MKPointAnnotation {
    var propertyState: [NSObject: AnyObject] {
        get {
            return [ LocationKey.Longitude.rawValue as NSObject: NSNumber(value: coordinate.latitude),
                     LocationKey.Longitude.rawValue as NSObject: NSNumber(value: coordinate.longitude),
                     LocationKey.Title.rawValue as NSObject: title as AnyObject]
        }
        set {
            let lat = (newValue[LocationKey.Latitude.rawValue] as NSNumber).doubleValue
            let long = (newValue[LocationKey.Longitude.rawValue] as NSNumber).doubleValue
            coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
            title = newValue[LocationKey.Title.rawValue] as NSString
        }
    }
}

The lines of code that I really have trouble with are:

let lat = (newValue[LocationKey.Latitude.rawValue] as NSNumber).doubleValue
let long = (newValue[LocationKey.Longitude.rawValue] as NSNumber).doubleValue
title = newValue[LocationKey.Title.rawValue] as NSString

Thanks a bunch!

Tofix
  • 151
  • 1
  • 9
  • Possible duplicate of [Cannot subscript a value of type '\[NSObject : AnyObject\]?' with an index of type 'String'](https://stackoverflow.com/questions/29994541/cannot-subscript-a-value-of-type-nsobject-anyobject-with-an-index-of-type) – Anton Belousov May 29 '18 at 11:27

3 Answers3

1

var propertyState: [NSObject: AnyObject] is a Dictionary which has keys of type NSObject. Try changing that to type String and see if that works.

JaredH
  • 2,338
  • 1
  • 30
  • 40
1

It's because you're creating a Dictionary with NSObject key.

Try this:

import Foundation
import MapKit

enum LocationKey: String {
    case Latitude = "lat"
    case Longitude = "long"
    case Title = "title"
}

extension MKPointAnnotation {
    var propertyState: [String: AnyObject] {
        get {
            return [ LocationKey.Longitude.rawValue: NSNumber(value: coordinate.latitude),
                     LocationKey.Longitude.rawValue: NSNumber(value: coordinate.longitude),
                     LocationKey.Title.rawValue: title as AnyObject]
        }
        set {
            guard let lat = (newValue[LocationKey.Latitude.rawValue] as? NSNumber)?.doubleValue,
                let long = (newValue[LocationKey.Longitude.rawValue] as? NSNumber)?.doubleValue else {
                return
            }
            coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
            title = newValue[LocationKey.Title.rawValue] as? String
        }
    }
}

In code you've seen сonditionally unwrapped optionals in properyState setter because it's good a practice not to use force unwrapping.

Ivan Smetanin
  • 1,999
  • 2
  • 21
  • 28
1

Your code is too complicated. All values are value type so declare the dictionary as [String:Any] – which solves the error by the way – and get rid of all ugly type casts to NSNumber and AnyObject.

import Foundation
import MapKit

enum LocationKey: String {
    case latitude = "lat"
    case longitude = "long"
    case title = "title"
}


extension MKPointAnnotation {
    var propertyState: [String: Any] {
        get {
            return [ LocationKey.latitude.rawValue: coordinate.latitude,
                     LocationKey.longitude.rawValue: coordinate.longitude,
                     LocationKey.title.rawValue: title ?? ""]
        }
        set {
            guard let lat = newValue[LocationKey.latitude.rawValue] as? CLLocationDegrees,
            let long = newValue[LocationKey.longitude.rawValue] as? CLLocationDegrees else { return }
            coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
            title = newValue[LocationKey.title.rawValue] as? String
        }
    }
}

You can even use the enum as key

extension MKPointAnnotation {
    var propertyState: [LocationKey: Any] {
        get {
            return [ .latitude: coordinate.latitude,
                     .longitude: coordinate.longitude,
                     .title: title ?? ""]
        }
        set {
            guard let lat = newValue[.latitude] as? CLLocationDegrees,
            let long = newValue[.longitude] as? CLLocationDegrees else { return }
            coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
            title = newValue[.title] as? String
        }
    }
}

Note: Your getter uses LocationKey.Longitude twice which will cause a compiler error.

vadian
  • 274,689
  • 30
  • 353
  • 361