Подтвердить что ты не робот

Есть ли способ добавить расширение к AnyObject?

В Objective-C я создал очень удобную категорию (расширение в терминах Swift) NSObject, которая добавила возможность добавлять произвольные пары ключ/значение во все NSObject во время выполнения. Он использует связанные объекты для присоединения изменяемого словаря к объекту, а затем предоставляет методы get и set, которые получают/устанавливают пары ключ/значение в/из этого словаря. Это всего лишь несколько строк кода.

Это позволяет присоединить произвольные пары ключ/значение к любому объекту во время выполнения, включая объекты, созданные системой. Это ключ. Бывают случаи, когда системная структура возвращает вам объект, и вы должны иметь возможность привязать к ней значение.

Этот трюк также позволяет создавать категории с новыми переменными экземпляра. (Хорошо, на самом деле это не так, но это позволяет добавлять новые переменные состояния к объектам в категории.)

Это невозможно в Swift 1.2, потому что:

  • Swift не имеет базового класса для всех объектов, таких как NSObject в Objective-C. Он использует AnyObject, который является протоколом.
  • Swift 1.2 не разрешает расширения протоколов.

Мне пришлось отказаться от этого в Swift 1.2.

Но Swift 2 позволяет расширять протоколы. Я подумал: "Отлично, теперь я могу добавить расширение, которое позволяет добавлять пары" ключ/значение "в AnyObject!"

Нет радости.

Когда я пытаюсь создать расширение для AnyObject:

extension AnyObject: AssociatedObjectProtocol

Я получаю сообщение об ошибке

Протокол AnyObject не может быть расширен

Arghh! Так близко, но нет. Кажется, что язык явно запрещает расширение AnyObject. Почему это, и есть ли какой-нибудь способ вокруг него?

Я не часто использую свою категорию в NSObject, но когда я это делаю, это спасатель. Я хотел бы добавить его в свою сумку трюков в Свифт.

Я мог бы добавить его в NSObject так же, как в Objective-C, но это означает, что он работает только для объектов, которые наследуют от NSObject, что делает его недействительным для родных классов Swift.

4b9b3361

Ответ 1

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

protocol A: AnyObject {}

// in Swift you would rather use this
protocol A: class {}

// add default implementations
extension A {
    func aMethod() {
        // code
    }
}

// Example
class B: A {}

// use the method
B().aMethod()

Этот подход не делает все классы автоматически соответствующими этому протоколу (но только классы могут соответствовать ему). Поэтому вы должны заставить их соответствовать себе. Поскольку вы не используете это как можно больше, это будет разумным решением.

Ответ 2

В соответствии с ответом @Qbyte, объявив, что NSObject соответствует протоколу, означает, что почти каждый класс во всем юниуме Cocoa/UIKit/Foundation наследует эту функциональность:

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        print("This is me, doing something.")
    }
}

extension NSObject: MyProtocol { }

Вы только что присоединили 99% классов Apple к MyProtocol. Вы можете сделать свои собственные классы совместимыми с MyProtocol, наследуя от NSObject или просто соответствуя ему.