简体   繁体   中英

Calling class properties from within protocol extension

In using protocol extension for default implementation I encounter a problem. I define a protocol with different optional properties and functions to use. In the extension I implement a default function and nil properties. In the implementation I use properties and functions from within the protocol.

On the device it works how I expect. Also on the debugger it gave me the property from the class when I run into breakpoint within the extension implementation.

Can someone help me out why I didn't get the property in the example from the class but the nil property from extension.

Example from playground

import UIKit

protocol Collectable {

    var item: String?  { get }
    func collect()
}

extension Collectable {
    var item: String?  { return nil }
    func collect() {
        if let some = item {
            print("collect \(some)")
        } else {
            print("nothing")
        }
    }
}

class Car: Collectable {
    var item = "letter"
}

let car = Car()
car.collect()

In the protocol your item is optional string, while in your class you declared another variable named also item. Your collect function is looking for the optional item, and in the extension you specified that it should return nil.

As @SavcaMarin stated in their answer, you have a type conflict between the item property declared in your extension ( String? ) and the one in your Car ( String ).

You can see this if you comment the extension. The compiler will tell you that Car does not conform to Collectable . If you ask it to create the required stubs it will create func collect and var item: String? . It then gives an error that item is re-defined.

As Rob and Matt pointed out in comments on the other answer, this seems to be a bug in the Swift compiler. It doesn't indicate the re-definition of item or the non-conformance of your item to the protocol if there is a default implementation that satisfies the protocol conformance (your extension).

The simple fix is to tell Swift that the item in Car is the same as item in Collectable by declaring the type explicitly ( String? ) rather than relying on type inference (Which gives String ):

class Car: Collectable {    
    var item:String? = "letter"
}

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