Hola, me llamo Miguel y para hoy les traigo otro tutorial.
Índice
Conozca los 4 operadores de rango diferentes disponibles
Los rangos en Swift nos permiten seleccionar partes de cadenas, colecciones y otros tipos. Son la variante Swift de NSRange que conocemos por Objective-C
, aunque no son exactamente iguales en uso, como explicaré en esta publicación de blog.
Los rangos nos permiten escribir un código Swift elegante haciendo uso del operador de rango. La primera vez que trabaja con ellos puede deberse a que necesita seleccionar un rango de caracteres de una Cadena, ¡pero hay mucho más que puede hacer con él!
Tipos de rangos
Hay varios tipos de rangos en Swift que puede usar. La forma más sencilla de trabajar con ellos es haciendo uso del operador de rango. Repasemos los diferentes tipos disponibles en Swift.
let range: ClosedRange = 0...10 print(range.first!) // 0 print(range.last!) // 10
Un operador de rango cerrado que va desde a...b
define un rango que incluye a
y b
en el que a
no debe ser mayor que b
.
El operador cerrado es útil si desea utilizar todos los valores. Por ejemplo, si desea iterar sobre todos los elementos de una colección:
let names = ["Antoine", "Maaike", "Jaap"] for index in 0...2 print("Name (index) is (names[index])") // Name 0 is Antoine // Name 1 is Maaike // Name 2 is Jaap
Los diferentes tipos de operadores también se pueden utilizar para seleccionar elementos de una colección. Para esto, sin embargo, necesitamos hacer uso de la CountableClosedRange
tipo:
let names = ["Antoine", "Maaike", "Jaap"] let range: CountableClosedRange = 0...2 print(names[range]) // ["Antoine", "Maaike", "Jaap"]
Obviamente, Swift es lo suficientemente inteligente como para detectar la variante contable por sí mismo. Por lo tanto, puede escribir el código anterior de la siguiente manera:
let names = ["Antoine", "Maaike", "Jaap"] print(names[0...2]) // ["Antoine", "Maaike", "Jaap"]
let range: Range = 0..<10 print(range.first!) // 0 print(range.last!) // 9
Un rango semiabierto define un rango que va desde a
a b
pero no incluye b
. Se llama medio abierto porque contiene su primer valor pero no su valor final. Al igual que con el rango cerrado, el valor de a
no debe ser mayor que b
.
El operador semiabierto se puede utilizar para iterar sobre listas de base cero, como matrices y colecciones en Swift, en las que desea iterar hasta la longitud de la lista, pero sin incluirla.
Es básicamente lo mismo que el ejemplo de código anterior, pero ahora podemos hacer uso de la count
propiedad:
let names = ["Antoine", "Maaike", "Jaap"] print(names[0..<names.count]) // ["Antoine", "Maaike", "Jaap"]
Si hubiéramos hecho lo mismo con un operador cerrado, nos encontraríamos con el siguiente error:
Error fatal: el índice de matriz está fuera de rango
Un operador de rango unilateral solo define un lado de los límites, por ejemplo, a...
o ...b
. Un rango unilateral va lo más lejos posible en una dirección, por ejemplo, tomando todos los elementos de una matriz desde el inicio de la matriz hasta el índice 2
:
let names = ["Antoine", "Maaike", "Jaap"] print(names[...2]) // ["Antoine", "Maaike", "Jaap"]
O tomando todos los elementos desde el índice 1
hasta el final de la matriz:
let names = ["Antoine", "Maaike", "Jaap"] print(names[1...]) // ["Maaike", "Jaap"]
Se puede usar un rango unilateral para la iteración, pero solo si se usa con un valor inicial a...
. De lo contrario, no está claro dónde debería comenzar la iteración.
Iterar sobre un rango unilateral requiere que verifique manualmente dónde debe terminar el bucle, ya que de lo contrario continuaría indefinidamente.
let neededNames = 2 var collectedNames: [String] = [] for index in 0... guard collectedNames.count != neededNames else break collectedNames.append(names[index]) print(collectedNames) // ["Antoine", "Maaike"]
Conversión de un rango en un NSRange
en Swift
Tarde o temprano, es posible que se encuentre con un problema cuando desee convertir un Range
en un tipo NSRange
.
Por ejemplo, si está trabajando con un NSAttributedString
en el que le gustaría aplicar atributos a un rango específico. En el siguiente ejemplo, nos gustaría aplicar un color naranja a «Swift» en el título:
let title = "A Swift Blog"
let range = title.range (de: "Swift")
let attributeString = NSMutableAttributedString (string: title)
attributeString.setAttributes ([NSAttributedString.Key.foregroundColor: UIColor.orange], range: range) // No se puede convertir el valor del tipo 'Rango <String.Index>?' al tipo de argumento esperado 'NSRange' (también conocido como '_NSRange')
Como Range
no se puede convertir a NSRange
nos encontramos con el siguiente error:
¿No se puede convertir el valor del tipo
"Range"
? al tipo de argumento esperado'NSRange'
(también conocido como'NSRange'
)
Podemos solucionar esto haciendo uso del inicializador de conveniencia disponible de un NSRange
Swift Range
:
let ConvertRange = NSRange (rango, en: título)
El código final tendrá el siguiente aspecto:
let title = "Un Blog Swift"
let range = title.range (de: "Swift")!
let ConvertRange = NSRange (rango, en: título)
let attributeString = NSMutableAttributedString (string: title)
attributeString.setAttributes ([NSAttributedString.Key.foregroundColor: UIColor.orange], rango: convertRange)
print (atributoString)
// A {
// } Swift {
// NSColor = "UIExtendedSRGBColorSpace 1 0.5 0 1";
//} Blog {
//}
Rangos y cadenas
Las cadenas y los rangos son un poco más especiales. Como sabrá, a String
es en realidad una colección de personajes. Sin embargo, no todos los caracteres tienen el mismo tamaño. Podemos demostrar esto trabajando con a NSRange
y a NSString
que contengan un emoji:
let emojiText: NSString = "🚀launcher"
print (emojiText.substring (with: NSRange (location: 0, length: 2)))
// Se esperaba: 🚀l
// En realidad devuelve: 🚀
Como puede ver, el emoji de cohete tiene más de 1 carácter. Por lo tanto, nuestra subcadena no devuelve el resultado esperado.
Trabajar con índices de cadena
La solución a este problema es utilizar en Range<String.Index>
lugar de Range<Int>
. La String.Index
toma en cuenta el tamaño real de un personaje.
Solo podemos hacer uso de un medio abierto Range
como lo requiere el String
subíndice.
let emojiText = "🚀launcher"
let endIndex = emojiText.index (emojiText.startIndex, offsetBy: 2)
let range: Range <String.Index> = emojiText.startIndex .. <endIndex
print (emojiText [range]) // 🚀l
Espero que te haya sido de utilidad. Gracias por leer este tutorial.
Añadir comentario