【问题标题】:Cannot force unwrap value of non-optional type 'AnyObject'无法强制解开非可选类型“AnyObject”的值
【发布时间】:2018-01-16 13:15:49
【问题描述】:

我已将我的 iOS 项目从 swift 2.x 转换为 swift 3.x 我的代码中现在有 50 多个错误。最常见的一种是“无法强制解开非可选类型'AnyObject'的值”

下面是部分代码:

let documentURL = JSON[eachOne]["media"]!![eachMedia]["media_url"]! 行产生错误

我该如何解决这个问题?谢谢!

if let JSON = response.result.value as? [[String: AnyObject]]{
    //print("JSON: \(JSON)")
    myDefaultValues.userDefaults.setValue(JSON, forKey: "JSON")

    for eachOne in 0 ..< (JSON as AnyObject).count{
        // print("Cover: \(JSON[eachOne]["cover"])")

        //Download all Covers
        let documentURL = JSON[eachOne]["cover"]!
        let pathus = URL(string: documentURL as! String)

        if pathus != nil {
            HttpDownloader.loadFileSync(pathus!, completion:{(path:String, error:NSError!) in

            })
        }

        //Download all Media Files
        if JSON[eachOne]["media"] != nil{
            //print(JSON[eachOne]["media"]!)
            //print(JSON[eachOne]["media"]!!.count)

            let thisMediaView = JSON[eachOne]["media"]!.count

            for eachMedia in 0 ..< thisMediaView!{
                //print(JSON[eachOne]["media"]!![eachMedia]["media_url"])
                **let documentURL = JSON[eachOne]["media"]!![eachMedia]["media_url"]!**
                let pathus = URL(string: documentURL as! String)


                if pathus != nil {

                    HttpDownloader.loadFileSync(pathus!, completion:{(path:String, error:NSError!) in
                    })
                }
            }
        }
    }
}

【问题讨论】:

  • 你不应该再使用 AnyObject,使用“Any?”
  • 在(let documentURL = JSON[eachOne]["media"]....)中分别定义:数组、字符串、字典
  • 我尝试过使用“Any”,但它会产生相同的错误
  • @MAhipalSingh 你能给我举个例子吗?
  • 让 JSON = JSON 为! Dictionary 让 dic1 = JSON["eachOne"] as! Dictionary 让 arrMedia = object["media"] as!数组类似这样的东西

标签: ios swift swift3 xcode9


【解决方案1】:

作为一个 Swift 初学者,你应该假设 ! 强制解包运算符不存在。我称它为“crash if nil”运算符。相反,您应该使用if letguard let 可选绑定。您将 JSON 对象转换为字典数组,因此直接使用该数组:

for anObject in JSON {
   guard let mediaArray = anObject["media"] as [[String: Any]] else 
   { 
     return
   }
   for aMediaObject in mediaArray {
     guard let aMediaDict = aMediaObject as? [String: Any],
       let documentURLString = aMediaDict["media_url"] as? String,
        let url = URL(string: documentURLString ) else 
     {
        return
     }
     //The code below is extracted from your question. It has multiple
     //issues, like using force-unwrap, and the fact that it appears to be
     //a synchronous network call?
     HttpDownloader.loadFileSync(pathus!, 
       completion:{(path:String, error:NSError!) in {
     }
   }
}

该代码可能并不完美,但它应该可以为您提供思路。

【讨论】:

  • 嗨,邓肯 C,谢谢。我正在尝试实现您的代码,请看一下! link
  • 好的,考虑清楚吧。编译器不知道数组中的对象是字典,因此您必须在保护语句中添加子句以将其转换为正确的类型。我将编辑我的答案以添加适当的代码。 (代码不要发图,用起来很费劲。)
  • 谢谢 Duncan C,它现在似乎可以工作了 :) 非常感谢!
  • 不客气,但不要在不理解的情况下复制/粘贴我给你的代码。继续阅读可选项、展开、保护语句、if let 可选绑定等。这些是学习 Swift 的核心主题,您越早熟悉它们,就会越好。
【解决方案2】:

首先,代码中的以下行生成一个 Int,而不是 Array:

let thisMediaView = JSON[eachOne]["media"]!.count

其次,您可以强制解开所有值,但这会带来很大风险。你不应该强制解包,除非......不要等待,只是不要强制解包。

您在此处的行对 JSON 中的值类型做了很多假设,而没有实际检查。

let documentURL = JSON[eachOne]["media"]!![eachMedia]["media_url"]!

为了更安全和更有表现力,请尝试如下编写:

if let value = JSON[eachOne] as? [String: Any],
   let anotherValue = JSON[value] as? [String: Any],
   ...etc,
   let documentURL = anotherValue["media_url"] as? String {
   // do something with the values
} else {
   // handle unexpected value or ignore
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多