Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to cast NSString to AnyObject? #687

Open
crutchcorn opened this issue Jan 2, 2025 · 1 comment
Open

How to cast NSString to AnyObject? #687

crutchcorn opened this issue Jan 2, 2025 · 1 comment
Labels
A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates question Further information is requested

Comments

@crutchcorn
Copy link

Apologies for this being a naive question, I'm new to Rust and even newer to objc2.

Looking at Apple's docs for MPNowPlayingInfoCenter's nowPlayingInfo, I see:

var nowPlayingInfo: [String : Any]? { get set }

But this Any is the cause of some headaches for me. According to the reference docs, the following should be allowed:

  func setNowPlayingMetadata(_ metadata: NowPlayableStaticMetadata) {
       
        let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
        var nowPlayingInfo = [String: Any]()
        
        NSLog("%@", "**** Set track metadata: title \(metadata.title)")
        nowPlayingInfo[MPNowPlayingInfoPropertyAssetURL] = metadata.assetURL
        nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = metadata.mediaType.rawValue
        nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = metadata.isLiveStream
        nowPlayingInfo[MPMediaItemPropertyTitle] = metadata.title
        nowPlayingInfo[MPMediaItemPropertyArtist] = metadata.artist
        nowPlayingInfo[MPMediaItemPropertyArtwork] = metadata.artwork
        nowPlayingInfo[MPMediaItemPropertyAlbumArtist] = metadata.albumArtist
        nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = metadata.albumTitle
        
        nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
    }

However, when trying to do the same with Rust:

pub fn set_now_playing() {
    unsafe {
        let default = MPNowPlayingInfoCenter::defaultCenter();
        MPNowPlayingInfoCenter::setNowPlayingInfo(&*default, {
            let keys = &[
                MPNowPlayingInfoPropertyAssetURL,
                MPNowPlayingInfoPropertyMediaType,
                MPNowPlayingInfoPropertyIsLiveStream,
                MPMediaItemPropertyTitle,
                MPMediaItemPropertyArtist,
                MPMediaItemPropertyArtwork,
                MPMediaItemPropertyAlbumArtist,
                MPMediaItemPropertyAlbumTitle
            ];
            let owned_objects = &[
                NSString::from_str("https://example.com"),
                NSString::from_str("1"),
                NSString::from_str("false"),
                NSString::from_str("Title"),
                NSString::from_str("Artist"),
                NSString::from_str("Artwork"),
                NSString::from_str("Album Artist"),
                NSString::from_str("Album Title")
            ];
            Some(objc2_foundation::NSDictionary::from_id_slice(keys, owned_objects).as_ref())
        });
    }
}

I get an error:

mismatched types
expected reference `&NSDictionary<_, AnyObject>`
   found reference `&NSDictionary<_, NSString>`rustcClick for full compiler diagnostic

How can I fix this?

crutchcorn added a commit to crutchcorn/moonsound that referenced this issue Jan 2, 2025
@madsmtm madsmtm added question Further information is requested A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates labels Jan 2, 2025
@madsmtm
Copy link
Owner

madsmtm commented Jan 2, 2025

There are several ways around it, and unfortunately none of them very pretty :/.

One of them is something like:

let owned_objects: &[Retained<AnyObject>] = &[
    Retained::into_super(Retained::into_super(NSString::from_str("https://example.com"))),
    Retained::into_super(Retained::into_super(NSString::from_str("1"))),
    Retained::into_super(Retained::into_super(NSString::from_str("false"))),
    Retained::into_super(Retained::into_super(NSString::from_str("Title"))),
    Retained::into_super(Retained::into_super(NSString::from_str("Artist"))),
    Retained::into_super(Retained::into_super(NSString::from_str("Artwork"))),
    Retained::into_super(Retained::into_super(NSString::from_str("Album Artist"))),
    Retained::into_super(Retained::into_super(NSString::from_str("Album Title")),
];

And in the soon-to-be-released objc2-foundation v0.3, it'll look like this:

let owned_objects: &[Retained<AnyObject>] = &[
    NSString::from_str("https://example.com").into(),
    NSString::from_str("1").into(),
    NSString::from_str("false").into(),
    NSString::from_str("Title").into(),
    NSString::from_str("Artist").into(),
    NSString::from_str("Artwork").into(),
    NSString::from_str("Album Artist").into(),
    NSString::from_str("Album Title").into(),
];

Which is better, but still not great. Doing the kind of upcasting you desire (NSDictionary<X, Y> -> NSDictionary<X, AnyObject>) is tracked in #654.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants