0

У меня есть фреймворк iOS, который я обновляю до Swift 3. Я бы хотел, чтобы сигнатуры методов API соответствовали соглашениям Swift 3 с использованием первого именованного параметра для методов, сохраняя при этом обратную совместимость. Достаточно просто добавить новые сигнатуры API-метода и отказаться от старых. Но каков наилучший способ справиться с такими протоколами, которые используются в делегатах?Устаревшие протоколы для Swift 3 upgrade

API для Swift 2.x:

@objc(FooManager) 
public class FooManager { 
    public var delegate: FooManagerDelegate? 
    public func saveFoo(foo: Foo) { 
    ...  
    delegate?.didSaveFoo(foo) 
    } 
... 
} 

@objc public protocol FooManagerDelegate { 
    @objc optional func didSaveFoo(foo: Foo) 
} 

Новый API для Swift 3.x:

@objc(FooManager) 
public class FooManager { 
    public var delegate: FooManagerDelegate? 

    @available(*, deprecated, message: "use didSave(foo: foo)") 
    public func saveFoo(foo: Foo) { 
    ...  
    delegate?.didSaveFoo(foo) 
    } 
    public func save(foo: Foo) { 
    ...  
    delegate?.didSave(foo: foo) 
    } 
... 
} 

@objc public protocol FooManagerDelegate { 
    @objc optional func didSaveFoo(foo: Foo) 
    @objc optional func didSave(foo: Foo) 
} 

выше решение будет работать, но не будет давать никаких устаревания предупреждения пользователей для продолжения использования старых методов делегатов. Я мог бы создать новый делегат и отказаться от старого класса делегата, но потом мне придется иметь нестандартный класс делегата и именование свойств. Я не хотел бы, чтобы мой FooManager выглядеть некрасиво так:

public class FooManager { 
    @available(*, deprecated, message: "use swift3delegate") 
    public var delegate: FooDelegate? 
    public var swift3delegate: Swift3FooDelegate? 

Есть ли какие-либо лучшие решения для миграции пользователей на новые сигнатуры методов протокола при сохранении обратной совместимости?

ответ

1

Точно то, о чем вы просите, невозможно в Swift (или Objective-C?), Насколько мне известно. Цитируя response to a related question:

Основной проблема метания предупреждения устаревания любого класса, который соответствует MyProtocol и реализованного myOldFunction() является то, что нет ничего плохого в классах реализации функций и свойств, которые не являются частью вашего протокола.

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

Я полностью вижу смысл этого, и мне тоже понравится эта функция, но, насколько мне известно, Swift 3, по крайней мере, не предлагает ее (и не имеет значения Objective-C).

Одним из решений для этого было бы обесценить весь протокол и создать новый протокол, который необходимо объявить в коде Swift 3. Таким образом, это работает:

@available(*, deprecated, message="use ModernX instead") 
protocol X {} 

class A: X {} 

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

protocol BaseX { 
    func foo() 
    func bar() 
} 

@available(*, deprecated, message: "Use ModernX instead") 
protocol X: BaseX { 
    func theDeprecatedFunction() 
} 

protocol ModernX: BaseX { 
    func theModernFunction() 
} 

// you'll get a deprecation warning here. 
class A: X { 
    func foo() {} 
    func bar() {} 

    func theDeprecatedFunction() { 
    } 
} 
+0

Спасибо, идея использования базового протокола является полезным. Таким образом, мне нужно только одно свойство 'delegate' в классе менеджера. Мне просто жаль, что мне не нужно было создавать новый протокол с забавным именем - мой протокол Swift 2 имеет имя, которое я хочу использовать. :( – davidgyoung

+0

Если ваш собственный код является единственной реализацией протокола, например, в том же целевом/проектном/рабочем пространстве (т. Е. В настройке, которую можно было бы легко найти и заменить), вы всегда можете переименовать его как «... Legacy " или что-то.Но да, я не могу сказать, что меня волнует этот обходной путь любым другим способом, чем то, что он аккуратно изолирует устаревшие вещи в единицу (протокол с просто устаревшими вещами в нем). – mz2