无法将类型“ NSTaggedPointerString”的值强制转换为“ NSNumber”


73

我有一个这样的Swift结构。

struct Usage {
    var totalData: Double
    var remainingTotalData: Double

    init(jsonData: NSData) {
        var jsonDict = [String: AnyObject]()

        do {
            jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as! [String: AnyObject]
        } catch {
            print("Error occurred parsing data: \(error)")
        }

        totalData = jsonDict["totalfup"] as! Double
        remainingTotalData = jsonDict["totalrem"] as! Double
    }
}

从API,我得到以下JSON响应。这是jsonDict变量的println 。

[
    "totalfup": 96.340899, 
    "totalrem": 3548710948
]

当我尝试将的值分配给totalfup属性时totalData,出现此错误。

无法将类型“ NSTaggedPointerString”的值强制转换为“ NSNumber”

有人知道为什么吗?我尝试将属性类型更改为float,然后将整个结构更改为class,但是仍然出现问题。

Answers:


110

错误的原因jsonDict["totalfup"]是String(NSTaggedPointerString是的子类NSString),因此您应该将String转换为Double。

请确保在强制拆开之前捕获异常并检查类型!

totalData = (jsonDict["totalfup"] as! NSString).doubleValue

为了安全起见,请使用if let

// check dict["totalfup"] is a String?
if let totalfup = (dict["totalfup"] as? NSString)?.doubleValue {
  // totalfup is a Double here 
}
else {
  // dict["totalfup"] isn't a String
  // you can try to 'as? Double' here
}

2
谢谢!那行得通。你知道为什么吗 回到Swift 1.2,我们不必转换为NSStrings,对吧?
Isuru,2015年

我不确定Swift 1.2。但NSJSONSerialization有时会将数字值反序列化为数字。当然,在从中转换值之前NSDecimalNumber ,请首先检查[object class](dynamicType)。
tuledev

1
我使用的框架发生了相同的错误,该框架从捆绑资源中的自定义plist文件读取配置值(不涉及JSON)。我已将某些plist字段定义为Strings,但是它们API可能希望它们是 Numbers。更改类型以Number解决问题。
Nicolas Miari'3

20

我认为这可以帮助您

totalData = Double(jsonDict["totalfup"] as! String)!

4

失败原因是JSON返回String值,而不是数字。

如果返回的JSON数据仅包含这两个键值对,则声明类型,因为[String:String]这避免了类型转换。

无论如何,您都必须将代码更新以将变量更新到表达式的“ good”分支中do - catch

struct Usage {
    var totalData = 0.0
    var remainingTotalData = 0.0

    init(jsonData: NSData) { // Swift 3: Data

        do {
            let jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as! [String: String]                
            // Swift 3: let jsonDict = try NSJSONSerialization.jsonObject(with: jsonData) as! [String: String]
            totalData = Double(jsonDict["totalfup"]!)
            remainingTotalData = Double(jsonDict["totalrem"]!)
        } catch {
            print("Error occurred parsing data: \(error)")
        }
    }
}

谢谢回复。但是Double(jsonDict["totalfup"])当我收到此错误时,我不能简单地做。无法为类型为'(AnyObject?)'的参数列表调用类型为'Double'的初始化程序。我想您必须定义键值对类型[String: Double]才能正常工作。
Isuru 2015年

如果jsonDict强制转换为`[String:String]`(请参见NSJSONSerialization答案中的行尾),则编译器无法假定它为AnyObject。但是我忘了带感叹号的哟,您解开了数值
vadian

@vadian请更新您的答案,否则它将无法编译...(必须初始化所有属性)
user3441734

0

经过测试并适用于Swift 5.0。

我有同样的问题。

这对我有用。

// check dict["dummy"] is a String first
if let receivedData = (dict["dummy"]).doubleValue {
  // add more code in case the condition is true
}
else {
 // add more code in case the condition is false
}

当您想要比较接收到的数据或仅检查值时(如以下示例),这确实很有帮助。

let receivedData = (results["data"]!).doubleValue

if (receivedData == 0){
      self.label.text = "Nothing seem to be added yet!"
}

-1

为什么不直接使用Swift的本机类型?

import Foundation

struct Usage {
    var totalData: Double = 0
    var remainingTotalData: Double = 0

    init(jsonData: NSData) {
        do {
            if let jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as? [String:Double] {
                totalData = jsonDict["totalfup"] ?? 0
                remainingTotalData = jsonDict["totalrem"] ?? 0
            }
        } catch {
            print("Error occurred parsing data: \(error)")
        }
    }
}

if let data = "{\"totalfup\":96.340899,\"totalrem\":3548710948}".dataUsingEncoding(NSUTF8StringEncoding) {
    let usage = Usage(jsonData: data)
    dump(usage)
    /*
    ▿ Usage
      - totalData: 96.340899
      - remainingTotalData: 3548710948.0
    */
}

-2

斯威夫特4

    let strStatus:String = dictProperty.value(forKey: "StatusType") as! String
    let myStatus = Double.init(strStatus)

更新资料

extension String {
    func toDouble() -> Double? {
        let numberFormatter = NumberFormatter()
        numberFormatter.locale = Locale(identifier: "en_US_POSIX")
        return numberFormatter.number(from: self)?.doubleValue
    }

    func toInt() -> Int? {
        let numberFormatter = NumberFormatter()
        numberFormatter.locale = Locale(identifier: "en_US_POSIX")
        return numberFormatter.number(from: self)?.intValue
    }

    func toFloat() -> Float? {
        let numberFormatter = NumberFormatter()
        numberFormatter.locale = Locale(identifier: "en_US_POSIX")
        return numberFormatter.number(from: self)?.floatValue
    }

    func toBool() -> Bool? {
        let numberFormatter = NumberFormatter()
        numberFormatter.locale = Locale(identifier: "en_US_POSIX")
        return numberFormatter.number(from: self)?.boolValue
    }
}

强制强制转换很少是一个好主意。这是不建议使用的许多次操作之一,它可能导致应用程序意外崩溃。
ZGski

@ZGski只是将字符串转换为双精度值,请检查您的api端数据类型,(它必须是字符串数据类型,而不是数字,布尔值或其他字符串形式的参数),然后才起作用
Vivek

以任何方式我只要添加新的字符串扩展名,这也将有助于将字符串转换为双精度值,请检查我更新的答案
Vivek
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.