Reputation: 10194
I would like to create a trimmedText
property for UITextView
and UITextField
. Here is what I did:
protocol TrimmedTextSupporting: class {
var _text: String? { get }
var trimmedText: String { get }
}
extension TrimmedTextSupporting {
var trimmedText: String {
let text = self._text ?? ""
return text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
}
}
extension UITextField: TrimmedTextSupporting {
var _text: String? {
return self.text
}
}
extension UITextView: TrimmedTextSupporting {
var _text: String? {
return self.text
}
}
I need _text
property because text
is declared as String?
in UITextField
and as String!
in UITextView
(whyyyy?! >_<). Now I would like to hide this property to avoid cluttering the API.
Here's what I tried:
1) Marking it as private
. The compiler doesn't allow this: 'private' modifier cannot be used in protocols
2) Separating it into a private protocol:
private protocol TextExposing {
var _text: String? { get }
}
extension UITextField: TextExposing {
var _text: String? {
return self.text
}
}
extension UITextView: TextExposing {
var _text: String? {
return self.text
}
}
///////
protocol TrimmedTextSupporting: class {
var trimmedText: String { get }
}
extension UITextField: TrimmedTextSupporting {}
extension UITextView: TrimmedTextSupporting {}
extension TrimmedTextSupporting where Self: TextExposing {
// compiler error
var trimmedText: String {
let text = self._text ?? ""
return text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
}
}
But compiler complains again:
Property 'trimmedText' must be declared internal because it matches a requirement in internal protocol 'TrimmedTextSupporting'
I am out of ideas.
Upvotes: 6
Views: 3221
Reputation: 150
Or you can let trimmedText is not required, set to optional.
(if you wanna use optional in Swift, you should let protocol to be @objc)
@objc protocol TrimmedTextSupporting: class {
optional var trimmedText: String { get }
}
Upvotes: -1
Reputation: 10195
I'd be inclined to go with:
protocol TrimmedTextSupporting: class {
var trimmedText: String { get }
}
extension TrimmedTextSupporting {
private func trimText(text: String) -> String {
return text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
}
}
extension UITextField: TrimmedTextSupporting {
var trimmedText: String {
return trimText(text ?? "")
}
}
extension UITextView: TrimmedTextSupporting {
var trimmedText: String {
return trimText(text ?? "")
}
}
So you've avoided duplicating the hard work by doing it in a shared and private function, and the extensions on UITextField
and UITextView
do the minimum they need to do.
Upvotes: 4
Reputation: 42449
You declare TrimmedTextSupporting
as an internal Protocol. If you don't want to declare trimmedText
as internal
, declare TrimmedTextSupporting
as a private protocol:
private protocol TrimmedTextSupporting: class {
var trimmedText: String { get }
}
This compiles fine.
let textView = UITextView()
textView.text = "hello "
print(textView.trimmedText) // "hello"
let textField = UITextField()
textField.text = " world "
print(textField.trimmedText) // "world"
Upvotes: 0