Ошибка быстрой компиляции, подкласс NSValue, с использованием super.init(nonretainedObject:)

#swift #nsvalue

#swift #nsvalue

Вопрос:

Этот код

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

выдает эту ошибку компилятора:

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

Как мне избавиться от этого?

Вещи, о которых я думал

Я подумал, что ошибка может быть связана с тем, что NSValue инициализатор имеет AnyObject? тип (обратите внимание: postfix ? ). Я пробовал различные варианты приведения и [?!] постфиксации местами, и это ничего не исправило.

Кроме того, предположительно NSValue(nonretainedObject:) должен быть вызван назначенный инициализатор, верно?

Ответ №1:

NSValue(nonretainedObject:) не является назначенным инициализатором. Единственным инициализатором, указанным в ссылке NSValue (и, следовательно, назначенным инициализатором), является NSValue(value:CConstVoidPointer, withObjCType type:CString)

Все остальные конструкторы являются удобными конструкторами, производными от вспомогательных методов класса.

Вы можете попробовать:

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

«^v» — это строка типа, возвращаемая значением NSValue, созданным с помощью valueWithNonRetained ….

К сожалению, я не придумал подходящего способа передачи baseObject в качестве CConstVoidPointer .

За исключением этого, лучшее, что я могу придумать, это обернуть NSValue вместо его подкласса:

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

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

Наконец-то что-то заработало, но это немного некрасиво, в основном добавьте удобный конструктор, который оборачивает конструктор nonretainedObject, а затем используйте его в своем подклассе:

 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)
    }
}
 

В зависимости от того, что вы на самом деле пытаетесь сделать, одной категории может быть достаточно?

Комментарии:

1. На данный момент я вижу init(nonretainedObject:) в этих документах Apple . Документы кажутся запутанными в том, ссылаются ли они на value/-init методы. Несмотря на это, вы указали путь к хорошему обходному пути.

2. Да, в этих документах довольно четко указано, что init(bytes value: CConstVoidPointer, objCType type: Cstring) это назначенный инициализатор. Теперь, если вы можете просто выяснить, как передать BaseObject, вы в восторге 🙂

3. IIUC, не должно иметь значения, что такое назначенный инициализатор, если вы привязаны к нему. Я бы подумал, что все NSValue удобные инициализаторы должны делать это, верно?

4. В конечном итоге вы должны вызвать (a) назначенный инициализатор из вашего подкласса. Для удобства также существуют некоторые ограничения на пометку инициализаторов, которые не являются назначенным инициализатором, но мне пришлось бы точно посмотреть, каковы правила. По сути, компилятор скажет вам пометить это «удобство», и вы это сделаете 🙂