Unwrapping Unmanaged<SKIndex>

This compiler error is confusing me.

'Unmanaged' is not convertible to 'SKIndex'; did you mean to use 'as!' to force downcast?

In this function below, doc is an Unmanaged<SKDocument> and the compiler is fine with the as. But it doesn't like a similar construction with skIndex: Unmanaged<SKIndex>. I tried changing as to as! but it crashes at runtime.

How do I pass the SKIndex to that function? (It's from Search Kit.)

func addCardToIndex(card: Card) {
    guard let skIndex = self.skIndex else { fatalError() }
    let doc = SKDocumentCreate("card" as CFString, nil, card.id.description as CFString)!
    let contents = "foo bar baz"
    let replace = true
    SKIndexAddDocumentWithText(
         skIndex as SKIndex /* error */, 
         doc as SKDocument, contents as CFString, replace)
}

You most likely want to call skIndex.takeUnretainedValue() instead of skIndex as SKIndex. Perhaps this will be helpful.

1 Like

Yup, that appears to do it.

The as compiled with SKDocument, but causes a failure at runtime. I needed to replace that with doc.takeUnretainedValue() as well, to get the function call to succeed.

To be clear, this is most likely not the best way to work with SKIndex or similar, refer to this SO answer. Ideally, you should have already called takeRetainedValue() whenever you've got that Unmanaged<SKIndex> passed to you by one of the SKIndexCreate* functions. I'm not an expert in Foundation's reference-counted types anyways though, so perhaps somebody else chimes in and provides better guidance.

1 Like

Nikita Belov wrote:

Ideally, you should have already called takeRetainedValue() whenever
you've got that Unmanaged<SKIndex> passed to you by one of the
SKIndexCreate* functions.

That’s exactly right. Your goal here should be to minimise the amount of unmanaged stuff that you do. In this case that means converting from an unmanaged reference to a managed reference as soon as possible. I often do that by writing a small wrapper, for example:

func SKDocumentCreateQ(_ scheme: String, parent: SKDocument?, name: String) -> SKDocument? {
    guard let doc = SKDocumentCreate(scheme as NSString, parent, name as NSString) else {
        // This returns `nil` on error but it might make more sense to throw.
        return nil
    }
    return doc.takeRetainedValue()
}

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

2 Likes
Terms of Service

Privacy Policy

Cookie Policy