реализация по умолчанию расширения протокола swift против фактической реализации в классе - PullRequest
0 голосов
/ 17 июня 2019

Рассмотрим следующий код:

protocol MyProtocol {
    static var name: String { get }
}

extension MyProtocol {
    static var name: String {
        return "unnamed"
    }
}

// does not specify its own name
class MyClass: MyProtocol {

}

//specifies its own name!
class MyClass2: MyProtocol {
    static var name: String {
        return "Specific name"
    }
}

let myClass = MyClass()
print("\(MyClass.name)")
//>>"unnamed"

let myClass2 = MyClass2()
print("\(MyClass2.name)")
//>>"Specific name"

Гарантирует ли swift, что для классов (таких как в данном случае MyClass2), которые имеют фактическую реализацию свойства протокола, в данном случае «name», это используется из класса, а не из класса по умолчанию » имя "реализация через расширение протокола?

Ответы [ 2 ]

1 голос
/ 17 июня 2019

Наличие реализации по умолчанию для требуемой функции / свойства протокола означает, что ваши соответствующие типы не должны будут реализовывать эту функцию / свойство, вместо этого они могут использовать реализацию по умолчанию.

Однако, если соответствующий тип действительно реализует функцию / свойство, то компилятор всегда будет вызывать более конкретную реализацию, а именно ту, которая находится в вашем соответствующем классе, а не стандартную.

Такдаже если вы сохранили экземпляр MyClass2 в переменной типа MyProtocol, вы все равно получите реализацию MyClass2 при обращении к свойству переменной.

let myClass2: MyProtocol = MyClass2()
type(of: myClass2).name // "Specific name"

Поведение отличаетсядля необязательных свойств / функций, объявленных и определенных в расширении протокола.Если вы объявите свойство / функцию только в расширении протокола, то даже если вы предоставите другую реализацию для этого в соответствующем классе, вы не сможете получить доступ к этой реализации из переменной, тип которой является типом протокола, а неопределенный соответствующий тип.

protocol MyProtocol {
    static var name: String { get }
}

extension MyProtocol {
    static var name: String {
        return "unnamed"
    }

    // Optional protocol requirement
    static var nonRequired: String {
        return "nonRequired"
    }
}

// does not specify its own name
class MyClass: MyProtocol { }

//specifies its own name!
class MyClass2: MyProtocol {
    static var name: String {
        return "Specific name"
    }

    // Specific implementation
    static var nonRequired: String {
        return "Specific"
    }
}

let myClass = MyClass()
MyClass.name

let myClass2: MyProtocol = MyClass2()
type(of: myClass2).name // "Specific name"
type(of: myClass2).nonRequired // "nonRequired"
MyClass2.nonRequired // "Specific"
0 голосов
/ 17 июня 2019

К сожалению, ваш пример пропускает действительно интересный вариант использования.Сделайте ваши свойства экземпляра свойств, а не статические свойства, и удалите требование name из протокола:

protocol MyProtocol {
}

extension MyProtocol {
    var name: String {
        return "unnamed"
    }
}

class MyClass: MyProtocol {

}

class MyClass2: MyProtocol {
    var name: String {
        return "Specific name"
    }
}

Сейчас:

let myClass = MyClass()
print("\(myClass.name)")
//>>"unnamed"

let myClass2 = MyClass2()
print("\(myClass2.name)")
//>>"Specific name"

Хорошо, но посмотрите это:

let myClass2b : MyProtocol = MyClass2()
print("\(myClass2b.name)")
//>>"unnamed"

Таким образом, ответ таков: в этой ситуации ничто не «гарантировано»;все зависит от того, как набран объект.Расширение протокола может победить динамическую диспетчеризацию.

...