Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust Cocoa - How to Iterate NSArray

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 🙇🏻‍♂️

like image 226
Mikeumus Avatar asked Dec 19 '25 16:12

Mikeumus


2 Answers

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)
like image 67
Rob Napier Avatar answered Dec 21 '25 07:12

Rob Napier


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)) {
   // ...
}
like image 27
Jmb Avatar answered Dec 21 '25 08:12

Jmb