Инициализировать подкласс, который требует `init (coder: NSCoder)` - PullRequest
0 голосов
/ 15 января 2019

Я хочу создать подкласс CAShapeLayer, чтобы он содержал ссылку на соответствующий объект в модели данных:

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

Где itsDataRef и itsEventData - это ссылки (указатели, если хотите) на базовые данные. Таким образом, я могу обновить модель, если переместил экземпляр класса майского слоя, или нарисовать его, используя стили графики, указанные в eventData. Мой CPCoursePointLayer не владеет этими переменными, чтобы использовать термин Rust.

Теперь, когда мне нужно реализовать инициализатор init(coder:), как мне инициализировать переменные моего экземпляра из ничего? Могу ли я декодировать указатель из NSCoder? Это не имеет смысла для меня ...

Хотя я никогда не собираюсь звонить init(coder:), сам, я думаю, что это там, потому что система может вызвать это. Тогда у меня будет экземпляр, который нельзя использовать ...

Я хочу избежать дополнительного бремени выполнения дополнительных if let в каждом методе, если я объявлю переменные своего экземпляра как необязательные (?).

Ответы [ 2 ]

0 голосов
/ 15 января 2019

У вас есть три варианта:

  1. Объявление переменных как неявно развернутых опций
  2. У init?(coder:) сбой, смертельно или нет
  3. У CPCoursePoint и CPEventData есть возможность разархивировать через init?(coder:)

Вариант 1:

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint!
    let itsEventData :CPEventData!

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

Это приведет к сбою, если вы ссылаетесь на itsDataRef или itsEventData и ваш объект не был инициализирован вашим новым инициализатором.

Вариант 2 (а)

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        return nil
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

Это просто не сможет инициализировать объект, если используется init(coder:).

Вариант 2 (б)

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) is not supported for this class"
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

Это вызовет сбой вашей программы, если будет вызван init(coder:).

Вариант 3

class CPCoursePointLayer : CAShapeLayer
{
    let itsDataRef :CPCoursePoint
    let itsEventData :CPEventData

    required init?(coder aDecoder: NSCoder) {
        guard let itsDataRef = aDecoder.decodeObject(forKey:"itsDataRef"),
              let itsEventData = aDecoder.decodeObject(forKey:"itsEventData") else {
            return nil
        }
        self.itsDataRef = itsDataRef
        self.itsEventData = itsEventData
        super.init(coder: aDecoder)
    }

    init( coursePoint: CPCoursePoint, in eventData :CPEventData)
    {
        itsDataRef = coursePoint
        itsEventData = eventData
    }
}

Вариант 2 (b), вероятно, является наиболее распространенным, так как это "быстрый отказ" - вы должны уловить это во время тестирования довольно быстро, если вызывается этот инициализатор.

0 голосов
/ 15 января 2019

Типичным решением, если вы не хотите поддерживать NSCoding в своем подклассе, является fatalError в init(coder:). Фактически, компилятор даже предложит это как исправление, если вы полностью опустите инициализатор:

fix-it

Так что просто сделайте это:

class CPCoursePointLayer: CAShapeLayer {
    let itsDataRef: CPCoursePoint
    let itsEventData: CPEventData

    init(coursePoint: CPCoursePoint, in eventData: CPEventData) {
        itsDataRef = coursePoint
        itsEventData = eventData
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Система обычно не пытается декодировать экземпляр вашего пользовательского слоя.

...