How to pass a Dictionary to Objective-C method in Swift - ios

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);

Related

Create NSMutableDictionsry in Swifty-Json

I want to create a NSMutableDictionary using Swifty-Json.
I have declared dictionary like this
var arrTest = Array<JSON>()
var testDict : JSON = [:]
testDict.dictionaryObject?.updateValue(arrTest[0]["test"][indexPath.item]["xyz"], forKey: "abc")
Now I am unable to setValueForKey in this Dictionary.
Can Someone tell me how to create a NSMutableDictionary using SwiftyJson and also how to insert, update and delete values in this dictionary.
Thanks in advance
Don't use NSMutableDictionary in Swift, use Swift built-in type Dictionary instead. Declaring it as var will make it mutable.
You also don't use updateValue for Dictionary, simply use a subscript:
var testDict : [String : AnyObject] = [:]
let key = "abc"
let value = arrTest[0]["test"][indexPath.item]["xyz"]
testDict[key] = value
// add object
let testobj = ["qwe" : arrTest[0]["test"][indexPath.item]["xyz"]]
dictSelectedOption = JSON(testobj)
//remove objects
dictSelectedOption.dictionaryObject?.removeAll()

How to convert NSDictionary to NSObject in Swift?

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>

How to cast Dictionary in Swift to related type?

This is what I am trying to do with the dictionary:
if let deliveries = dictionary["deliveries"] as? NSDictionary {
var castedDeliveries = [Double: Double]()
for delivery in deliveries {
if let value = delivery.value as? Double {
castedDeliveries[Double(delivery.key as! NSNumber)] = value //Could not cast value of type 'NSTaggedPointerString' (0x1a1e3af20) to 'NSNumber' (0x1a1e458b0).
}
}
settings!.deliveries = castedDeliveries
}
And this is what I try to cast, as a part of JSON response from server:
deliveries = {
2 = 0;
5 = "2.59";
7 = "3.59";
};
It doesnt work, because there is an error at commented line:
Could not cast value of type 'NSTaggedPointerString' (0x1a1e3af20) to 'NSNumber' (0x1a1e458b0).
You are trying to cast dictionary directly but instead you need to cast each key - value pair. If you want generic solution to this problem take a look at SwiftyJSON library which address JSON parsing problem for you.
Casting doens't mean data transformation from a type to another.
Your dictionary seems to be composed by Integer keys and String values.
If you want to transform in something else you ca use the map function.
let converted = deliveries.map{[Double($0) : Double($1)]}
But pay attention.
Here we are saying, iterate over the dictionary (in the $0 there is the dictionary key in the $1 there is the value) and create a new dictionary that has as a key a Double initialized at the key value and as a new value a Double initialized as the old dictionary value. The last conversion can fail, so the returned data is an optional.
As I noted in the comments, this isn't casting. You want a data conversion. You need to do that explicitly, especially in this case since it might fail.
Looking at the error, I think you really have a dictionary of [String:String] here (in NSDictionary form). That suggests the JSON is badly encoded, but such is life. Assuming that dictionary looks something like this:
let dictionary: NSDictionary = ["deliveries": ["2":"0", "5": "2.59", "7": "3.59"]]
You would convert it to [Double:Double] like this:
if let jsonDeliveries = dictionary["deliveries"] as? [String:String] {
var deliveries: [Double: Double] = [:]
for (key, value) in jsonDeliveries {
if let keyDouble = Double(key),
valueDouble = Double(value) {
deliveries[keyDouble] = valueDouble
}
}
// Use deliveries
}
This silently ignores any values that can't be converted to Double. If you would rather generate errors, use a guard let rather than an if let.

Convert from Objective-C NSArray to swift [[String:String]]?

I want to convert from NSArray to swift array [Dictionary<String:String>]
Any help ?
Simple as that:
let someArray = myArray as? [[String:String]]
Optional casting is recommended if you want to make sure you don't get any crashes when converting. You can then use it in if-let constructions like this:
if let dictArray = myArray as? [[String:String]] {
// do something with the array of dictionaries
}
BTW, your initial definition was not correct, there's no such thing as Dictionary<String:String>, the correct definition is Dictionary<String, String>.

I can't downcast an NSDictionary, CFDictionaryRef, nor an NSMutableDictionary, to SecItemAdd()

I don't understand Keychain that well. As far as I know you want to send a CFDictionaryRef to SecItemAdd() to store the attributes in applications' keychain. I'm probably not understanding unwrapping or something. I feel like the answer is obvious but this is my first experience with something so low-level, so please be patient with me. :)
Here's my Swift:
var keychainDictionary : NSMutableDictionary? = NSMutableDictionary()
var username = "Arcrammer"
var password = "somePassword"
var site = "http://www.hausofalexander.tk/"
// Item class
keychainDictionary![(kSecClass as String)] = kSecClassInternetPassword
// Attributes
keychainDictionary![(kSecAttrAccount as String)] = username
keychainDictionary![(kSecAttrService as String)] = "Haus"
keychainDictionary![(kSecAttrAccessible as String)] = kSecAttrAccessibleWhenUnlockedThisDeviceOnly as CFTypeRef)
keychainDictionary![(kSecMatchCaseInsensitive as String)] = (kCFBooleanTrue asCFTypeRef)
keychainDictionary![(kSecReturnData as String)] = (kCFBooleanTrue as CFTypeRef)
// Completely mutable NSDictionary from the NSMutableDictionary
var result : OSStatus?
SecItemAdd(keychainDictionary!, result)
I've created an empty and optional NSMutableDictionary() to hold the Keychain dictionary attributes and values. Next, I add add some kSecAttr- values to the dictionary as keys. I'm also casting them as String because the compiler throws the error LoginViewController.swift:112:37: Type 'CFStringRef' does not conform to protocol 'NSCopying' if I try to them as CFTypeRef or I don't try to cast them at all. Of course, String does conform to the NSCopying protocol. I don't know if this has an effect on the attribute value, but it definitely dismisses the error.
After that I continue to pass information as the String data type. From what I've gathered (which isn't much, tbh) CFTypeRef is an enumeration and the data returned by something like kCFBooleanTrue will return the type value from that enumeration which would be something like CFBoolean, CFDictionary, or basically what AnyObject or id would be to Foundation.
After that I proceed to create an empty variable named result with the type OSStatus. This variable will hold the result of the AddSecItem() function following on line 118.
However, I'm given the following error:
swift:118:17: Cannot convert the expression's type '(#lvalue NSMutableDictionary, #lvalue OSStatus?)' to type 'CFDictionary!'
I have no idea what this means and I can't figure it out. What in the world am I doing wrong here?
I don't know the parameter supply for SecItemAdd but you need more something like
var idontknow = UnsafeMutablePointer<Unmanaged<AnyObject>?>()
result = SecItemAdd(keychainDictionary!, idontknow)
Try to find out from the docu what idontknow exactly is.

Resources