# MacOS: Can't create a delegate that gets called

**URL:** <https://users.rust-lang.org/t/macos-cant-create-a-delegate-that-gets-called/47184>\
**Category:** help\
**Created:** [August 11, 2020, 8:27pm UTC](https://users.rust-lang.org/t/macos-cant-create-a-delegate-that-gets-called/47184 "2020-08-11T20:27:12Z")\
**Posts on this page:** 1\
**Showing post:** 3

<div class="post-metadata">

**Author:** ![nolan](https://avatars.discourse-cdn.com/v4/letter/n/aeb1de/32.png) [@nolan](https://users.rust-lang.org/u/nolan)\
**Post date:** [August 11, 2020, 10:26pm UTC](https://users.rust-lang.org/t/macos-cant-create-a-delegate-that-gets-called/47184/3 "2020-08-11T22:26:14Z")

</div>

> [@H2CO3](#):
>
> Your delegate class doesn't conform to the `NSSpeechSinthesizerDelegate` protocol. Maybe the `NSSpeechSynthesizer` class checks actual protocol conformance and not only the existence of the delegate callback method? Also, shouldn't the delegate method be called `speechSynthesizer:didFinishSpeaking:` as per [the documentation](https://developer.apple.com/documentation/appkit/nsspeechsynthesizerdelegate/1448538-speechsynthesizer?language=objc)? It also takes the speech synthesizer object as its first argument, not only a `BOOL` (that your current implementation assumes).

So, a couple questions:

1. What are you proposing the correct syntax be here? I've tried several different things and none worked. I'm not sure what to name the selector, particularly since any additional `:` in the name causes the function to need new arguments.

2. Isn't my current function accepting the sender? See the first argument, which I ignore for now.

```rust
        extern "C" fn speech_synthesizer_did_finish_speaking(_: &Object, _: Sel, _: BOOL) {

```

> [@](#):
>
> By the way, there are several other strange things in your code:

I'll address these, but note that nice code that doesn't work is worse than ugly code that does. 🙂 At least the latter can be fixed up.

> [@](#):
>
> – you seem to use `+new` for allocating and initializing the speech synthesizer object but you make separate `+alloc` and `-init` calls for creating the delegate object. This in turn results in uglier code (e.g. unnecessary mutability).

I thought so, but I don't fully understand the `new`/`alloc`/`init` distinction. Figured I'd get this working then iterate on that. If it works, then I can clean it up until it doesn't, then roll the breaking change back.

> [@](#):
>
> – The `let _: () =` declaration before the `setDelegate:` method call is unnecessary.

If I do:

```rust
        unsafe { msg_send![obj, setDelegate: delegate_obj] };

```

I get:

```rust
error[E0282]: type annotations needed
  --> src/backends/ns_speech_synthesizer.rs:31:18
   |
31 | unsafe { msg_send![obj, setDelegate: delegate_obj] };
   | 41 caret characters consider giving `result` a type
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error

```

Also, the type annotation is required as per the [docs](https://github.com/SSheldon/rust-objc/):

```rust
// Even void methods must have their return type annotated
let _: () = msg_send![obj, release];

```

Could be that I'm misunderstanding something.

> [@](#):
>
> – The `NSSpeechSynthesizerBackend` struct contains two pointers to allocated objects yet you never `-release` them. Shouldn't you be implementing `Drop` for your struct where you release both objects?

Yes I should, but code that doesn't work and cleans up after itself isn't really useful to me. Plus, there's going to be much more cleanup later when I'm managing a `Vec<NSString>` so might as well just do it all then once things work.

I've done a bit more digging, and it seems like the issue may be my lack of an `NSRunLoop`. Formerly my example did:

```rust
    io::stdin().read_line(&mut _input)?;

```

to block and allow for text to speak. But apparently that doesn't let delegates run. Now I'm doing:

```rust
    let run_loop: id = unsafe { NSRunLoop::currentRunLoop() };
    unsafe {
        let _: () = msg_send![run_loop, run];
    }
    // io::stdin().read_line(&mut _input)?;

```

The example still blocks, and _Enter_ doesn't terminate anymore. So it seems like the `NSRunLoop` may be working. But the delegate still isn't running.

Thanks for any help. Ugh, this is way more painful than working with Microsoft's preview WinRT bindings in a VM was. 😕

---

_[View the full topic](https://users.rust-lang.org/t/macos-cant-create-a-delegate-that-gets-called/47184)._
