Rust Cocoa - How to make an NSDictionary?

326 Views Asked by At

I've been reading around trying to understand it. You can see here dictionaryWithObjects:objects the takes an array of Objects and Keys:

NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
                                                       forKeys:keys
                                                         count:count];

https://developer.apple.com/documentation/foundation/nsdictionary#overview


but initWithObjectsAndKeys_ only a single Object for input? ‍♂️

unsafe fn initWithObjectsAndKeys_(self, firstObject: *mut Object) -> *mut Object

https://docs.rs/cocoa/0.24.0/cocoa/foundation/trait.NSDictionary.html#tymethod.initWithObjectsAndKeys_

3

There are 3 best solutions below

2
Josh Matthews On BEST ANSWER

Many of Rust cocoa APIs are direct wrappers of the underlying Objective-C APIs, like initWithObjectsAndKeys: https://developer.apple.com/documentation/foundation/nsdictionary/1574190-initwithobjectsandkeys?language=objc. Callers are expected to pass a pointer to the first element of a null-terminated array containing alternating value and key elements for the dictionary.

0
Scott Thompson On

In Objective C you call initWithObjectsAndKeys like this:

NSMutableDictionary *aDictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
                                    @"Value1", @"Key1",
                                    @"Value2", @"Key2",
                                    @"Value3", @"Key3",
                                    nil, nil
];

(Technically speaking, one nil would be sufficient, but I find it lacks symmetry so I put two :-P)

It's a variadic function that can take multiple arguments.

I'm afraid I don't know enough about Rust to know if it can handle things the same way.

0
Mikeumus On

Of course after learning how to do it from the great answers here (as well as, before posting this question, searching the repo, all GitHub, and the web for an undisclosed amount of time), I find an example in a test from @Josh Matthews servo/core-foundation-rs library here:

let mkstr = |s| unsafe { NSString::alloc(nil).init_str(s) };
let keys = vec!["a", "b", "c", "d", "e", "f"];
let objects = vec!["1", "2", "3", "4", "5", "6"];

unsafe {
               
  let keys_raw_vec = keys.clone().into_iter().map(&mkstr).collect::<Vec<_>>();
  let objs_raw_vec = objects.clone().into_iter().map(&mkstr).collect::<Vec<_>>();

  let keys_array = NSArray::arrayWithObjects(nil, &keys_raw_vec);
  let objs_array = NSArray::arrayWithObjects(nil, &objs_raw_vec);

  let dict = NSDictionary::dictionaryWithObjects_forKeys_(nil, objs_array, keys_array);
}

From https://github.com/servo/core-foundation-rs/blob/355740417e69d3b1a8d909f84d91a6618c9721cc/cocoa-foundation/tests/foundation.rs#L145