array - substring to string swift 3
La forma más rápida y sencilla de agregar caracteres para formar una cadena en Swift (1)
(Esta respuesta fue escrita en base a la documentación y el código fuente válido para Swift 2 y 3: posiblemente necesite actualizaciones y enmiendas una vez que llegue Swift 4)
Ya que Swift ahora es de código abierto, podemos ver el código fuente de la String
nativa de Swift:
De la fuente anterior, hemos siguiente comentario
/// Growth and Capacity /// =================== /// /// When a string''s contiguous storage fills up, new storage must be /// allocated and characters must be moved to the new storage. /// `String` uses an exponential growth strategy that makes `append` a /// constant time operation *when amortized over many invocations*.
Teniendo en cuenta lo anterior, no debería preocuparse por el rendimiento de los caracteres agregados en Swift (ya sea a través de append(_: Character)
, append(_: UniodeScalar)
o appendContentsOf(_: String)
), como reasignación de los contiguos El almacenamiento para una determinada instancia de String
no debe ser muy frecuente. Es necesario adjuntar el número de caracteres individuales para que se produzca esta reasignación.
También tenga en cuenta que NSMutableString
no es Swift
"puramente nativo", sino que pertenece a la familia de clases Obj-C puenteadas (a las que se puede acceder a través de Foundation
).
Una nota a tu comentario.
"Pensé que
String
era inmutable, pero noté que su método anexado devuelveVoid
".
String
es solo un tipo (valor), que puede ser usado por propiedades mutables e inmutables
var foo = "foo" // mutable
let bar = "bar" // immutable
/* (both the above inferred to be of type ''String'') */
Los métodos de instancia mutante void-return append(_: Character)
y append(_: UniodeScalar)
son accesibles a instancias de String
mutables e inmutables, pero su uso con este último producirá un error de tiempo de compilación
let chars : [Character] = ["b","a","r"]
foo.append(chars[0]) // "foob"
bar.append(chars[0]) // error: cannot use mutating member on immutable value ...
Vengo de un fondo de C # donde System.String
es inmutable y la concatenación de cadenas es relativamente costosa (ya que requiere la reasignación de la cadena). Sabemos que usamos el tipo StringBuilder
lugar, ya que preasigna un búfer más grande donde caracteres individuales tipo de valor) y cadenas cortas se pueden concatenar a bajo costo sin asignación adicional.
Estoy transfiriendo algo de código C # a Swift, que se lee desde una matriz de bits ( [Bool]
) en índices de suboctetos con longitudes de caracteres menores a 8 bits (es un formato de archivo muy consciente del espacio).
Mi código C # hace algo como esto:
StringBuilder sb = new StringBuilder( expectedCharacterCount );
int idxInBits = 0;
Boolean[] bits = ...;
for(int i = 0; i < someLength; i++) {
Char c = ReadNextCharacter( ref idxInBits, 6 ); // each character is 6 bits in this example
sb.Append( c );
}
En Swift, asumo que NSMutableString
es el equivalente de StringBuilder
de .NET, y encontré este control de calidad sobre la adición de caracteres individuales ( ¿Cómo agregar un carácter a la cadena en Swift? ) Así que en Swift tengo esto:
var buffer: NSMutableString
for i in 0..<charCount {
let charValue: Character = readNextCharacter( ... )
buffer.AppendWithFormat("%c", charValue)
}
return String(buffer)
Pero no sé por qué pasa primero por una cadena de formato, eso parece ineficiente (volver a compartir la cadena de formato en cada iteración) y como mi código se ejecuta en dispositivos iOS, quiero ser muy conservador con la CPU y la memoria de mi programa uso.
Mientras escribía esto, aprendí que mi código realmente debería usar UnicodeScalar
lugar de Character
, el problema es que NSMutableString
no te permite agregar un valor de UnicodeScalar
, tienes que usar el propio tipo de String
mutable de Swift, así que ahora mi código parece:
var buffer: String
for i in 0..<charCount {
let x: UnicodeScalar = readNextCharacter( ... )
buffer.append(x)
}
return buffer
Pensé que String
era inmutable, pero noté que su método append
devuelve Void
.
Todavía me siento incómodo al hacer esto porque no sé cómo se implementa internamente el tipo String
''s String
, y no veo cómo puedo preasignar un búfer grande para evitar reasignaciones (asumiendo que la String
Swift utiliza un algoritmo creciente).