2016-02-26 7 views
1

Я хотел бы динамически присоединить замыкание к другому методу из init класса. Например, для UIViewController я хотел бы добавить расширение, чтобы я мог ввести код в событие viewDidLoad. Я пытался что-то вроде ниже, но это не работает:Можно ли динамически подключать логику к методу?

class BaseViewController: UIViewController, MyProtocol { 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     // Setup and bind 
     configure() 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Call MyProtocol.myDidLoad but not explicitly! 
    } 

    override func viewWillAppear(animated: Bool) { 
     super.viewWillAppear(animated) 

     // Call viewWillAppear but not explicitly! 
    } 

} 

protocol MyProtocol { } 

extension MyProtocol where Self: UIViewController { 

    func configure() { 
     // Something like below isn't possible??? 
     self.viewDidLoad += myDidLoad 
     self.viewWillAppear += myWillAppear 
    } 

    func myDidLoad() { 
     // Something 
    } 

    func myWillAppear() { 
     // Something 
    } 
} 

ли достижение этой цели возможно, без явного вызова функции протокола из UIViewController? Я не хочу проходить все классы и вызывать функции протокола для каждой функции. Это было бы утомительным, избыточным кодом, и его можно легко упустить. Есть ли более элегантный способ?

UPDATE:

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

class FirstViewController: BaseViewController { 

} 

class BaseViewController: UIViewController, MyProtocol, MyProtocol2, MyProtocol3 { 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     // Configure protocols 
     configure(self as MyProtocol) 
     configure(self as MyProtocol2) 
     configure(self as MyProtocol3) 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Load protocols 
     viewDidLoad(self as MyProtocol) 
     viewDidLoad(self as MyProtocol2) 
     viewDidLoad(self as MyProtocol3) 
    } 

    override func viewWillAppear(animated: Bool) { 
     super.viewWillAppear(animated) 

     // Prerender protocols 
     viewWillAppear(self as MyProtocol) 
     viewWillAppear(self as MyProtocol2) 
     viewWillAppear(self as MyProtocol3) 
    } 

} 

protocol MyProtocol { } 

extension MyProtocol where Self: UIViewController { 

    func configure(delegate: MyProtocol) { 
     print("MyProtocol.configure") 
    } 

    func viewDidLoad(delegate: MyProtocol) { 
     print("MyProtocol.viewDidLoad") 
    } 

    func viewWillAppear(delegate: MyProtocol) { 
     print("MyProtocol.viewWillAppear") 
    } 
} 

protocol MyProtocol2 { } 

extension MyProtocol2 where Self: UIViewController { 

    func configure(delegate: MyProtocol2) { 
     print("MyProtocol2.configure") 
    } 

    func viewDidLoad(delegate: MyProtocol2) { 
     print("MyProtocol2.viewDidLoad") 
    } 

    func viewWillAppear(delegate: MyProtocol2) { 
     print("MyProtocol2.viewWillAppear") 
    } 
} 

protocol MyProtocol3 { } 

extension MyProtocol3 where Self: UIViewController { 

    func configure(delegate: MyProtocol3) { 
     print("MyProtocol3.configure") 
    } 

    func viewDidLoad(delegate: MyProtocol3) { 
     print("MyProtocol3.viewDidLoad") 
    } 

    func viewWillAppear(delegate: MyProtocol3) { 
     print("MyProtocol3.viewWillAppear") 
    } 
} 

//Output: 
//MyProtocol.configure 
//MyProtocol2.configure 
//MyProtocol3.configure 
//MyProtocol.viewDidLoad 
//MyProtocol2.viewDidLoad 
//MyProtocol3.viewDidLoad 
//MyProtocol.viewWillAppear 
//MyProtocol2.viewWillAppear 
//MyProtocol3.viewWillAppear 

Это побеждает всю цель протокола ориентированного программирования. Есть ли элегантный подход, который Swift может обрабатывать при работе в рамках разработки iOS, или POP не работает в этом случае?

ответ

4

То, что вы хотите сделать, невозможно, так как Swift и Objective-C - это языки с одним наследованием.

Расширение может только добавлять дополнительные методы, оно не может переопределять методы. Только подкласс может переопределять методы в существующем классе. Рассмотрим случай, когда несколько расширений перекрывают один и тот же метод - который нужно вызывать? Все они ?, если так, в каком порядке? См. The Diamond Problem

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

+0

Я сделал то, что вы предлагали, и обновил ответ с помощью нового кода, он очень утомительный и не очень элегантный. Я думаю, что POP не был создан для разработки iOS? – TruMan1

+1

Я думаю, что в то время как POP предоставляет некоторые функции множественного наследования, это не то же самое, что множественное наследование. Swift и Objective-C являются как единичными языками наследования. Протоколы обеспечивают много преимуществ множественного наследования, но избегают проблемы с алмазами - https://en.wikipedia.org/wiki/Multiple_inheritance. Даже эти языки с множественным наследованием требуют, чтобы вы решительно решали проблему с алмазом и поэтому не разрешали выполнение всех ваших реализаций 'viewDidLoad' – Paulw11

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