1

Было много проблем с протоколами Swift в сочетании с массивами, но я даже не мог воспроизвести всю свою проблему до того, как все стало ломаться на детской площадке. Вот минимальный пример.Объявление соответствия протоколу @objc в пустых разрывах расширений с EXC_BAD_INSTRUCTION

У меня есть два протокола и класс Bus, который декларирует соответствие одному из протоколов. Кроме того, пустое расширение Bus заявляет о соответствии с другим протоколом:

import Foundation 

@objc 
protocol Displayable { var name: String {get} } 

@objc 
protocol Utterable { var utterance: String {get} } 

class Bus : Displayable { var name = "a bus"; var utterance = "this is a bus"} 

extension Bus : Utterable {} 

var bus1 = Bus() // this line fails with EXC_BAD_INSTRUCTION 

Выход консоли может выглядеть случайным образом, но это не так. Я получаю это последовательно, если я пытаюсь создать экземпляр Bus:

objc[9658]: Method cache corrupted. This may be a message to an invalid object, or a memory error somewhere else. 
objc[9658]: unused 0x0, SEL 0x10e4ce130, isa 0x1181f9ad0, cache 0x1181f9ae0, buckets 0x7fc491501060, mask 0x0, occupied 0x0 
objc[9658]: unused 0 bytes, buckets 64 bytes 
objc[9658]: selector 'resolveInstanceMethod:' 
objc[9658]: isa '__lldb_expr_1314.Bus' 
objc[9658]: Method cache corrupted. 
  • ошибка исчезнет, ​​если мы закомментируйте все @objc атрибуты
  • ошибка уходит, если мы не соответствуют Utterable: extension Bus : Utterable {}

причина, почему мои протоколы MUST имеют атрибут @objc, потому что в противном случае среда выполнения Obj-c будет жаловаться при попытке сделать что-то вроде var myDisplayables: [Displayable] = [ Bus() ] или иначе динамически проверять на соответствие протоколу

Снова обратите внимание, что это минимальный пример.

Обновление с помощью Swift 1.2: Похоже, что оно исправлено. Xcode предлагает эти изменения «так как протокол требует»:

class Bus : Displayable { @objc var name = "a bus"; @objc var utterance = "this is a bus"} 

ответ

1

Я думаю, что проблема о протоколе Utterable, имеющий свойство, которое уже реализуется в конкретном классе.

Как вы, вероятно, знаете, расширение не может определять сохраненные свойства (только для вычисления). Принимая протокол в расширении, происходит что-то неправильное - и это явно ошибка (он должен просто работать или компилятор должен поднять ошибку компиляции).

Чтобы исправить это, просто принять протокол в объявлении класса, а не к расширению:

class Bus : Displayable, Utterable { var name = "a bus"; var utterance = "this is a bus"} 

extension Bus {} 

Удивительно, превращая utterance собственности в вычисленной один и перемещая его в теле расширения:

extension Bus : Utterable { 
    var utterance: String { return "this is a bus" } 
} 

не решает проблему - по-прежнему та же ошибка. Я считаю это доказательством того, что это ошибка.