Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift extension clause where this or that

I want an extension for two classes UITextField and UITextView and the code is identical, but I have trouble coming up with an extension that will work for them both.

I am using ReactiveCocoa and I currently 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 would I write an extension that would work for both? I was trying 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 either UITextField or UITextView. Something like where Self == UITextField || Self == UITextView would probably make this possible.

Is there a nice way to accomplish what I want to try? Is this 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

like image 318
Filuren Avatar asked Feb 15 '16 22:02

Filuren


People also ask

Can we extend structure in Swift?

In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of. For more details, see Protocol Extensions. Extensions can add new functionality to a type, but they can't override existing functionality.

How do you name a file extension in Swift?

Naming a fileAll Swift files should use the . swift extension. The name of a file should make it clear what the contents are.

Can you add a stored property to a type by using an extension how or why not?

Yeah. Extensions cannot contain stored properties. If you need to add a property to a native component, you must create your own button inheriting from UIButton. In my opinion, creating your own button using a UIButton inheritance is the best way to resolve this situation.

What is difference between extension and inheritance Swift?

Under the protocols section in the language guide, it is explained that: Protocol extensions can add implementations to conforming types but can't make a protocol extend or inherit from another protocol. Protocol inheritance is always specified in the protocol declaration itself.


1 Answers

You can cut down your proposed solution to a single 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 don't think there's a more concise way than that, though. UITextField and UITextView's rac_textSignal() implementations have nothing in common.

like image 67
Ian Henry Avatar answered Sep 20 '22 16:09

Ian Henry