Rust Cocoa - How to Iterate NSArray

361 Views Asked by At

From brandonhamilton/image-capture-core-rs's ICCameraDevice.mediaFiles() I can get the NSArray::count() (from core-foundation-rs) :

let cam_media_files = camera_device.mediaFiles();

println!(
  NSArray::count(cam_media_files)  // 123
);

But how can you iterate this Object?

I've tried a couple things:

// for media_file in NSArray::array(nil, cam_media_files) {
// for media_file in NSArray::arrayWithObject(nil, cam_media_files) {
for media_file in cam_media_files {
    println!("   media_file: {:?}", media_file);
}

All result in something like this:

error[E0277]: `*mut Object` is not an iterator
  --> src/image_capture_core_mod.rs:86:31
   |
86 |             for media_file in cam_media_files {
   |                               ^^^^^^^^^^^^^^^ `*mut Object` is not an iterator
   |
   = help: the trait `Iterator` is not implemented for `*mut Object`
   = note: required because of the requirements on the impl of `IntoIterator` for `*mut Object`
   = note: required by `into_iter`

Not much to work with here: https://docs.rs/cocoa/0.24.0/cocoa/foundation/trait.NSArray.html

What am I missing?

Thank you ‍♂️

3

There are 3 best solutions below

0
Jmb On BEST ANSWER

According to the docs, NSArray has an objectAtIndex method, so this should work:

for idx in 0..NSArray::count (cam_media_files) {
   let media_file = NSArray::objectAtIndex (cam_media_files, idx);
   // ...
}

or if you want to do it with iterators:

for media_file in (0..NSArray::count (cam_media_files)).map (|idx| NSArray::objectAtIndex (cam_media_files, idx)) {
   // ...
}
2
Zeppi On

I don't know Cocoa well, and I'm just giving you a path that I hope can help you find the solution.

You use do let cam_media_files = camera_device.mediaFiles(); and mediaFiles(self) -> id;

Wath is id?

pub type id = *mut runtime::Object;

The doc about runtime::Object this is https://docs.rs/objc/0.2.7/objc/ and you can use msg_send! crate to call Cocoa methode

let cls = class!(NSObject);
let obj: *mut Object = msg_send![cls, new];
let hash: usize = msg_send![obj, hash];
3
Rob Napier On

You're missing the .iter():

for media_file in cam_media_files.iter() {

In ObjC, NSArray implements NSFastEnumeration, which is how ObjC implements its for...in syntax.

This crate's bridge to NSFastEnumeration provides iter(), which returns an NSFastIterator. (NSFastIterator is not a Cocoa type. It's something this crate provides to bridge NSFastEnumeration to Iterator.)

Note that this crate applies NSFastEnumeration to all object types (that's what id means), even ones that don't implement NSFastEnumeration in Cocoa. That means that you can iterate on anything...but it'll crash at runtime if it's not supported by Cocoa, and you won't get a compile time warning or error:

let string = cam_media_files.objectAtIndex(0);
for x in string.iter() {} // *Crash* (NSString doesn't support this)