para otros limpiar liberar espacio como cache borrar basura archivos app apartado ios cocoa caching swift nsdatepicker

ios - otros - ¿Es el almacenamiento en caché una buena idea para toda la aplicación NSDateformatter?



como limpiar mi iphone de archivos basura (7)

Es well sabido que crear NSDateFormatters es '' expensive ''

Incluso la Guía de formato de datos de Apple (actualizada 2014-02) establece:

Crear un formateador de fecha no es una operación barata. Si es probable que utilice un formateador con frecuencia, generalmente es más eficiente almacenar en caché una sola instancia que crear y eliminar varias instancias. Un enfoque es usar una variable estática.

Pero ese documento parece no estar realmente actualizado con rapidez y tampoco puedo encontrar nada al respecto en la última Referencia de clase de NSDateFormatter sobre el almacenamiento en caché del formateador, así que solo puedo suponer que es tan costoso tan rápido como lo es para objetivo-c .

Muchas fuentes sugieren caching el formateador dentro de la clase, por ejemplo, un controlador o una vista.

Me preguntaba si sería útil o incluso ''más barato'' agregar una clase singleton al proyecto para almacenar el datepicker para que esté seguro de que nunca será necesario volver a crearlo. Esto podría usarse en todas partes en la aplicación. También puede crear varias instancias compartidas que contengan múltiples datapickers. Por ejemplo, un datepicker para mostrar fechas y uno para una notación de tiempo:

class DateformatterManager { var formatter = NSDateFormatter() class var dateFormatManager : DateformatterManager { struct Static { static let instance : DateformatterManager = DateformatterManager() } // date shown as date in some tableviews Static.instance.formatter.dateFormat = "yyyy-MM-dd" return Static.instance } class var timeFormatManager : DateformatterManager { struct Static { static let instance : DateformatterManager = DateformatterManager() } // date shown as time in some tableviews Static.instance.formatter.dateFormat = "HH:mm" return Static.instance } // MARK: - Helpers func stringFromDate(date: NSDate) -> String { return self.formatter.stringFromDate(date) } func dateFromString(date: String) -> NSDate? { return self.formatter.dateFromString(date)! } } // Usage would be something like: DateformatterManager.dateFormatManager.dateFromString("2014-12-05")

Otro enfoque similar sería crear solo un singleton y cambiar el formato según la necesidad:

class DateformatterManager { var formatter = NSDateFormatter() var dateFormatter : NSDateFormatter{ get { // date shown as date in some tableviews formatter.dateFormat = "yyyy-MM-dd" return formatter } } var timeFormatter : NSDateFormatter{ get { // date shown as time in some tableviews formatter.dateFormat = "HH:mm" return formatter } } class var sharedManager : DateformatterManager { struct Static { static let instance : DateformatterManager = DateformatterManager() } return Static.instance } // MARK: - Helpers func dateStringFromDate(date: NSDate) -> String { return self.dateFormatter.stringFromDate(date) } func dateFromDateString(date: String) -> NSDate? { return self.dateFormatter.dateFromString(date)! } func timeStringFromDate(date: NSDate) -> String { return self.timeFormatter.stringFromDate(date) } func dateFromTimeString(date: String) -> NSDate? { return self.timeFormatter.dateFromString(date)! } } // Usage would be something like: var DateformatterManager.sharedManager.dateFromDateString("2014-12-05")

¿Alguna de esas sería una idea buena o horrible? ¿Y el cambio de formato también es costoso?

Actualización: como señalan Hot Licks y Lorenzo Rossi , cambiar los formatos probablemente no sea una buena idea (no es seguro ni tan costoso como volver a crear ...).


¿Alguna de esas sería una idea buena o horrible?

La introducción de singletons (cada vez que necesite una nueva variante de un formateador) no es una buena solución. Crear formateadores no es tan caro.

En su lugar, idee formas de reutilizar y compartir instancias de formateadores y transmítelos en su programa, como las variables regulares. Este enfoque es bastante simple de introducir en un programa existente.

Los instrumentos lo ayudarán a identificar dónde su programa crea muchos formateadores, y puede considerar cómo reutilizar los formateadores basados ​​en esa información.

¿Y el cambio de formato también es costoso?

No se moleste en formatear los formateadores que comparte, a menos que se use en contextos muy específicos / locales (como una colección particular de vistas). Esto va a ser mucho más fácil de lograr los resultados esperados. En su lugar, copie y mutee si necesita una variante de un formateador compartido.


En Objc:

Tener en cuenta que NSDateFormatter se considera inseguro de subprocesos con un solo formateador en su aplicación puede no ser la mejor idea. Tener un formateador por hilo puede ser un camino por recorrer. Alternativamente, podría considerar envolver el formateador en una clase segura para subprocesos.

De Apple Docs: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html

En Swift:

Si swift ofrece seguridad de subprocesos de la clase, no debería haber ningún problema con tener una instancia.


En lugar de usar un singleton, use la inyección de dependencia. Recuerde seguir la regla 0, 1, infinito.

http://en.wikipedia.org/wiki/Zero_one_infinity_rule

Aquí, claramente no podemos tener 0, y mientras que 1 suena bien, si vas a utilizarlo desde múltiples hilos, entonces no puedes tener solo uno sin que cuelgue. Entonces, infinito.

Una buena forma de abordar esto es solo tener cuidado con la cantidad de spawn, mantener solo uno por cada hilo que abra, y asegurarse de que se limpien tan pronto como haya terminado de usarlos.

Para ayudarte, echa un vistazo a este otro enlace de : me temo que mi respuesta estará en línea con la de ellos (mantén el número de NSDateformatters al mínimo). Sin embargo, es posible que tengan algún razonamiento que no esté cubierto en este hilo (¡no se trata de un juego de palabras!)

¿Cómo minimizar los costos de asignación e inicialización de NSDateFormatter?

Además, si puedo preguntar, si se encuentra con esta pregunta, ¿hay algún lugar en su programa donde se pueda mejorar el flujo para evitar incluso la necesidad de tantos formateadores?


En mi opinión, el almacenamiento en caché de NSDateFormatter es una buena idea si su aplicación la usa ampliamente o en toda su aplicación, esto aumentará el rendimiento de su aplicación. Si necesita eso en 1 o 2 lugares, no será una buena idea. Sin embargo, cambiar el formato de la fecha no es una buena idea, puede llevarte a situaciones no deseadas. (Debe seguir el formato actual cada vez antes de usarlo)

En una de mis aplicaciones usé un singleton con tres objetos de formato de fecha (los tres contienen tres formatos diferentes) como propiedades. NSDateFormatter personalizados para cada NSDateFormatter

+ (instancetype)defaultDateManager { static DateManager *dateManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dateManager = [[DateManager alloc] init]; }); return dateManager; } // Custom Getter for short date - (NSDateFormatter *)shortDate { if (!_shortDateFormatter) { _shortDateFormatter = [[NSDateFormatter alloc] init]; [_shortDateFormatter setDateFormat:@"yyyy-MM-dd"] } return _shortDateFormatter }

De esta manera, implementé getters personalizados para los otros dos también.

¿Por qué implementé getters personalizados? ¿Por qué no NSDateFormatter durante la inicialización de Singleton?

Es porque no quiero asignarlos en el principio. Necesito asignarlo cuando sea necesario por primera vez (según la demanda). En mi aplicación, los tres NSDateFormatters no son ampliamente utilizados, por eso elegí un patrón para implementarlo. (Mi aplicación está en Objective C, por eso utilicé el código Objective C aquí)


También me gustaría expandir la respuesta de Mobile Ben al proporcionar un ejemplo:

import Foundation public class DateFormatter : NSDateFormatter{ public class func sharedFormatter() -> NSDateFormatter { // current thread''s hash let threadHash = NSThread.currentThread().hash // check if a date formatter has already been created for this thread if let existingFormatter = NSThread.currentThread().threadDictionary[threadHash] as? NSDateFormatter{ // a date formatter has already been created, return that return existingFormatter }else{ // otherwise, create a new date formatter let dateFormatter = NSDateFormatter() // and store it in the threadDictionary (so that we can access it later on in the current thread) NSThread.currentThread().threadDictionary[threadHash] = dateFormatter return dateFormatter } } }

Esto se usa en una biblioteca, por eso puedes ver el modificador público en todo momento.


Tocaré aquí con una respuesta basada en la experiencia. La respuesta es sí, el almacenamiento en caché de NSDateFormatter para toda la aplicación es una buena idea, sin embargo, para mayor seguridad, hay un paso que debe dar para esto.

¿Por qué es bueno? Actuación. Resulta que crear NSDateFormatters es realmente lento. Trabajé en una aplicación que estaba muy localizada y usé muchos NSDateFormatters así como NSNumberFormatters. Hubo momentos en que los creamos dinámicamente con métodos y clases que tenían su propia copia de los formateadores que necesitaban. Además, tuvimos la carga adicional de que había casos en los que también podíamos visualizar cadenas localizadas para diferentes configuraciones regionales en la misma pantalla. Nos dimos cuenta de que nuestra aplicación se estaba ejecutando lentamente en ciertos casos, y después de ejecutar Instruments, nos dimos cuenta de que era la creación del formateador. Por ejemplo, vimos el rendimiento alcanzado al desplazar las vistas de tabla con una gran cantidad de celdas. Así que terminamos en el caché creando un objeto singleton que vendió el formateador apropiado.

Una llamada se vería así:

NSDateFormatter *dateFormatter = [[FormatterVender sharedInstance] shortDate];

Tenga en cuenta que esto es Obj-C, pero el equivalente se puede hacer en Swift. Simplemente sucedió que el nuestro estaba en Obj-C.

A partir de iOS 7, NSDateFormatters y NSNumberFormatters son "seguros para subprocesos", sin embargo, como mencionó Hot Licks, es probable que no desee modificar el formato si otro subproceso lo está utilizando. Otro +1 para almacenarlos en caché.

Y otro beneficio en el que solo pensé fue la mantenibilidad del código. Especialmente si tienes un equipo grande como el que tenemos. Como todos los desarrolladores saben que hay un objeto centralizado que vende los formateadores, simplemente pueden ver si el formateador que necesitan ya existe. Si no lo hace, se agrega. Esto suele estar relacionado con funciones, y por lo tanto, significa que también se necesitará un formateador nuevo en otros lugares. Esto también ayuda a reducir los errores, porque si hay un error en el formateador, lo arreglas en un solo lugar. Pero generalmente lo detectamos durante las pruebas unitarias del nuevo formateador.

Hay un elemento más que puede agregar para mayor seguridad, si lo desea. Cuál es usted puede utilizar el threadDictionary de NSThread para almacenar el formateador. En otras palabras, cuando llamas al singleton que venderá el formateador, esa clase verifica threadDictionary de la secuencia actual para ver si ese formateador existe o no. Si existe, entonces simplemente lo devuelve. Si no, lo crea y luego lo devuelve. Esto agrega un nivel de seguridad así que si, por algún motivo, desea modificar su formateador, puede hacerlo y no tener que preocuparse de que el formateador esté siendo modificado por otro hilo.

Lo que usamos al final del día fue singleton, que vendió formateadores específicos (tanto NSDateFormatter como NSNumberFormatter), asegurando que cada thread tuviera su propia copia de ese formateador específico (note que la aplicación fue creada antes de iOS 7, lo que hizo que cosa esencial que hacer). Al hacerlo, mejoró el rendimiento de nuestra aplicación y nos liberó de algunos desagradables efectos secundarios que experimentamos debido a la seguridad de los hilos y formateadores. Como tenemos la parte threadDictionary en su lugar, nunca la probé para ver si teníamos algún problema en iOS7 + sin ella (es decir, realmente se han vuelto seguros para la ejecución de subprocesos). Entonces, ¿por qué agregué el "si quieres" más arriba?


Ejemplo Swift

Basado en la respuesta de @Mobile Ben: este es un ejemplo de un simple Singleton de Swift.

class YourDateFormatter { // MARK: - Properties static let sharedFormatter = YourDateFormatter() /// only date format private let dateFormatter: NSDateFormatter /// only time format private let timeFormatter: NSDateFormatter // MARK: - private init private init() { // init the formatters dateFormatter = NSDateFormatter() timeFormatter = NSDateFormatter() // config the format dateFormatter.dateStyle = .MediumStyle dateFormatter.timeStyle = .NoStyle dateFormatter.doesRelativeDateFormatting = true timeFormatter.dateStyle = .NoStyle timeFormatter.timeStyle = .MediumStyle } // MARK: - Public func dateFormat(date: NSDate) -> String { return dateFormatter.stringFromDate(date) } func timeFormat(date: NSDate) -> String { return timeFormatter.stringFromDate(date) } func dateTimeFormat(date: NSDate) -> String { let dateFormat = self.dateFormat(date) let timeFormat = self.timeFormat(date) return dateFormat + " - " + timeFormat } }