objective c - Diferencias entre
objective-c cocoa-touch (7)
últimamente trabajo mucho con matrices y me pregunto ... ¿qué diferencias hay entre esas dos líneas?
NSArray *array = [NSArray arrayWithArray:someArray];
y
NSArray *array = [someArray copy];
¿Cuál de ellos es más rápido? ¿Qué pasa si tenemos NSMutableArray
y mutableCopy
?
¿Cuál de ellos es más rápido?
No te preocupes por eso Optimización prematura.
La principal diferencia es que el primer enfoque da como resultado una "copia" autorrellezada que usted no posee y no tiene que liberar, mientras que usted posee el objeto creado en la segunda línea. Ambas matrices serán inmutables, por cierto.
Además de las otras respuestas, también tenga en cuenta que cuando someArray
es nulo, la primera línea hará que array
señale a una matriz vacía y la segunda hará que apunte a nil. Esta podría ser una diferencia importante, especialmente en matrices mutables.
La diferencia entre los dos es que este último se mantendrá. El primero será lanzado de forma automática.
Ambas versiones hacen una copia superficial de la matriz.
NSMutableArray *notMutableReally = [NSArray arrayWithArray:aMutableArray];
Debería darle una advertencia de compilación ya que intentará asignar un NSArray
a un NSMutableArray
.
Utilizar.
NSMutableArray *mutableArrayCopy = [NSMutableArray arrayWithArray:aMutableArray];
¿Cual es mas rápido? No te preocupes, todos son mucho más rápidos que el resto de lo que harás. Consulte con los instrumentos si realmente le importa.
La principal diferencia es que la copia sabe mejor cómo copiarse (puede hacerlo de manera más eficiente y quizás use una subclase más adaptada de NSArray), mientras que +arrayWithArray:
creará una nueva instancia de NSArray
(bueno, de hecho, la clase concreta utilizada por Foundation for arrays) y alimentarlo con la misma lista de objetos del objeto inicial. También agregará una liberación automática adicional.
Así que -copy
es (muy) muy probable que sea más eficiente.
De hecho, para los NSArrays
inmutables, la NSArrays
solo lo está haciendo, por lo que ni siquiera se molesta en crear una nueva instancia.
Uno de ellos es probablemente más rápido. Ejecútelos un millón de veces y vea si alguien gana.
En el caso de NSArray
vs NSMutableArray
, una matriz inmutable que se copia no tiene que devolver una copia, ya que no puede cambiar. Sin embargo, si tiene una matriz mutable, necesitaría copiarse ya que podría cambiar la original. Y por supuesto, hacer una copia mutable siempre necesita devolver un nuevo objeto.
En toda su aplicación, la diferencia de velocidad y memoria probablemente no importará en comparación con todo lo demás que está sucediendo.
NSMutableArray *arr = [NSMutableArray array];
for ( int i = 0; i < 10000; i ++)
{
[arr addObject:@(i*1000000ULL)];
}
// MARK
// arr = (id)[NSArray arrayWithArray:arr];
NSTimeInterval t = [NSDate timeIntervalSinceReferenceDate];
NSArray *res = nil;
for ( int i = 0; i < 10000; i ++)
{
res = [arr copy];
}
NSLog(@"time A: %f", [NSDate timeIntervalSinceReferenceDate] - t);
t = [NSDate timeIntervalSinceReferenceDate];
for ( int i = 0; i < 10000; i ++)
{
res = [NSArray arrayWithArray:arr];
}
NSLog(@"time B: %f", [NSDate timeIntervalSinceReferenceDate] - t);
tiempo A: 1.572795, tiempo B: 1.539150, B [NSArray arrayWithArray:] siempre más rápido, pero la diferencia de tiempo es muy pequeña. Pero si descomentamos "MARK" y obtenemos copia de NSArray en su lugar NSMutableArray tendremos otro tiempo de ejecución A: 0.000473 tiempo B: 1.548400 resultado: ~ 3200x veces más rápido
En Swift, es muy diferente. Gracias a la nueva Fundación de código abierto para Swift, sabemos que mientras que init(array:)
crea una nueva matriz con los elementos dados (si los hay), copy()
simplemente devuelve self
.
public override func copy() -> AnyObject {
return copyWithZone(nil)
}
public func copyWithZone(zone: NSZone) -> AnyObject {
return self
}
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L82
public convenience init(array: [AnyObject]) {
self.init(array: array, copyItems: false)
}
public convenience init(array: [AnyObject], copyItems: Bool) {
let optionalArray : [AnyObject?] =
copyItems ?
array.map { return Optional<AnyObject>(($0 as! NSObject).copy()) } :
array.map { return Optional<AnyObject>($0) }
// This would have been nice, but "initializer delegation cannot be nested in another expression"
// optionalArray.withUnsafeBufferPointer { ptr in
// self.init(objects: ptr.baseAddress, count: array.count)
// }
let cnt = array.count
let buffer = UnsafeMutablePointer<AnyObject?>.alloc(cnt)
buffer.initializeFrom(optionalArray)
self.init(objects: buffer, count: cnt)
buffer.destroy(cnt)
buffer.dealloc(cnt)
}
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L116
Entonces, obviamente, copy()
es más rápido, ¡y ahora sabes cómo funcionan ambos! (Solo en Swift)