Ваш Project
модуль декларирует соответствие MyClass
ProtocolA
.
Swift реализует это соответствие, используя структуру данных, называемую «таблица-свидетель протокола».Для каждого метода, объявленного протоколом, таблица свидетелей содержит функцию, которая вызывает фактическую реализацию метода для соответствующего типа.
Конкретнее, существует таблица свидетелей для соответствия MyClass
ProtocolA
.Эта таблица свидетелей содержит функцию для метода dontCrash
, объявленного ProtocolA
.Эта функция в таблице свидетелей вызывает метод MyClass
dontCrash
.
Вы можете увидеть функцию из таблицы свидетелей протокола в трассировке стека, когда ваш тестовый набор достигнет fatalError
:
#8 0x00000001003ab9d9 in _assertionFailure(_:_:file:line:flags:) ()
#9 0x00000001000016fc in ProtocolA.dontCrash() at /Users/rmayoff/TestProjects/Project/Project/AppDelegate.swift:11
#10 0x0000000100001868 in protocol witness for ProtocolA.dontCrash() in conformance MyClass ()
#11 0x000000010000171e in ProtocolA.tryCrash() at /Users/rmayoff/TestProjects/Project/Project/AppDelegate.swift:15
#12 0x00000001030f1987 in ProjectTests.testExample() at /Users/rmayoff/TestProjects/Project/ProjectTests/ProjectTests.swift:12
#13 0x00000001030f19c4 in @objc ProjectTests.testExample() ()
Кадр # 10 - это вызов от tryCrash
функции в таблице свидетелей протокола.Кадр № 9 - это вызов от функции таблицы-свидетеля протокола к фактической реализации dontCrash
.
Swift генерирует таблицу-свидетеля протокола в модуле, который декларирует соответствие.Таким образом, в вашем случае таблица свидетелей является частью модуля Project
.
Переопределение dontCrash
в вашем тестовом комплекте не может изменить содержимое таблицы свидетелей.Слишком поздно для этого.Таблица свидетелей была полностью определена, когда Swift сгенерировал модуль Project
.
Вот почему это должно быть так:
Предположим, я автор модуля Project
, а выВы просто пользователь этого.Когда я писал модуль Project
, я знал, что вызов MyClass().dontCrash()
вызовет fatalError
, и я полагался на это поведение.Во многих местах внутри Project
я звонил MyClass().dontCrash()
именно потому, что знал, что это будет fatalError
.Вы, как пользователь Project
, не знаете, насколько Project
зависит от этого поведения.
Теперь вы используете в своем приложении модуль Project
, но вы ретроактивно меняете MyClass().dontCrash()
нане звоните fatalError
.Теперь все те места, где Project
звонит MyClass().dontCrash()
, ведут себя не так, как я ожидал, когда писал модуль Project
.Вы сломали модуль Project
, даже если не изменили исходный код модуля Project
или любого из модулей, которые импортирует Project
.
Это важно для правильной работыProject
модуль, чтобы этого не случилось.Таким образом, единственный способ изменить то, что означает MyClass().dontCrash()
(при вызове из модуля Project
), - это изменить исходный код самого модуля Project
(или изменить исходный код того, что импортирует Project
).