Тайфун - Как ввести параметр, который соответствует PROTOCOL вместо CLASS

У меня есть класс, который представляет вошедшего в систему пользователя

public class User: NSObject {        
    init(authenticator: Authenticator) {        
        self.authenticator = authenticator
    }
    ... 
}

Его единственные начальные аргументы - это объект, соответствующий протоколу Authenticator.

protocol Authenticator
{
    func authenticate(login:String , password:String , handler: (result:AuthenticationResult)->()  )
}

В моем случае объект Auth является экземпляром класса BackendService

Мое определение сборки тайфуна:

public dynamic func user() -> AnyObject {
    return TyphoonDefinition.withClass(User.self) {
        (definition) in

        definition.useInitializer("initWithAuthenticator") {
            (initializer) in

            initializer.injectParameterWith( self.backendService() )
        }            
    }
}

Приложение вызывает runtime-error

'Method 'initWithAuthenticator' has 0 parameters, but 1 was injected. Do you mean 'initWithAuthenticator:'?'

Если я изменяю метод init на initWithAuthenticator: он падает с

'Method 'initWithAuthenticator:' not found on 'PersonalMessages.User'. Did you include the required ':' characters to signify arguments?'

1 ответ

В настоящее время необходимо добавить директиву @objc к протоколам Swift, чтобы они были доступны для внедрения зависимостей с помощью Typhoon. Без него функции самоанализа и динамической диспетчеризации во время выполнения target-c недоступны, и они необходимы.

Аналогично, в случае с классом он должен расширяться из NSObject или иметь директиву @objc, в противном случае он также будет использовать vtable dispatch в стиле C++ и (по существу) не иметь отражения. В случае приватных переменных или методов они также должны иметь модификатор "dynamic".

Хотя диспетчеризация vtable быстрее, она предотвращает перехват метода во время выполнения, на который полагаются многие из наиболее мощных функций Cocoa, таких как KVO. Таким образом, обе парадигмы важны и впечатляет, что Swift может переключаться между ними. Однако в случае протоколов использование директивы @objc несколько неудачно, поскольку подразумевает "устаревшее" поведение. Возможно, "динамический" был бы лучше?

dynamic protocol Authenticator //Not supported but would've been a nicer than '@objc'?

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

Между тем, для классов требование о расширении NSObject не очень заметно в том, что касается работы с приложениями Cocoa/Touch.

Другие вопросы по тегам