Declaring conformance to @objc protocol in empty e

2019-02-27 18:17发布

问题:

Been having lots and lots of trouble with Swift protocols in combination with arrays, but I couldn't even reproduce my whole problem before things started to break in playground. Here's a minimal example.

I have two protocols and a class Bus which declares conformance to one of the protocols. In addition, an empty extension of Bus declares conformance to the other protocol:

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

The console output may look random but it's not. I get it consistently if I try to create an instance of 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.
  • The error goes away if we comment out all @objc attributes
  • The error goes away if we don't conform to Utterable: extension Bus: Utterable{}

The reason why my protocols must have the attribute @objc is because otherwise the Obj-c runtime will complain when trying to do things like var myDisplayables: [Displayable] = [ Bus() ] or otherwise dynamically check for conformance to a protocol

Again, please note that this is a minimal example.

Update with Swift 1.2: Seems like it's fixed now. Xcode suggests these changes "because the protocol requires it":

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

回答1:

I think that the problem is about the Utterable protocol having a property, which is already implemented in the concrete class.

As you probably know, an extension cannot define stored properties (computed only). By adopting the protocol in the extension, something wrong happens - and it is clearly a bug (it should just work or the compiler should raise a compilation error).

To fix it, just adopt the protocol in the class declaration rather than to the extension:

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

extension Bus  {}

Surprisingly, turning the utterance property into a computed one and moving it in the extension body:

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

doesn't solve the problem - still the same error. I consider it as a prove that it's a bug.