Having trouble figuring out how to make the following call in swift:
var anyError: NSError? = nil
var rsrc: NSNumber? = nil
var success = url.getResourceValue(&rsrc, forKey:NSURLIsUbiquitousItemKey, error:&anyError)
The above does not compile:
Cannot convert the expression's type 'Bool' to type 'inout Bool'
So I tried this:
var anyError: NSError? = nil
var rsrc: AutoreleasingUnsafePointer<AnyObject?> = nil
var success = url.getResourceValue(rsrc, forKey:NSURLIsUbiquitousItemKey, error:&anyError)
but this generates EXC_BAD_ACCESS runtime error.
How do I pass in the expected first arg as AutoreleasingUnsafePointer<AnyObject?> (which should point to a boolean NSNumber according to doc), and then be able to check its expected Bool value ?
You need to make rsrc an optional AnyObject and pass it by reference like so:
var anyError: NSError?
var rsrc: AnyObject?
var success = url.getResourceValue(&rsrc, forKey:NSURLIsUbiquitousItemKey, error:&anyError)
Note: You do not need to initialize Optionals to nil, they are set to nil by default.
If you then want to check if the value is an NSNumber you can then do a conversion:
if let number = rsrc as? NSNumber {
// use number
}
Here is drewag's code updated for Swift 2.0
do {
var rsrc: AnyObject?
try element.getResourceValue(&rsrc, forKey: NSURLIsDirectoryKey)
if let number = rsrc as? NSNumber {
if number == true {
// do something
}
}
} catch {
}
in swift 3 previous calls are not available/deprecated:
so use:
var keys = Set<URLResourceKey>()
keys.insert(URLResourceKey.isDirectoryKey)
do{
let URLResourceValues = try fileURL.resourceValues(forKeys: keys)
}catch _{
}
If the getResourceValue(:forKey:) result is ultimately a logical value, you can cast the returned pointer value directly to a Bool value:
let boolResult = rsrc as! Bool
or simply test it as a Bool value without assigning it:
if rsrc as! Bool {
// true code
} else {
// false code
}
or do both:
if let rsrc as! Bool {
// true
} else {
// false
}
Here's a concrete example as an extension of the URL type:
extension URL {
var creationDate : Date {
let url = self as NSURL
var value : AnyObject?
try? url.getResourceValue(&value, forKey: .creationDateKey)
if let date = value as? Date {
return date
}
return .distantPast
}
}
For convenience, if the call to getResourceValue() fails, it returns the value .distantPast by default. Using the try? form allows discarding the error which isn't always needed.
Related
I stored an Int in UserDefaults. The Int will serve as the index of audioOptionsList, an array of objects, each having a SystemSoundID property.
This crashes with error: Could not cast value of type 'NSTaggedPointerString' (0x7fff87b33c28) to 'NSNumber' (0x7fff87bf4e00).
var soundToPlay = SystemSoundID(1322)
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.standard.value(forKey: "timerSoundSelection") != nil {
let storedIndex = UserDefaults.standard.value(forKey: "timerSoundSelection")!
print("stored index is: \(storedIndex)") //prints a non-optional int as expected.
soundToPlay = audioOptionsList[storedIndex as! Int].sound //crashes with error
} else {
soundToPlay = SystemSoundID(1322)
}
Your key is stored as a String not an Int , use string(forKey: then cast it
if let stored = UserDefaults.standard.string(forKey: "timerSoundSelection")
, let value = Int(stored) { }
I have the following class
class BannerResponse : NSObject{
let URL = "Url";
let CONTACT_NO = "ContactNo";
let IMAGE = "Image";
let BIG_IMAGE = "BigImage";
let ID = "Id";
let TITLE = "Title";
let NO_VIEW = "NoView";
let START_DATE = "StartDate";
let END_DATE = "EndDate";
var url:String;
var contactNo:String;
var image:String;
var bigImage:String;
var title:String;
var id:Int;
var noView:Int;
var startDate:String;
var endDate:String;
init(data : NSDictionary){
url = data[URL] as! String;
contactNo = data[CONTACT_NO] as! String;
image = data[IMAGE] as! String;
bigImage = data[BIG_IMAGE] as! String;
title = data[TITLE] as! String;
id = data[ID] as! Int;
noView = data[NO_VIEW] as! Int;
startDate = data[START_DATE] as! String;
endDate = data[END_DATE] as! String;
}
}
when I run the code, I got the following error
Could not cast value of type 'NSNull' (0x10a85f378) to 'NSString' (0x109eccb20).
EDIT
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary{
onSuccess(BannerResponse(data: json))
}
} catch {
onFail()
}
One of your data[SOME_KEY] is of type NSNull instead of String and because you're forcing the cast to String by using ! the app crashes.
You can do one of two things:
Change your variables on the BannerResponse class to be optional. And use ? instead of ! when setting the values in your init method. Like this:
`
var title: String?
init(data: NSDictionary)
{
self.title = data[TITLE] as? String
}
or
Use ? instead of ! when setting the values in your init method but set a default value whenever dict[SOME_KEY] is nil or is not the expected type. This would look something like this:
`
if let title = data[TITLE] as? String
{
self.title = title
}
else
{
self.title = "default title"
}
// Shorthand would be:
// self.title = data[TITLE] as? String ?? "default title"
And I guess a third thing is ensure that the server never sends down null values. But this is impractical because there's no such thing as never. You should write your client-side code to assume every value in the JSON can be null or an unexpected type.
You are getting null values for some of your keys. They get mapped to NSNull by NSJSONSerialization.
You need to do several things
Change all your variables (url, contactNo, etc) to optionals:
var url:String?
var contactNo:String?
Change all of your assignments to use ? instead of !:
url = noNulls[URL] as? String
contactNo = noNulls[CONTACT_NO] as? String
And finally, make your code handle nil values for all of your variables. (But do not use !. That path leads to crashes.)
I have a Swift struct like this.
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
}
}
From an API, I get the following JSON response. This is the println of the jsonDict variable.
[
"totalfup": 96.340899,
"totalrem": 3548710948
]
When I try to assign the value of the totalfup to the property totalData, I get this error.
Could not cast value of type 'NSTaggedPointerString' to 'NSNumber'
Anyone knows why? I tried changing the property type to float and then the whole struct to class but still the issue occurs.
The reason of the error is jsonDict["totalfup"] is a String (NSTaggedPointerString is a subclass of NSString) , so you should convert String to Double.
Please make sure, catch exception and check type before force-unwrap !
totalData = (jsonDict["totalfup"] as! NSString).doubleValue
For safety, using 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
}
I think this could help you
totalData = Double(jsonDict["totalfup"] as! String)!
The failure reason is that the JSON returns String values, not numbers.
If the returned JSON data contains only these two key value pairs declare the type as [String:String] that avoids the type casting.
In any case you have to put the code to update the variables into the "good" branch of the do - catch expression.
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)")
}
}
}
Tested and Working for Swift 5.0.
I had the same problem.
This worked for me.
// 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
}
It is really helpful when you want to compare the received data or just check the value like the following example.
let receivedData = (results["data"]!).doubleValue
if (receivedData == 0){
self.label.text = "Nothing seem to be added yet!"
}
String interpolation
I posted my answer in a similar thread.
if let jsonDict_any = jsonDict["totalfup"],
let jsonDict_double = Double("\(jsonDict_any)") {
//..
}
Essentially, this avoids having to try multiple typecastings. By checking first for its existence, we can can then use string interpolation, then try casting it to a Double.
Warning:
As #Alexander pointed out, this solution allows any Type to become a String and be checked for a Double value. Only use this if you're not concerned about the value's Type prior to interpolation.
why not use Swift's native types directly?
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
*/
}
Swift 4
let strStatus:String = dictProperty.value(forKey: "StatusType") as! String
let myStatus = Double.init(strStatus)
Update
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
}
}
I have a json response which is fetched from server and it should be parsed as dictionary and convert it to NSObjects in Swift. How can i do this.
func convertJSONToObjects(object:Dictionary<String,AnyObject>?) -> CommonResponse{
var response:CommonResponse;
if(object != nil){
response = CommonResponse()
var responseObject = object //It is dictionary
var responseHeader = object["responseHeader"] //error
response.status = responseHeader["status"] as Int //error
//response.status is Int
}
return response
}
var parsedJson = NSJSONSerialization.JSONObjectWithData(object as NSData, options: NSJSONReadingOptions.MutableContainers, error: &parseError) as NSDictionary
calling function
convertJSONToObjects(parsedJson)
object is optional. You need some kind of unwrapping optional chaining, or optional bidding.
if let object = object {
var responseHeader = object["responseHeader"]
}
or
var responseHeader = object!["responseHeader"]
or
if let responseHeader = object?["responseHeader"] {
// ...
}
and so on.
You could set a break point before:
var responseHeader = object["responseHeader"] //error
to make sure that object does contains a key named "responseHeader".
Otherwise you should let variable responseHeader to be an Optional value.
I wrote a class that parses JSON text and maps it to Swift structs/classes.
let p = CutePossumParser(json: json)
let model = Possum(
name: p.parse("name", miss: ""),
home: Address(
planet: p["home"].parse("planet", miss: "")
)
)
if !p.success { /* mapping failed */ }
https://github.com/exchangegroup/cute-possum-parser
I'm tring to parse a JSON format like this:
{
"key_1" : {
"key_2" : "value"
}
}
and then assign "value" to a variable.
Here is my code:
var variableShouldBeAssigned: String
if let x = (jsonResult["key_1"]? as? NSDictionary) {
if let y = (x["key_2"]? as? String) {
variableShouldBeAssigned = y
}
}
However, an error occurs when I try to downcast from x["key_2"]? to a String, but it's fine to downcast from jsonResult["key_1"]? to an NSDictionary.
I can solve the error by using x["key_2"] to replace x["key_2"]?, but I don't really know why it only works for jsonResult["key_1"]?.
Can anybody tell me the reason?
String does not conform to NSCopying, but surely NSString does!
Also, going from NSString to String is instantaneously implied...
So I would say try something like this... Change String to NSString
here is a sample, assuming that you handle the jsonResult as a NSDictionary...
func giveDictionary(jsonResult:NSDictionary) -> String?
{
if let x = (jsonResult["key_1"]? as? NSDictionary)
{
if let y = (x["key_2"]? as? NSString)
{
return y
}
}
return nil
}
You can simplify all your type checking by using a Swift dictionary at the beginning:
var variableShouldBeAssigned: String
if let dict = jsonResult as? [String:[String:String]] {
if let key1Dict = dict["key_1"] {
if let value = key1Dict["key_2"] {
variableShouldBeAssigned = value
}
}
}
In fact, you can even combine the two last if statements:
var variableShouldBeAssigned: String
if let dict = jsonResult as? [String:[String:String]] {
if let value = dict["key_1"]?["key_2"] {
variableShouldBeAssigned = value
}
}
In general, you should using Swift Dictionaries instead of NSDictionary