简体   繁体   中英

Candidate is not '@objc' but protocol requires it

I have been following this tutorial to learn swift & iOS app development. In the Protocol section, the tutorial defined the following protocol:

@objc protocol Speaker {
  func Speak()
  optional func TellJoke()
}

It says If you want to have a protocol with optional methods, you must prefix the protocol with the @objc tag (even if your class is not interoperating with objective-C) .

Then, it shows the sample to implement the protocol:

class Vicki: Speaker {
  func Speak() {
    println("Hello, I am Vicki!")
  }
  func TellJoke() {
    println("Q: What did Sushi A say to Sushi B?")
  }
}

I tried the above code in my xcode playground, but I got the compiler error "Type Vicki doesn't conform to protocol Speaker" .

Xcode also pops up an fix-it text which says "Candidate is not '@objc' but protocol requires it" .

I get completely confused now, the tutorial doesn't mention this error at all. Could someone please explain to me all this to make me clear? Thanks!

From what I can tell, marking your protocol as @objc means that any classes implementing it also have to be exposed to Objective-C. This can be done either by making Vicki a subclass of NSObject:

class Vicki: NSObject, Speaker {

Or by marking each implemented method as @objc:

class Vicki: Speaker {
    @objc func Speak() {
        print("Hello, I am Vicki!")
    }
    @objc func TellJoke() {
        print("Q: What did Sushi A say to Sushi B?")
    }
}

Update: From Apple's Swift Language Documentation

Optional protocol requirements can only be specified if your protocol is marked with the @objc attribute.

...

Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to specify optional requirements, you will only be able to apply that protocol to class types.

In order for a type to conform to a protocol marked @objc , that type must also marked with @objc or the methods being used to satisfy the protocol must be.

Using @objc on a declaration tells the compiler to expose it to the Objective-C runtime. In order for that to be possible, the type that was declared @objc must be able to be represented in Objective-C.

For classes this means they must inherit from NSObject. For methods, this means they become backed by dynamic Objective-C message passing.

Looks like we only need to prefix protocol method with @objc in private class.

private class A: NSObject, SomeObjcProtocol {
  @objc func someProtocolMethod() {}
}

Warning is not likely to rise for non-private class.

class A: NSObject, SomeObjcProtocol {
  func someProtocolMethod() {}
}

Both are fine.

Add an extension to the protocol returning empty functions and default values. Any class that conforms to the protocol and wishes to override any func or var may optionally do so.

    public protocol Speaker {
      func Speak()
      func TellJoke()
    }

    extension Speaker {
      func Speak() {}
      func TellJoke() { print("What did the Teabag say to the Octopus?"}
    }

The bonuses are you don't inherit all of the obj-c baggage.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM