Можете ли вы украсить функцию прерывания отладки, чтобы взломать, откуда эта функция вызывается? - PullRequest
0 голосов
/ 04 мая 2018

Это лучше всего объяснить на примере. Учтите это mustOverride вспомогательная функция:

func mustOverride(callSite:String = #function) -> Never {
    preconditionFailure("\(callSite) must be overridden in a subclass")
}

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

// Faux 'abstract' class
class SoundBase {

    func play(){
        mustOverride()
    }
}

// 'Concrete' class
class CatSound : SoundBase {

    override func play(){
        // play cat 'meow' sound
    }
}

С учетом вышесказанного, если вы создаете экземпляр SoundBase напрямую и вызываете play(), вы активируете функцию mustOverride(), которая выходит из состояния отладки. Проблема в том, что он ломается внутри функции mustOverride(), а не на сайте вызова play().

Microsoft .NET имеет удобную функцию, в которой вы можете украшать функции атрибутами, чтобы изменить их взаимодействие с отладчиком ( см. Здесь для получения дополнительной информации).

Например, у них есть атрибут DebuggerHidden, который, если применить его к mustOverride(), приведет к тому, что отладчик прервет работу внутри вызывающей функции play(), а не внутри mustOverride(), что сохранит вам ненужное путешествие в стек вызовов только для того, чтобы выполнить резервное копирование на один уровень, чтобы выяснить, где на самом деле ошибка.

Мне интересно, есть ли у Swift что-то похожее на эту возможность. Это действительно здорово, когда используется правильно.

1 Ответ

0 голосов
/ 08 октября 2018

Предполагая, что вы отлаживаете в XCode, вы ищете атрибут @_transparent. Вот оно в действии:

@_transparent
func mustOverride(callSite: String = #function) -> Never {
    preconditionFailure("\(callSite) must be overridden in a subclass")
}

class SoundBase {
    func play(){
        mustOverride()
    }
}

class CatSound: SoundBase {
    override func play() {}
}

SoundBase().play()

И результат:

Из документации:

Семантически, @_transparent означает что-то вроде «обрабатывать эту операцию, как если бы она была примитивной операцией». Имя подразумевает, что как компилятор, так и скомпилированная программа будут «видеть сквозь» операцию до ее реализации.

Примечание:

  • Поскольку @_transparent начинается с подчеркивания, оно может измениться в будущем
...