2

This code

class ID<T: AnyObject> : NSValue {
    init(baseObject: T) {
        super.init(nonretainedObject: baseObject)
    }
}

gives this compiler error:

error: must call a designated initializer of the superclass 'NSValue'
    super.init(nonretainedObject: baseObject)
    ^

How do I get rid of this?

Things I thought of

I thought the error might be because the NSValue initializer has an AnyObject? type (Note well: postfix ?). I tried various flavors of casting and [?!] postfixing in places, and it fixed nothing.

Also, presumably NSValue(nonretainedObject:) must call the designated initializer, right?

Clay Bridges
  • 11,602
  • 10
  • 68
  • 118

1 Answers1

2

NSValue(nonretainedObject:) isn't a designated initializer. The only initializer listed in the NSValue reference (and hence the designated initializer) is NSValue(value:CConstVoidPointer, withObjCType type:CString)

The other constructors are all convenience constructors derived from class helper methods.

You might try:

init(baseObject: T) {
    super.init(bytes:&baseObject, withObjCType:"^v")
}

"^v" is the type string returned by an NSValue created with valueWithNonRetained....

Unfortunately, I'm not coming up with an appropriate way to pass baseObject as a CConstVoidPointer.

Barring that, the best thing I can come up with is to wrap NSValue instead of subclassing it:

class ID<T:AnyObject> {
    let wrapped:NSValue

    init(baseObject:T) {
        wrapped = NSValue(nonretainedObject:baseObject)
    }
}

Finally got something to work, but it's a little bit ugly, basically add a convenience constructor that wraps the nonretainedObject constructor and then use that in your subclass:

extension NSValue {
    convenience init<T:AnyObject>(unretained:T) {
        self.init(nonretainedObject:unretained)
    }
}


class ID<T>:NSValue {
    convenience init<T:AnyObject>(unretained:T) {
        self.init(unretained:unretained)
    }
}

Depending on what you're actually trying to do the category alone might be sufficient?

David Berry
  • 40,941
  • 12
  • 84
  • 95
  • At the moment, I see `init(nonretainedObject:)` in [these Apple docs](https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Classes/NSValue_Class/index.html) . The docs seem confused on whether they are referring to `+value/-init` methods. Regardless, you've pointed the way to a good workaround. – Clay Bridges Jun 27 '14 at 16:16
  • Yeah, those docs are pretty explicit that `init(bytes value: CConstVoidPointer, objCType type: Cstring)` is the designated initializer. Now if you can just figure out how to pass baseObject in you're golden :) – David Berry Jun 27 '14 at 16:20
  • IIUC, it shouldn't matter what the designated initializer is, so long as you chain to it. I'd figure all of `NSValue`s convenience initializers should be doing this, right? – Clay Bridges Jun 27 '14 at 16:22
  • You have to eventually call the (a) designated initializer from your subclass. There's also some restrictions on flagging initializers that aren't the designated initializer as convenience, but I'd have to look up exactly what the rules are. Basically the compiler will tell you to flag it "convenience" and you do :) – David Berry Jun 27 '14 at 16:30