iphone - videos - ¿Cuáles son las mejores prácticas que utiliza al escribir Objective-C y Cocoa?




recortar tamaño video iphone (20)

Sé sobre el HIG (¡que es bastante útil!), Pero qué prácticas de programación utiliza al escribir Objective-C, y más específicamente cuando usa Cocoa (o CocoaTouch).


Evitar autorelease

Debido a que normalmente (1) no tiene control directo sobre su vida útil, los objetos lanzados automáticamente pueden persistir por un tiempo comparativamente largo y aumentar innecesariamente la huella de memoria de su aplicación. Si bien en el escritorio esto puede tener poca importancia, en plataformas más restringidas puede ser un problema importante. Por lo tanto, en todas las plataformas, y especialmente en las plataformas más restringidas, se considera la mejor práctica para evitar el uso de métodos que conduzcan a la publicación automática de objetos y, en su lugar, se recomienda utilizar el patrón alloc / init.

Así, en lugar de:

aVariable = [AClass convenienceMethod];

donde sea posible, deberías usar:

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

Cuando está escribiendo sus propios métodos que devuelven un objeto recién creado, puede aprovechar la convención de nomenclatura de Cocoa para señalar al receptor que debe liberarse al añadir el nombre del método con "nuevo".

Así, en lugar de:

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}

usted podría escribir:

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

Dado que el nombre del método comienza con "nuevo", los consumidores de su API saben que son responsables de liberar el objeto recibido (consulte, por ejemplo, el método newObject de newObject ).

(1) Puede tomar el control utilizando sus propios grupos locales de autorelease. Para más sobre esto, vea Grupos de Autorelease .


IBOutlets

Históricamente, la gestión de memoria de las salidas ha sido deficiente. La mejor práctica actual es declarar puntos de venta como propiedades:

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

El uso de propiedades hace que la semántica de administración de memoria sea clara; también proporciona un patrón consistente si utiliza la síntesis de variables de instancia.


Ordenar las cadenas como el usuario quiera

Cuando ordena cadenas para presentar al usuario, no debe usar el método simple compare: En su lugar, siempre debe utilizar métodos de comparación localizedCompare: como localizedCompare: o localizedCaseInsensitiveCompare:

Para obtener más detalles, consulte Buscar, comparar y ordenar cadenas .


Piensa en valores nulos.

Como señala esta pregunta , los mensajes a nil son válidos en Objective-C. Si bien esto es con frecuencia una ventaja, lo que lleva a un código más limpio y más natural, la característica puede llevar ocasionalmente a errores peculiares y difíciles de rastrear si obtiene un valor nil cuando no lo esperaba.


Utilice el analizador estático LLVM / Clang

NOTA: Bajo Xcode 4 esto ahora está integrado en el IDE.

Usted usa el analizador estático Clang para, como era de esperar, analizar su código C y Objective-C (aún no C ++) en Mac OS X 10.5. Es trivial de instalar y usar:

  1. Descarga la última versión desde esta página .
  2. Desde la línea de comandos, cd a su directorio de proyecto.
  3. Ejecute scan-build -k -V xcodebuild .

(Existen algunas restricciones adicionales, etc., en particular, debe analizar un proyecto en su configuración de "Depuración"; consulte http://clang.llvm.org/StaticAnalysisUsage.html para obtener más información, pero eso es más o menos lo que se reduce a)

Luego, el analizador produce un conjunto de páginas web para usted que muestran la administración de memoria probable y otros problemas básicos que el compilador no puede detectar.


@kendell

En lugar de:

@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end

Utilizar:

@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end

Nuevo en Objective-C 2.0.

Las extensiones de clase se describen en la Referencia de Objective-C 2.0 de Apple.

"Las extensiones de clase le permiten declarar la API adicional requerida para una clase en ubicaciones que no sean dentro del bloque de interfaz principal de la clase primaria"

Así que son parte de la clase real, y NO de una categoría (privada) además de la clase. Diferencia sutil pero importante.


Asegúrese de marcar la página Magia de depuración . Esta debería ser tu primera parada cuando te golpees la cabeza contra una pared mientras intentas encontrar la fuente de un error de cacao.

Por ejemplo, le dirá cómo encontrar el método donde primero asignó la memoria que más tarde está causando bloqueos (como durante la finalización de la aplicación).


Escribir pruebas unitarias. Puedes probar muchas cosas en Cocoa que podrían ser más difíciles en otros marcos. Por ejemplo, con el código UI, generalmente puede verificar que las cosas estén conectadas como deberían estar y confiar en que funcionarán cuando se utilicen. Y puede configurar los métodos de estado e invocación de delegado fácilmente para probarlos.

Tampoco tiene visibilidad de métodos públicos frente a protegidos frente a métodos privados que le impiden escribir pruebas para sus aspectos internos.


Hay algunas cosas que comencé a hacer que no creo que sean estándar:

1) Con el advenimiento de las propiedades, ya no uso "_" para prefijar variables de clase "privadas". Después de todo, si otras clases pueden acceder a una variable, ¿no debería haber una propiedad para ella? Siempre me disgustó el prefijo "_" para hacer el código más feo, y ahora puedo omitirlo.

2) Hablando de cosas privadas, prefiero ubicar las definiciones de métodos privados dentro del archivo .m en una extensión de clase como tal:

#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

¿Por qué desordenar el archivo .h con cosas que los extraños no deberían preocuparse? El empty () funciona para categorías privadas en el archivo .m, y emite advertencias de compilación si no implementa los métodos declarados.

3) He comenzado a colocar dealloc en la parte superior del archivo .m, justo debajo de las directivas de @synthesize. ¿No debería estar en la parte superior de la lista de cosas que quiere pensar en una clase? Eso es especialmente cierto en un entorno como el iPhone.

3.5) En las celdas de la tabla, haga que todos los elementos (incluida la celda) sean opacos para el rendimiento. Eso significa establecer el color de fondo apropiado en todo.

3.6) Al usar un NSURLConnection, como regla, es posible que desee implementar el método delegado:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

Me parece que la mayoría de las llamadas web son muy singulares y es más una excepción que la regla que deseará que las respuestas se almacenen en caché, especialmente para las llamadas de servicios web. Implementar el método como se muestra deshabilita el almacenamiento en caché de respuestas.

También de interés, son algunos buenos consejos específicos para iPhone de Joseph Mattiello (recibidos en una lista de correo de iPhone). Hay más, pero pensé que estos fueron los más útiles en general (tenga en cuenta que algunos bits ahora se han editado ligeramente desde el original para incluir detalles ofrecidos en las respuestas):

4) Solo use precisión doble si tiene que hacerlo, como cuando trabaja con CoreLocation. Asegúrese de terminar sus constantes en 'f' para hacer que gcc las almacene como flotadores.

float val = someFloat * 2.2f;

Esto es sobre todo importante cuando algo de someFloat puede ser doble, no necesitas las matemáticas de modo mixto, ya que estás perdiendo precisión en "val" en el almacenamiento. Si bien los números de punto flotante son compatibles con el hardware en los iPhones, aún puede tomar más tiempo hacer aritmética de doble precisión en lugar de precisión simple. Referencias:

En los teléfonos más antiguos, los cálculos supuestamente funcionan a la misma velocidad, pero puede tener más componentes de precisión simple en los registros que en los dobles, por lo que para muchos cálculos, la precisión única terminará siendo más rápida.

5) Establecer sus propiedades como no nonatomic . Son atomic por defecto y en síntesis, se creará un código de semáforo para evitar problemas de subprocesos múltiples. Es probable que el 99% de usted no tenga que preocuparse por esto y el código está mucho menos hinchado y es más eficiente en memoria cuando se configura en no atómico.

6) SQLite puede ser una forma muy rápida de almacenar grandes conjuntos de datos. Una aplicación de mapas, por ejemplo, puede almacenar en caché sus mosaicos en archivos SQLite. La parte más cara es la E / S del disco. Evita muchas escrituras pequeñas enviando BEGIN; y COMMIT; Entre grandes bloques. Usamos un temporizador de 2 segundos, por ejemplo, que se reinicia en cada nuevo envío. Cuando expira, enviamos COMMIT; , lo que hace que todas tus escrituras vayan en una gran parte. SQLite almacena los datos de la transacción en el disco y, al hacer esto, el ajuste Begin / End evita la creación de muchos archivos de transacción, agrupando todas las transacciones en un solo archivo.

Además, SQL bloqueará su GUI si está en su hilo principal. Si tiene una consulta muy larga, es una buena idea almacenar sus consultas como objetos estáticos y ejecutar su SQL en un hilo separado. Asegúrese de envolver todo lo que modifique la base de datos para las cadenas de consulta en los @synchronize() {} . Para consultas cortas, simplemente deje las cosas en el hilo principal para una mayor comodidad.

Más consejos de optimización de SQLite están aquí, aunque el documento parece desactualizado, muchos de los puntos probablemente todavía sean buenos;

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html


No escriba Objective-C como si fuera Java / C # / C ++ / etc.

Una vez vi a un equipo acostumbrado a escribir aplicaciones web Java EE intentar escribir una aplicación de escritorio Cocoa. Como si fuera una aplicación web Java EE. Había muchos AbstractFooFactory y FooFactory e IFoo y Foo volando cuando lo único que necesitaban era una clase de Foo y posiblemente un protocolo de Fooable.

Parte de asegurarse de no hacer esto es entender realmente las diferencias en el idioma. Por ejemplo, no necesita las clases abstractas de fábrica y de fábrica anteriores porque los métodos de clase de Objective-C se distribuyen de forma tan dinámica como los métodos de instancia, y se pueden anular en subclases.


Resista subclasificar el mundo. En Cocoa, mucho se hace a través de la delegación y el uso del tiempo de ejecución subyacente que en otros marcos se realiza a través de subclases.

Por ejemplo, en Java usa mucho las subclases de *Listener anónimas y en .NET usa mucho las subclases EventArgs . En Cocoa, tampoco lo haces, en su lugar se usa la acción de destino.


Simple pero a menudo olvidado. Según la especificación:

En general, los métodos en diferentes clases que tienen el mismo selector (el mismo nombre) también deben compartir los mismos tipos de retorno y argumento. Esta restricción es impuesta por el compilador para permitir el enlace dinámico.

en cuyo caso, se considerará que todos los mismos selectores con nombre, incluso en clases diferentes , tienen tipos de devolución / argumento idénticos. Aquí hay un ejemplo simple.

@interface FooInt:NSObject{}
-(int) print;
@end

@implementation FooInt
-(int) print{
    return 5;
}
@end

@interface FooFloat:NSObject{}
-(float) print;
@end

@implementation FooFloat
-(float) print{
    return 3.3;
}
@end

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
    id f1=[[FooFloat alloc]init];
    //prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
    NSLog(@"%f",[f1 print]);

    FooFloat* f2=[[FooFloat alloc]init];
    //prints 3.3 expectedly as the static type is FooFloat
    NSLog(@"%f",[f2 print]);

    [f1 release];
    [f2 release]
    [pool drain];

    return 0;
}   

Use las convenciones y terminología estándar de nomenclatura y formato de Cocoa en lugar de lo que esté acostumbrado en otro entorno. Hay muchos desarrolladores de Cocoa por ahí, y cuando otro de ellos comience a trabajar con su código, será mucho más accesible si se ve y se siente similar a otro código de Cocoa.

Ejemplos de qué hacer y qué no hacer:

  • No declare id m_something; en la interfaz de un objeto y llámelo una variable o campo miembro ; use something o _something para su nombre y _something una variable de instancia .
  • No nombre un getter -getSomething ; El nombre apropiado de Cacao es solo -something .
  • No nombrar un setter -something: debe ser -setSomething:
  • El nombre del método está entremezclado con los argumentos e incluye dos puntos; es -[NSObject performSelector:withObject:] , no NSObject::performSelector .
  • Use inter-caps (CamelCase) en los nombres de métodos, parámetros, variables, nombres de clases, etc. en lugar de barras inferiores (guiones bajos).
  • Los nombres de clase comienzan con una letra mayúscula, una variable y un nombre de método en minúscula.

Hagas lo que hagas, no uses la notación húngara al estilo de Win16 / Win32. Incluso Microsoft renunció a eso con el cambio a la plataforma .NET.


Utilice NSAssert y amigos. Uso nil como objeto válido todo el tiempo ... especialmente el envío de mensajes a nil es perfectamente válido en Obj-C. Sin embargo, si realmente quiero asegurarme del estado de una variable, utilizo NSAssert y NSParameterAssert, que ayuda a localizar problemas fácilmente.


Active todas las advertencias de GCC, luego desactive las que son causadas regularmente por los encabezados de Apple para reducir el ruido.

También ejecute el análisis estático Clang con frecuencia; puede habilitarlo para todas las compilaciones a través de la configuración de compilación "Run Static Analyzer".

Escribe pruebas unitarias y ejecútalas con cada compilación.



No olvide que NSWindowController y NSViewController liberarán los objetos de nivel superior de los archivos NIB que rigen.

Si carga manualmente un archivo NIB, es responsable de liberar los objetos de nivel superior de ese NIB cuando haya terminado con ellos.


Sé que pasé por alto esto cuando entré por primera vez en la programación de Cocoa.

Asegúrese de que comprende las responsabilidades de gestión de memoria con respecto a los archivos NIB. Usted es responsable de liberar los objetos de nivel superior en cualquier archivo NIB que cargue. Lea la documentación de Apple sobre el tema.


Si está utilizando Leopard (Mac OS X 10.5) o posterior, puede usar la aplicación Instruments para encontrar y rastrear pérdidas de memoria. Después de construir su programa en Xcode, seleccione Ejecutar> Iniciar con herramienta de rendimiento> Fugas.

Incluso si su aplicación no muestra ninguna fuga, es posible que mantenga los objetos por mucho tiempo. En Instrumentos, puede usar el instrumento ObjectAlloc para esto. Seleccione el instrumento ObjectAlloc en su documento de Instrumentos y muestre los detalles del instrumento (si aún no se muestra) seleccionando Ver> Detalles (debería tener una marca de verificación al lado). En "Vida útil de asignación" en el detalle de ObjectAlloc, asegúrese de elegir el botón de opción junto a "Creado y vivo".

Ahora, cuando deje de grabar su aplicación, al seleccionar la herramienta ObjectAlloc le mostrará cuántas referencias hay de cada objeto que aún vive en su aplicación en la columna "# Net". Asegúrese de no solo ver sus propias clases, sino también las clases de los objetos de nivel superior de sus archivos NIB. Por ejemplo, si no tiene ventanas en la pantalla y ve referencias a una ventana sin conexión de NS, es posible que no la haya publicado en su código.


Todos estos comentarios son excelentes, pero estoy realmente sorprendido de que nadie haya mencionado la Guía de estilo Objective-C de Google que se publicó hace un tiempo. Creo que han hecho un trabajo muy completo.







ios