I have a meta variable NSObject in a viewcontroller that I intend to be able to receive any kind of object from the parent viewcontroller that pushes it. I also have a type variable that will determine how I typecast and interpret this NSObject inside the viewcontroller.
The problem is when I tried to cast an NSDictionary into NSObject in the parent, Xcode warns that that type of typecasting will always fail.
Code that I have tried:
childVc.meta = ["title":"test"] as! NSObject; // warning: cast from '[String:String?]' to unrelated type 'NSObject' always fails.
let data = ["title":"test"];
childVc.meta = data as! NSObject; // warning: cast from '[String:String?]' to unrelated type 'NSObject' always fails.
let data = ["title":"test"];
childVc.meta = data as NSObject; // error: cannot convert value of type '[String:String?]' to type 'NSObject' in coercion.
let data = ["title":"test"] as! NSObject; // warning: cast from '[String:String?]' to unrelated type 'NSObject' always fails.
childVc.meta = data;
But the opposite typecasting always works:
let unwrappedMeta = self.meta as! NSDictionary;
Oh btw, I know that swift doesn't need semicolon at the end. It's just my habit from obj-c and swift looks like doesn't care about it, so don't let this semicolon distract us. :)
You have an optional value in dictionary, seems not to be NSDictionary.
// warning: cast from '[String:String?]'
Try to cast it as AnyObject
Please try to use like this:
var traitsDic : NSDictionary! = ["title":"test"]
var traits = traitsDic as Dictionary<String, AnyObject>
Related
I need to pass a Dictionary to a Objective-C method in Swift. In Swift the code is like this:
let modelData: Dictionary<String, [Double]> = getModelData()
result = myChilitags.estimate3D(configAt: configFilePath, forModel: modelData);
(The configure file has nothing to do with this problem, just ignore it.)
I used a .h file:
#interface myChilitags : NSObject
+ (nonnull UIImage *)estimate3D:configAt:(NSString *)configFilePath forModel:(nonnull NSDictionary*) modelData;
#end
The question is that I need to do something with the modelData in the Objective-C method estimate3D but I don't know what to do after I passed the Dictionary value modelData to the method.
I tried to just print the modelData value but all that came out was:
1
I also tried to print the value in the Dictionary like:
std::cout << modelData["face001"] << std::endl;
I am pretty sure that there is a key "face001" in the dictionary but the result was still:
1
I know it must have something to do with NSDictionary and Dictionary but I just don't know what to do.
First of all, a Dictionary in Swift is struct, an NSDictionary is class.
Objective-C is not type-safe so it doesn't show an error.
If you try to do the same in Swift, it will tell you
Cannot assign value of type '[String : [Double]]' to type 'NSDictionary'
let swiftDictionary = [String: [Double]]()
var nsDictionary = NSDictionary()
nsDictionary = swiftDictionary //shows error
So you have to convert the Swift dictionary to an NSDictionary.
let modelData: Dictionary<String, [Double]> = getModelData()
let nsModelData = NSDictionary(dictionary: modelData)
result = myChilitags.estimate3D(configAt: configFilePath, forModel: nsModelData);
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.
(I'm new to Swift and iOS development in general).
I'm porting some Objective-C code over to Swift and I don't know how to translate this:
-(void) fooDidBar:(NSNotification *)notification
{
Foo* foo = [[notification userInfo] objectForKey:BarKey];
// do stuff with foo
}
So far I have this:
private func fooDidBar(notification: NSNotification) {
var foo: Foo = notification.userInfo.objectForKey(BarKey)
}
But I get a compiler error:
/Users/me/src-me/project/FooBarViewController.swift:53:57: Value of type '[NSObject : AnyObject]?' has no member 'objectForKey'
As userInfo is declared as an NSDictionary in UIApplicationShortcutItem.h:
#property (nullable, nonatomic, copy) NSDictionary<NSString *, id <NSSecureCoding>> *userInfo;
...I thought I'd try this:
= notification.userInfo[BarKey]
but then I get this error:
/Users/me/src-me/project/FooBarViewController.swift:53:65: Type '[NSObject : AnyObject]?' has no subscript members
Your idea to use subscripts was correct, however as you can see by the presence of ?, the userInfo dictionary is Optional, meaning that it can be nil (in Objective-C, no distinction is made). Furthermore, Swift's Dictionary is not as lenient with types as NSDictionary, so you'll need to use as? to ensure the value is a Foo instance as you expect.
You can't directly subscript the optional dictionary, but if you use a ? for optional chaining, then you can access the value if the dictionary is non-nil. I would also recommend if let to access the final value if it's non-nil. (Or you might choose to use guard let with a fatalError or return in case the Foo is not present.)
if let foo = notification.userInfo?[BarKey] as? Foo {
// foo is non-nil (type `Foo`) in here
}
In the following code, downcasting by as! is failed for same type.
Doesn't Swift allow downcasting for same type or not?
class base {
var a = 1
}
class derived : base {
}
let a: base? = base()
let b = a as! base // error occur!
println("\(b.a)")
Error message:
error: downcast from 'base?' to 'base' only unwraps optionals; did you mean to use '!'?
let b = a as! base
~ ^ ~~~~
If I modify an above code like the following, there is no problem.
let a: base? = derived()
let b = a as! derived
println("\(b.a)")
This is the define of DownCasting in swift
Downcasting
A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as? or as!).
So,if the type is same,that is not DownCasting.
Swift document
You can try this :
let b = a!
I'm using NSJSONSerialization as so:
let twData: AnyObject? = NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions.MutableLeaves, error: &dataError)
This gives me an AnyObject?.
From here, I want to convert it to Array<Dictionary<String,String>>
I've tried all sorts, leading up to this:
var twDataArray: Array<Dictionary<String,String>>? = twData? as? Array<Dictionary<String,String>>
which simply gives the error:
Type 'Array>' does not conform to protocol
'AnyObject'.
And putting the simpler version:
var twDataArray = twData as Array
gives the error:
Cannot convert the expression's type 'AnyObject?' to type 'Array'
To cast your data to an array:
var twDataArray = (twData as! NSArray) as Array
The code above first casts twData to an NSArray, and then to an Array via a bridging cast. A bridging cast is a special type of cast which converts an Objective-C type to it's _ObjectiveCBridgeable conformant, Swift counterpart.
(Note that I didn't need to write Array<AnyObject> because the element AnyObject is inferred in the bridging cast from NSArray → Array)
Note that the cast above is a forced downcast. Only use this if you're absolutely sure that twData is going to be an instance of NSArray. Otherwise, use an optional cast.
var twDataArray = (twData as? NSArray) as Array?
Try the following, you can iterate through the array as given below.
for element in twData as! Array<AnyObject> {
print(element)
}
This works in a playground:
var data: Array<Dictionary<String,String>>? = twData as? Array<Dictionary<String, String>>
the difference from your code is that twData does not require the ? at the end - it is an optional so the as? operator will take care of verifying that it can be case to an array of dictionaries - needless to say, if it's nil, as? will evaluate to nil
let twData: Any = NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions.MutableLeaves, error: &dataError)
Do not use AnyObject. Use Any instead of AnyObject. It will work fine. AnyObject is for all reference type and Array is a value type. That's why this comes. Change it to Any.
As you already know it is a String type you are inserting to something transformable, please do:
if let twoDataArray = twData as? Array<Dictionary<String, String>>{
for data in twoDataArray{
print(data)
}
}
This will guard you from a crashing app when the dictionary is not of type <String,String>.