简体   繁体   English

为什么 Swift Class-Only 协议需要 AnyObject 继承?

[英]Why do Swift Class-Only Protocols need AnyObject Inheritance?

I am trying to figure out Swift Documentation: https://docs.swift.org/swift-book/LanguageGuide/Protocols.html我想弄清楚 Swift 文档: https : //docs.swift.org/swift-book/LanguageGuide/Protocols.html

But I stuck at this issue, Why need AnyObject, I mean why i need to use that kind of restriction ?但我坚持这个问题,为什么需要 AnyObject,我的意思是为什么我需要使用那种限制? Is that a bad idea to not restrict for value and reference types just not using Any or AnyObject ?不限制值和引用类型只是不使用 Any 或 AnyObject 是一个坏主意吗?

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

Anyone can explain me some example with codes especially will be very helpful.任何人都可以用代码向我解释一些示例,这将非常有帮助。 Thanks.谢谢。

By the way that answer can be good but literally explanations made me confusing Why use class only protocols in Swift?顺便说一句,答案可能很好,但字面上的解释让我感到困惑为什么在 Swift 中仅使用类协议?

When you write a protocol, you define an interface for the types which adopt, or conform to the protocol:当您编写协议时,您为采用或符合协议的类型定义了一个接口:

// Every Greeter has a greeting message
// and a way for it to present that message.
protocol Greeter {
    var greeting: String { get }
    func greet()
}

extension Greeter {
    // Default implementation for the `greet` method.
    func greet() {
        print(self.greeting)
    }
}

This gives consistent behavior to every type which conforms and lets you treat them all in the same way regardless of what they are.这为每种符合的类型提供了一致的行为,并让您以相同的方式对待它们,而不管它们是什么。 For instance, a type can store a value bound to a protocol type:例如,类型可以存储绑定到协议类型的值:

struct Store {
    // The name of the store.
    var name: String

    // The address of the store.
    var address: String

    // An entity that greets customers when they walk in.
    var greeter: Greeter
}

In this case, Store.greeter can be set to any value or object which conforms to the Greeter protocol:在这种情况下, Store.greeter可以设置为任何符合Greeter协议的值或对象:

struct Bell: Greeter {
    let greeting = "Ding!"
}

class Person: Greeter {
    let greeting: String

    init(name: String) {
       greeting = "Welcome! My name is \(name)."
    }
}

var store = Store(name: "My Shop", address: "123 Main St.", greeter: Bell())
store.greeter.greet() // => "Ding!"

store.greeter = Person(name: "Itai")
store.greeter.greet() // => "Welcome! My name is Itai."

By default, a protocol can be adopted by both value types and object types, ie, both struct s and class es.默认情况下,一个协议可以被值类型和对象类型采用,即struct s 和class es。 This is a good default because in many cases, there's no reason to restrict who can conform to a protocol.这是一个很好的默认设置,因为在许多情况下,没有理由限制谁可以遵守协议。

However, there is one case where this matters.但是,在一种情况下这很重要。 By default, Store owns its greeter property, ie, when you assign an object to store.greeter , it is retained.默认情况下, Store拥有greeter属性,即,当您将一个对象分配给store.greeter ,它会被保留。 This is normally fine, except when you have a potentially circular relationship (for example, if Person has a reference to the Store they work at).这通常很好,除非您有潜在的循环关系(例如,如果Person有对他们工作的Store的引用)。

Normally, to break a potential circular chain like this up, you would make the variable weak :通常,要打破这样的潜在循环链,您可以将变量设置为weak

struct Store {
   // ...
   weak var greeter: Greeter?
   //       ^ error: 'weak' must not be applied to non-class-bound 'Greeter'; consider adding a protocol conformance that has a class bound
}

If you try this, though, you'll get the above error.但是,如果您尝试此操作,则会收到上述错误。 This is because weak only makes sense for objects, not for struct s ( struct s can only be owned because they are value types — every owner just makes a copy of a struct , so there is no one central value to retain or release).这是因为weak只对对象有意义,对struct s 没有意义( struct s 只能被拥有,因为它们是值类型——每个所有者只是制作一个struct的副本,所以没有一个中心值要保留或释放)。 In this case, to ensure a weak reference, you must ensure that Greeter an only be an object type.在这种情况下,要确保weak引用,您必须确保Greeter只能是一个对象类型。

The way to do this is to constrain the protocol to only allow classes to conform by using AnyObject as a constraint:这样做的方法是通过使用AnyObject作为约束来限制协议只允许类符合:

protocol Greeter: AnyObject {
    // ...
}

Now, Bell can't conform to Greeter any more ( error: non-class type 'Bell' cannot conform to class protocol 'Greeter' ) but you are allowed to have weak var greeter: Greeter?现在, Bell不能再符合Greeter了( error: non-class type 'Bell' cannot conform to class protocol 'Greeter' )但是你可以使用weak var greeter: Greeter? as a variable.作为变量。


So, when should you restrict your protocol to be "class-bound" (using AnyObject )?那么,什么时候应该将协议限制为“类绑定”(使用AnyObject )? Well, only when you really have to.好吧,只有当你真的必须这样做的时候。 The one benefit for class-bound protocols is to allow weak references to them, and the main use-case for that is with delegate references to prevent circular retains.类绑定协议的一个好处是允许对它们进行weak引用,主要用例是使用委托引用来防止循环保留。

For instance, UITableView has a weak delegate property because the delegate object is usually the view controller which owns the UITableView object itself.例如, UITableView有一个weak delegate属性,因为delegate对象通常是拥有UITableView对象本身的视图控制器。 If the view controller retains the table view, and the table view retains the controller, neither can be released automatically.如果视图控制器保留表视图,表视图保留控制器,则两者都不能自动释放。

So, in the general case, you don't need to worry about the AnyObject constraint unless you really do only want classes to conform to the protocol.因此,在一般情况下,您无需担心AnyObject约束,除非您确实只希望类符合协议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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