Swift AnyObject as String dynamic cast failed - ios

I have an Int that I saved in Parse as an AnyObject. When I retrieve the AnyObject? and try to cast it as a String, NSString, NSNumber, or anything else, I keep getting an EXC_Breakpoint as the casting is returning Nil and there's a "Swift dynamic cast failed" error".
I tried to create this simple test to figure out which part fails, but the crazy thing is that this test will pass where seemingly all the steps are the same:
func testAnyObjectCasting(){
var myInt32: Int32 = 265
var myInt: Int = Int(myInt32)
var myAnyObject: AnyObject? = myInt as AnyObject
var myAnyArray: [[AnyObject]] = [[AnyObject]]()
myAnyArray.append(["something", myAnyObject!])
println(myAnyObject)
var myOtherAnyObject: AnyObject? = myAnyArray[0][1]
println(myOtherAnyObject)
var myString:NSNumber? = myOtherAnyObject as? NSNumber
println(myString)
var myInt2: Int = myString! as Int
}
Here's the relevant code snippets from my logic, and notes that println() works fine until the downcast to NSNumber, at which time Nil is returned:
//ABRecordGetRecordId returns an ABRecordID, which is of type Int32
//This value that's stored in the 2nd column of the multiDim [[AnyObject]]
var personId: Int = Int(ABRecordGetRecordID(person))
//This is a call to a Parse object, which returns an AnyObject. I then cast that to
//a multidimensional array AnyObject as that's the true structure of the data in swift speak
var deviceContacts: [[AnyObject]] = device?[deviceContactsFieldName] as [[AnyObject]]
//This returns the expected value, which in my broader test case is 99999, which is supported by Int
var i:Int = 1
println("the value in device contacts \(i) column 1 is: \(deviceContacts[i][1])")
//This takes a single cell value from the multidim array and puts it in an optional AnyObject
var valueInParse: AnyObject? = deviceContacts[i][1]
//This still returns 99999
println(valueInParse)
//This is where 99999 is replaced with nil. Any ideas?
var valueNSNumberInParse: NSNumber? = valueInParse as? NSNumber
//Nil :(
println(valueNSNumberInParse)
//Exception as I'm trying to unwrap nil :(
var unwrappedNSNumber:NSNumber = valueNSNumberInParse!
Part of my frustration is that I don't understand why println() works fine for AnyObject but all the casting fails. Clearly there's code that can interpret the value as a string to show for println, but that syntax eludes me for proper casting.

Because you have saved an Int into Parse and an Int is not an object it had to be converted to an object. It seems that the Parse framework has converted it to an NSValue, which is effectively a byte buffer that represents an intrinsic type.
You could try and convert these bytes back to an Int, but it is easier and better to encode the value into an NSNumber before storing it in the Parse object - then you will be easily able to handle it when you retrieve the object.

Related

convert value of type 'String' to expected argument type 'Int'

I have a dictionary of data passed from another viewController, and when I tried to fetch the id from the dictionary it gives me conversion error!
var comments = [JSON]()
#IBAction func AddCommentBTN(_ sender: Any) {
let commentTXT = CommentTXTField.text
let name = self.accountDetails["name"]
let email = self.accountDetails["email"]
let articleId = self.comments["id"].string! ----> error is here
API.AddComment(articleId: "", name: name!, email: email!, message: commentTXT!) { (error: Error?, success: Bool) in
if success {
self.CommentTableView.reloadData()
print("Registerd Successfuly")
} else {
print("Faile To Comment")
}
}
}
Firstly, self.comments is an array of JSON object. So before getting value from the JSON you need to get the object first from the array. Before getting the 0 index value make sure the array contains value.
Seems like you are using SwiftyJSON to parse the value. So by using .intValue you can get the Int value. .intValue will return a Int type value. If the key not present there then this will return you the 0 value. .intValue not an Optional type.
Try this
let articleId = self.comments[0]["id"].intValue
instead of
let articleId = self.comments["id"].string!
You are converting a String to Int which is not as straightforward as you may think. The String can contain characters that is not a number like "Forest". To convert a String to Int you can use:
if let myInt = Int(self.comments["id"]) {
let articleId = myInt
}
It will check if the string is a correct Int and return an Optional value. You can also use a fallback to define a default value if the String is not correct Int
let myInt = Int(self.comments["id"]) ?? 0
That means “attempt to convert self.comments["id"] to an integer, but if the conversion failed because it contained something invalid then use 0 instead.”
The values of a json are optional and might be on any allowed type. A way parsing this save would be getting the value for "id", which will be an optional, and try to convert this optional to an Int. The Int itself is optional as well. (Short, it might be there or not)
guard let value = self.comments["id"], let articleId = Int64(value) else {
// Not valid
return
}
print(articleId)
A better way would be parsing your json data to an object in the first place. Your controller would not need to deal with the parsing of optional data, but instead just get the right data from the object.

Core Data and making double from type AnyObject? Swift

I was writing a code for CoreData. My datamodel includes name and moneyAmount. Here's the part of the code I have troubles with
do {
let request = NSFetchRequest(entityName: "MoneyData")
let results = try context.executeFetchRequest(request)
if results.count > 0 {
for item in results as! [NSManagedObject] {
let name = String(item.valueForKey("name"))
let moneyAmount = item.valueForKey("moneyAmount")
moneyManager.addMoney(name, moneyAmount: moneyAmount)
}
}
} catch {
print("There was an error saving data")
}
Now the problem is that my moneyManager.addMoney requires String and Double. However, with this code, the error that I get is:
Optional Chain has no effect, already produces 'Anyobject?'
Cannot convert value of type AnyObject? to expected argument type 'Double'
I don't really understand what it means by Anyobject. I think I should convert anyobject to double to make it work right?
Thanks in advance
valueForKey() returns an object of type AnyObject because there's no way of knowing at compile-time what type of object it's referencing. You can cast to a specific type using as. For example, moneyAmount as? Double will result in an object of type Double?, either containing the numeric value, or being nil if the object wasn't of type Double.

Swift: Convert Int to UInt32, and how to unwrap optional

im pretty new to swift, and im just trying to build something to test out the waters. this is in relation to a previous question i had. I am building some code to take user input from a UITextField object, and basically im trying to figure out how to convert an Int to a UInt32, but nothing ive searched on SO or otherwise has really helped.
here is my code
//this is where i call the user input.
var rangeInput: Int? {
get {
return Int(rangeInputTextField?.text ?? "")
}
//this is my function to create a range, and call a random number out of that range
let viewController = ViewController()
var x = ViewController().rangeInput
let y = (Int?(x!))
var number = arc4random_uniform(Int(y!))//ERROR OCCURS HERE "Cannot convert value of type 'Int' to expected argument type 'UInt32'
//MARK: Class for random number
struct RandomNumber {
// numberRange to change the value for 1...X(user input)
//creates the list to be picked from. (pickRandom)
func numberRange(high: UInt32) ->Range<UInt32>{
if let high = UInt32?(0){
print("Invalid number")
} else { let high = Int(y!) + 1
}
let range = 1...high
return range
}
//pick random number from that list
let pickRandom = number
}
edit: Converted UInt, using answer in comments, but am having an issue with unwrapping optionals.
am I doing something wrong with forcibly unwrapping optionals?
let viewController = ViewController()
var x = ViewController().rangeInput
var number = arc4random_uniform(UInt32(x!)) // <----- UInt32 conversion
However, do recommend to check the user input x and/or after the UInt32 conversion, in case user inputs something not sensible, using guard or if let
Initializers are called in swift by listing the data type (UInt32 in this case) followed by parenthesis containing the parameters. For most basic data types in Swift, there are no parameters for the initializers. So if you ever want to make an Int, Float, Double, UInt32, String etc., just do
UInt32(Value)!//UInt32 can be substituted for any of the above values
The "!" unwraps the optional, and will result in an error in runtime like "unexpectedly found nil when unwrapping optional value" if the value is not a valid form of the data type, if you want to do this safely, you can do this
if UInt32(Value) != nil {
//Valid Value
}else {
//Invalid Value
}
Also this is unrelated to the question, but your if let statement will always be true because you are overriding the value of the parameter "high" to a UInt32 of 0. I could be wrong though.

swift forcing objective-c int to be assigned as Int32 then crashing

I have an objective c property that has been declared as
#property int xmBufferSize;
If I do sharedExample.xmBufferSize = 1024 it just works fine
but when I am trying to set an integer value for that property from another variable
var getThat:Int = dict["bufferSize"]!.integerValue
sharedExample.xmBufferSize = getThat
It can't do above
Cannot assign a value of type 'Int' to a value of type 'Int32'
If I force this to
sharedExample.xmBufferSize =dict["bufferSize"] as! Int32
It is crashing with Error
Could not cast value of type '__NSCFNumber' to 'Swift.Int32'
EDIT::::
Dict init, there are other objects in dict besides integers
var bufferSize:Int = 1024
var dict = Dictionary<String, AnyObject>() = ["bufferSize":bufferSize]
The value in dict is an NSNumber, which cannot be cast or directly converted to Int32. You can first obtain the NSNumber and then call intValue on it:
if let bufferSize = dict["bufferSize"] as? NSNumber {
sharedExample.xmlBufferSize = bufferSize.intValue
}
The if let … as? allows you to verify that the value is indeed an NSNumber, since (as you said) there can be other types of objects in dict. The then-branch will only execute if dict["bufferSize"] exists and is an NSNumber.
(Note: You can also try integerValue if intValue gives the wrong type, or convert the resulting integer – CInt(bufferSize.integerValue) – as needed. Swift doesn't do implicit conversions between different integer types, so you need to match exactly.)
You need to convert your NSNumber to Int32.
sharedExample.xmBufferSize = dict["bufferSize"]!.intValue
Use type conversion, not as:
sharedExample.xmBufferSize = Int32(dict["bufferSize"] as! Int)
That should work.

set value of UISlider with a variable

I have now spent about 12 hours trying to solve this riddle, but I just can't! The truth is I am about 3 weeks into my Swift adventure and this is the first time I have ever written any code (well I think I made a rainbow once on my Atari 800XL!)
I don't really know what I am doing.... I also understand that what I am trying to do here could be fundamentally wrong, and so I will appreciate gift wrapped criticism.
I have a slider - C1
I want to set its value with a variable. However, it wants a float and I can't seem to convert the array I am using to a float. In fact I can't get any of the array values to convert to anything else, and keep getting an error about AnyObject. The code below is one iteration of the trials i have run, all without any luck. It is driving me mad!
The errors are
can't assign a value of int to a value of type float
AnyObject is not convertible to NSNumber; did you mean to use as! to force downcast
This is the code where I get the array from Parse and assign it to NSUSER.
var defaults = NSUserDefaults.standardUserDefaults()
var getAuditId:String = defaults.stringForKey("auditIdGlobal")!
var userId:String = defaults.stringForKey("userIdGlobal")!
var query = PFQuery(className: "auditData")
query.whereKey("auditId", equalTo:getAuditId)
query.findObjectsInBackgroundWithBlock {
(objects: Array?, idError: NSError?) -> Void in
if idError == nil {
if let objects = objects as? [PFObject] {
for object in objects {
var auditId: AnyObject? = object["auditId"]!
var callEhs: AnyObject? = object["ehsData"]!
NSUserDefaults.standardUserDefaults().setObject(callEhs, forKey: "ehsLoad")
This is the code at the user end
var defaults = NSUserDefaults.standardUserDefaults()
var loadArray = defaults.arrayForKey("ehsLoad")!
var test: AnyObject = loadArray[0]
var testFloat = Int(test)
c1.value = testFloat
I appreciate that it shows an int above, but I can't convert to anything!
Xcode asked me to insert a forced downcast to as!NSNumber
var = int(test as! NSNumber)
here I get this error
Could not cast value of type '__NSCFString' (0x10c0bfc50) to 'NSNumber' (0x10c550b88).
(lldb)
if I try to use a forced downcast
var testFloat = test as! Float
On running the app i get the error
Could not cast value of type '__NSCFString' (0x10b690c50) to 'NSNumber' (0x10bb21b88).
(lldb)
Your test variable is a NSString. Try
var test = loadArray[0] as! NSString
and then use
test.floatValue

Resources