Swift extension clause where one or the other

I want an extension for the two classes UITextField and UITextView , and the code is identical, but I am having problems with an extension that will work for both of them.

I am using ReactiveCocoa and I have this

 import UIKit import ReactiveCocoa import enum Result.NoError typealias NoError = Result.NoError // How to DRY up this code? extension UITextField { func textSignalProducer() -> SignalProducer<String, NoError> { return self.rac_textSignal() .toSignalProducer() .map { $0 as! String } .flatMapError { error in SignalProducer<String, NoError>(value: "") } } } extension UITextView { func textSignalProducer() -> SignalProducer<String, NoError> { return self.rac_textSignal() .toSignalProducer() .map { $0 as! String } .flatMapError { error in SignalProducer<String, NoError>(value: "") } } } 

How do I write an extension that will work for both? I tried to do something like

 protocol TextSignalProducer {} extension TextSignalProducer where Self: ???? { // Same code as is duplicated in both current extensions... } 

but I have no idea how to specify Self as a UITextField or UITextView . Maybe something like where Self == UITextField || Self == UITextView where Self == UITextField || Self == UITextView will make this possible.

Is there a good way to accomplish what I want to try? This is really necessary (I don't know the naming conventions for protocols / extensions)

 import UIKit import ReactiveCocoa import enum Result.NoError typealias NoError = Result.NoError protocol TextSignal { func rac_textSignal() -> RACSignal! } extension UITextField: TextSignal, TextSignalProducer {} extension UITextView: TextSignal, TextSignalProducer {} protocol TextSignalProducer {} extension TextSignalProducer where Self: TextSignal { func textSignalProducer() -> SignalProducer<String, NoError> { return self.rac_textSignal() .toSignalProducer() .map { $0 as! String } .flatMapError { error in SignalProducer<String, NoError>(value: "") } } } 

I am using Swift 2.1, Xcode 7.2 and ReactiveCocoa 4.0.1

+5
source share
2 answers

You can reduce the proposed solution to one dummy protocol:

 protocol TextSignalProducer { func rac_textSignal() -> RACSignal! } extension TextSignalProducer { func textSignalProducer() -> SignalProducer<String, NoError> { return self.rac_textSignal() .toSignalProducer() .map { $0 as! String } .flatMapError { error in SignalProducer<String, NoError>(value: "") } } } extension UITextField: TextSignalProducer {} extension UITextView: TextSignalProducer {} 

I do not think there is a shorter way than this. UITextField and UITextView rac_textSignal() have nothing in common.

+1
source

UITextView and UITextField conform to the UITextInput protocol. If rac_textSignal based on this protocol (I'm not sure because I don't have any project with RactiveCocoa :)) you can do this:

 protocol Cos { func textSignalProducer() -> String } extension UITextView: Cos { } extension UITextField: Cos { } extension Cos where Self: UITextInput { func textSignalProducer() -> String { return "dsfsdf" } } let cos = UITextView() cos.textSignalProducer() let cos2 = UITextField() cos2.textSignalProducer() 
0
source

Source: https://habr.com/ru/post/1243091/


All Articles