significado - swift transportation
Usando stringByReplacingCharactersInRange en Swift (13)
Estoy tratando de usar UITextFieldDelegate en Swift / Xcode6 y estoy luchando con la forma en que se supone que debo usar stringByReplacingCharactersInRange. El error del compilador es "No se puede convertir el tipo de expresión ''Cadena'' al tipo ''$ T8''.
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool
{
let s = textField.text.stringByReplacingCharactersInRange(range:range, withString:string)
if countElements(s) > 0 {
} else {
}
return true
}
Actualización para Xcode 6 Beta 5: la cosa es shouldChangeCharactersInRange proporciona un objeto NSRange y necesitaríamos un objeto Swift Range para stringByReplacingCharactersInRange. ¿Se puede seguir considerando esto un error ya que no veo por qué deberíamos estar tratando con objetos NS *? El argumento String del método delegado es, de todos modos, de tipo Swift.
A partir de Swift 4, esto es un poco más simple, como la respuesta de Alexander Volkov, pero sin la extensión.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let revisedText: String
if let text = textField.text, let swiftRange = Range(range, in: text) {
revisedText = text.replacingCharacters(in: swiftRange, with: string)
} else {
revisedText = string
}
// Do something with the text and return boolean.
}
Aquí se explica cómo calcular la cadena resultante en varias versiones Swift.
Tenga en cuenta que todos los métodos utilizan -[NSString stringByReplacingOccurrencesOfString:withString:]
exactamente de la misma manera, solo que difieren en la sintaxis.
Esta es la forma preferida de calcular la cadena resultante. La conversión a un Range
Swift y su uso en una String
Swift es propensa a errores. La respuesta de Johan, por ejemplo, es incorrecta en un par de formas cuando se opera en cadenas que no son ASCII.
Swift 3:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let result = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) ?? string
// ... do something with `result`
}
Swift 2.1:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let result = (textField.text as NSString?)?.stringByReplacingCharactersInRange(range, withString: string)
// ... do something with `result`
}
Swift 1 (solo queda aquí como referencia):
let result = textField.text.bridgeToObjectiveC().stringByReplacingCharactersInRange(range, withString:string)
Con Swift 2.0, la respuesta de Durul debe cambiarse porque los caracteres.cuenta deben usarse en lugar de count ().
Se debe hacer lo siguiente.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let length = textField.text!.characters.count - range.length + string.characters.count
if length > 0 {
submitButton.enabled = true
} else {
submitButton.enabled = false
}
return true
}
Crear String.Index es engorroso.
let string = "hello"
let range = string.startIndex .. string.startIndex.succ().succ()
let result = string.stringByReplacingCharactersInRange(range, withString: "si")
Esta es una publicación cruzada de esta pregunta , pero sin una manera de hacer un Range<String.Index>
el Swift-native String.stringByReplacingCharactersInRange()
es bastante inútil. Entonces, aquí hay una función para generar un Range<String.Index>
:
func RangeMake(#start:Int, #end:Int) -> Range<String.Index> {
assert(start <= end, "start must be less than or equal to end")
func rep(str: String, count: Int) -> String {
var result = ""
for i in 0..count {
result += str
}
return result
}
let length = end - start
let padding = rep(" ", start)
let dashes = rep("-", length)
let search = padding + dashes
return search.rangeOfString(dashes, options: nil, range: Range(start: search.startIndex, end: search.endIndex), locale: NSLocale.systemLocale())
}
let sourceString = "Call me Ishmael."
let range = RangeMake(start: 8, end: 15)
let name = sourceString.substringWithRange(range)
// name = "Ishmael"
La solución más sencilla que he encontrado está utilizando as NSString
, que nos permite usar NSRange
.
var textField : UITextField = UITextField()
textField.text = "this is a test"
let nsRange : NSRange = NSRange(location: 0, length: 4)
let replaced = (textField.text as NSString)
.stringByReplacingCharactersInRange(nsRange, withString: "that");
NSLog("Replaced: %@", replaced); //prints "that is a test"
Nada me funcionó, excepto lo siguiente: (Para tu información, estoy usando Xcode7.0 GM , Swift 2.0 , iOS9GM )
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let currentText = textField.text ?? ""
let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)
print("prospectiveText", prospectiveText)
return true;
}
para iOS 8.3 usar el siguiente código
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
if textField.isEqual(<textField whose value to be copied>)
{
<TextField to be updated>.text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
}
return true
}
NSRange
una extensión para NSRange
el convertido al Range<String.Index>
extension NSRange {
func toRange(string: String) -> Range<String.Index> {
let startIndex = advance(string.startIndex, location)
let endIndex = advance(startIndex, length)
return startIndex..<endIndex
}
}
Así que puedo crear la cadena como esta
let text = textField.text
let newText = text.stringByReplacingCharactersInRange(range.toRange(text), withString: string)
en Swift 2.1 la extensión se ve como:
extension NSRange {
func toRange(string: String) -> Range<String.Index> {
let startIndex = string.startIndex.advancedBy(location)
let endIndex = startIndex.advancedBy(length)
return startIndex..<endIndex
}
}
Swift 4:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
var text = textField.text ?? ""
text.replaceSubrange(range.toRange(string: text), with: string)
...
return true
}
extension NSRange {
/// Convert to Range for given string
///
/// - Parameter string: the string
/// - Returns: range
func toRange(string: String) -> Range<String.Index> {
let range = string.index(string.startIndex, offsetBy: self.lowerBound)..<string.index(string.startIndex, offsetBy: self.upperBound)
return range
}
}
Trabajando y probado
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
print(newString)
return true;
}
import UIKit
class LoginViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var submitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let length = count(textField.text) - range.length + count(string)
if length > 0 {
submitButton.enabled = true
} else {
submitButton.enabled = false
}
return true
}
}
let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
bridgeToObjectiveC puede eliminarse en próximas actualizaciones