简体   繁体   中英

Swift: Conversion from Swift 2 to Swift 3 Failing

I have been at this now for a few days.
I am simply trying to convert my project from Swift 2 to Swift 3, and I have fixed quite a few errors.
However, I am down to the last 19, all of which are the same error.
Basically, I have a request to a server that returns a JSON object.
That JSON object has nested objects in side of it.
I have been Googling and reading for multiple hours trying different things and unfortunately, nothing has worked.
Any help is appreciated.
(Note: I have been asked on previous questions to post what I have already tried.
I am not going to do that here because I have tried many different ways to fix this issue)

Error: Type 'Any' has no subscript members

if let response = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject] {
    if let data = response["data"] as? NSArray {
        for (index, item) in data.enumerated() {
            let id = item["id"] as! String
        }
    }
}

Here are a few things I have tried:

if let response = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject] {
    if let data = response["data"] as? NSArray {
        for (index, item):[String:AnyObject] in data.enumerated() {
            let id = item["id"] as! String
        }
    }
}

if let response = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject] {
    if let data = response["data"] as? NSArray {
        for (index, item) in data.enumerated() as? NSArray {
            let id = item["id"] as! String
        }
    }
}

if let response = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject] {
    if let data = response["data"] as? NSArray {
        for item in data as? NSArray {
            let id = item["id"] as! String
        }
    }
}

None of the above fixed the issue. Here are the SOF questions I have referenced:

  1. type any? has no subscript members
  2. Facebook SDK error for subscript members
  3. Type 'Any' has no subscript members (firebase)
  4. Type 'Any' Has no Subscript Members in xcode 8 Swift 3
  5. Type 'Any' has no subscript members after updating to Swift 3

Any help is greatly appreciated!

Hello You can try this:

if let response = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
    if let data = response["data"] as? [AnyObject] {
        for (index, item) {
           if let id = item["id"] as! String{
               print(id)
            }
        }
    }
}

or

let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary              

  if let parseJson = json {              
   if let data = parseJson["data"] as? [AnyObject] {                   
     for signleArray in data  {                  
          if let customObjects = signleArray as? [AnyObject] {                  
             for customObject in customObjects {                  
                let userId = customObject["id"] as! String
               }
             }
           }
         }
       }

Just let me know how it worked, so we can figure it out :)

Alright, so after some help from 0ndre_, here is how I fixed the problem. Unfortunately, it wasn't a complete fix for multidimensional / nested objects so I had to modify my API that the application is calling.

if let response = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary {
    if let data = response["data"] as? [AnyObject] {
        for (index, item) in data.enumerated() {
            let id = item["id"] as! String
        }
    }
}

You should not cast to NSArray , but [AnyObject] . When enumerating an NSArray , in Swift 3 that id item type maps to Any , which indeed doesn't have a subscript. You'll find more info on Any vs AnyObject in the standard library documentation , and the rationale for this Swift 3 change for treating id as Any vs AnyObject is explained in this Swift evolution proposal .

      let inputData:Data = "{\"data\": [{\"id\":\"x\"},{\"id\":\"y\"},{\"id\":\"z\"}]}".data(using: .utf8)!

      if let response = try JSONSerialization.jsonObject(with: inputData, options: []) as? [String:AnyObject],
      let responseData = response["data"] as? [AnyObject]
      {
          for (index, item) in responseData.enumerated()
          {
              let id = item["id"] as! String
              print(id)
          }
      }

Regarding using 3rd party libraries such as SwiftyJSON for JSON parsing, you may not like 3rd party modules, but your code above will crash on bad input (if item doesn't have key "id" or if it's not a string). It's of course not like libraries like SwiftyJSON or Freddy are the only way to write robust JSON parsing code in Swift, but the Cocoa provided facilities certainly are not using the Swift type system to the benefit of the programmer and it's easy to be complacent to bad input with that API, the more complex the parsing task (which in all likelihood shouldn't really crash your program, but should be reported as an error).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM