2016-01-18 2 views
7

я нашел интересное поведение, которое кажется как ошибка ...Swift расширение протокола способ доставки с суперкласса и подкласса

На основе поведения описаны в следующих статьях:

https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94

http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future

Выход не является тем, что я ожидаю, когда добавляю SomeSuperclass, а не напрямую принимаю протокол.

protocol TheProtocol { 
    func method1() 
} 

extension TheProtocol { 
    func method1() { 
     print("Called method1 from protocol extension") 
    } 
    func method2NotInProtocol() { 
     print("Called method2NotInProtocol from protocol extension") 
    } 
} 

// This is the difference - adding a superclass 
class SomeSuperclass: TheProtocol { 
} 

// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol 
class MyClass: SomeSuperclass { 
    func method1() { 
     print("Called method1 from MyClass implementation") 
    } 
    func method2NotInProtocol() { 
     print("Called method2NotInProtocol from MyClass implementation") 
    } 
} 

let foo: TheProtocol = MyClass() 
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension" 
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension 

Знаете ли вы, если это ошибка или по дизайну? Один из коллег предположил, что смешение наследования и расширений протоколов может работать не так, как ожидалось. Я собирался использовать расширение протокола, чтобы обеспечить реализацию по умолчанию ... если я не могу этого сделать, то, к сожалению, мне придется отметить его @objc и вернуться к необязательному протоколу.

+1

Возможный дубликат [Способ распространения расширения протокола в Swift 2.0] (http://stackoverflow.com/questions/32734403/protocol-extension-method-dispatch-in-swift-2-0) – mbelsky

ответ

1

От почты The Ghost of Swift Bugs Future, вот правила отправки для расширений протокола, которые упоминаются в конце сообщения.

  1. Если выведенный тип переменной является протоколом:
  2. И метод определен в первоначальном протоколе ТОГДА реализация типа среды выполнения называется, независимо от того, есть реализация по умолчанию в расширении ,
  3. И метод не определен в исходном протоколе, THEN вызывается реализация по умолчанию .
  4. ELSE ЕСЛИ выведенный тип переменной является типом THEN, который вызывается реализацией типа.

Итак, в вашем состоянии вы говорите, что метод method1() определен в протоколе и реализован в подклассе. Но ваш суперкласс использует протокол, но не реализует метод 1(), а подкласс просто наследуется от суперкласса и не принимает непосредственно протоколы. Вот почему я считаю, что это причина, когда вы звоните foo.method1(), он не ссылается на реализацию подклассов, как указано пунктом 1 & 2.

Но когда вы делаете,

class SomeSuperclass: TheProtocol { 
func method1(){ 
print("super class implementation of method1()")} 
} 

class MyClass : SomeSuperclass { 

override func method1() { 
    print("Called method1 from MyClass implementation") 
} 

override func method2NotInProtocol() { 
    print("Called method2NotInProtocol from MyClass implementation") 
} 
} 

а затем, когда вы звоните,

let foo: TheProtocol = MyClass() 
foo.method1() // Called method1 from MyClass implementation 
foo.method2NotInProtocol() 

Так что может быть обходной путь для этой ошибки (который, кажется, ошибка) является то, что вам нужно реализовать метод протокола в суперкласса, а затем вам нужно переопределить метод протокола в подклассе. HTH

0

Пожалуйста, проверьте код ниже:

import UIKit 

protocol TheProtocol { 
    func method1() 
    func method2NotInProtocol() 
} 

extension NSObject { 

    func method1() { 
     print("Called method1 from protocol extension") 
    } 
    func method2NotInProtocol() { 
     print("Called method2NotInProtocol from protocol extension") 
    } 
} 

// This is the difference - adding a superclass 
class SomeSuperclass :NSObject, TheProtocol { 

    override func method1() { 
     print("Called method1 from SomeSuperclass implementation") 
    } 

} 

// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol 
class MyClass : SomeSuperclass { 

    override func method1() { 
     print("Called method1 from MyClass implementation") 
    } 

    override func method2NotInProtocol() { 
     print("Called method2NotInProtocol from MyClass implementation") 
    } 
} 

    let foo: TheProtocol = MyClass() 
    foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension" 
    foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension 

Вместо того, чтобы расширение ввода на TheProtocol, написать продолжение к абстрактному классу (NSObject в коде выше). Это работает так, как ожидалось.

Смежные вопросы