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

Sé acerca de HIG (¡que es bastante útil!), Pero ¿qué prácticas de progtwigción usas cuando escribes Objective-C, y más específicamente cuando usas Cocoa (o CocoaTouch)?

Hay algunas cosas que he empezado a hacer que no creo que sean estándar:

1) Con la llegada de las propiedades, ya no uso “_” para prefijar las 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 “_” por hacer el código más feo, y ahora puedo dejarlo.

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

#import "MyClass.h" @interface MyClass () - (void) someMethod; - (void) someOtherMethod; @end @implementation MyClass 

¿Por qué complicar el archivo .h con cosas externas no debería importarle? Empty () funciona para categorías privadas en el archivo .m y emite advertencias de comstackción si no implementa los métodos declarados.

3) He llevado a poner dealloc en la parte superior del archivo .m, justo debajo de las directivas @synthesize. ¿No debería ser lo que trataste al principio de la lista de cosas en las que quieres pensar en una clase? Eso es especialmente cierto en un entorno como el iPhone.

3.5) En las celdas de la tabla, haga que cada elemento (incluida la celda misma) sea opaco para el rendimiento. Eso significa establecer el color de fondo apropiado en todo.

3.6) Cuando se usa una NSURLConnection, como regla, es posible que desee implementar el método de delegado:

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

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

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

4) Solo use doble precisión si es necesario, como cuando trabaja con CoreLocation. Asegúrese de finalizar sus constantes en ‘f’ para que gcc las almacene como flotantes.

 float val = someFloat * 2.2f; 

Esto es principalmente importante cuando un someFloat puede ser un doble, no necesita el modo mixto matemático, ya que está perdiendo precisión en ‘val’ en el almacenamiento. Si bien los números de punto flotante son compatibles con el hardware en iPhones, aún puede tomar más tiempo hacer aritmética de precisión doble en lugar de precisión simple. Referencias

  • Doble contra flotador en el iPhone
  • iPhone / iPad doble precisión matemática

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

5) Establezca sus propiedades como no nonatomic . Son atomic por defecto y, al sintetizarse, se creará un código de semáforo para evitar problemas de subprocesos múltiples. Es probable que el 99% de ustedes no tengan que preocuparse por esto y el código sea mucho menos hinchado y más eficiente con la memoria cuando se configura como no atómico.

6) SQLite puede ser una manera muy, muy rápida de almacenar en caché grandes conjuntos de datos. Una aplicación de mapa, por ejemplo, puede almacenar sus teselas en archivos SQLite. La parte más cara es la E / S de disco. Evite muchas escrituras pequeñas al enviar BEGIN; y COMMIT; entre grandes bloques. Usamos un temporizador de 2 segundos, por ejemplo, que se restablece en cada nuevo envío. Cuando caduca, enviamos COMMIT; , lo que hace que todas tus escrituras entren en una gran porción. SQLite almacena los datos de transacción en el disco y al hacer esto, la opción Principio / Finalización 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 ajustar todo lo que modifica la base de datos para cadenas de consulta en @synchronize() {} . Para consultas breves, simplemente deje las cosas en el hilo principal para una mayor comodidad.

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

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

No use cadenas desconocidas como cadenas de formato

Cuando los métodos o funciones toman un argumento de cadena de formato, debe asegurarse de tener control sobre el contenido de la cadena de formato.

Por ejemplo, cuando se registran cadenas, es tentador pasar la variable de cadena como único argumento para NSLog :

  NSString *aString = // get a string from somewhere; NSLog(aString); 

El problema con esto es que la cadena puede contener caracteres que se interpretan como cadenas de formato. Esto puede provocar errores en la producción, lockings y problemas de seguridad. En su lugar, debe sustituir la variable de cadena en una cadena de formato:

  NSLog(@"%@", aString); 

Use las convenciones y terminología estándar de nomenclatura y nombres de Cocoa en lugar de lo que esté acostumbrado de otro entorno. Hay muchos desarrolladores de Cocoa por ahí, y cuando otro de ellos comience a trabajar con tu 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 declarar id m_something; en la interfaz de un objeto y llamarlo una variable o campo miembro ; usa something o something por su nombre y llámalo una variable de instancia .
  • No nombre un getter -getSomething ; el nombre correcto de Cocoa es solo -something .
  • No nombre un setter -something: debería ser -setSomething:
  • El nombre del método está intercalado con los argumentos e incluye dos puntos; es -[NSObject performSelector:withObject:] , no NSObject::performSelector .
  • Use intercapas (CamelCase) en 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, variable y nombres de método con minúsculas.

Cualquier otra cosa que hagas, no uses la notación húngara Win16 / Win32. Incluso Microsoft renunció a eso con el cambio a la plataforma .NET.

IBOutlets

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

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

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

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 (sin C ++ todavía) en Mac OS X 10.5. Es trivial de instalar y usar:

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

(Hay 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 detalles, pero eso es más o menos lo que se reduce a).

Luego, el analizador genera un conjunto de páginas web que muestran la posible administración de la memoria y otros problemas básicos que el comstackdor no puede detectar.

Este es uno sutil pero útil. Si se está transfiriendo como delegado a otro objeto, restablezca el delegado de ese objeto antes de dealloc .

 - (void)dealloc { self.someObject.delegate = NULL; self.someObject = NULL; // [super dealloc]; } 

Al hacer esto, se asegura de que no se envíen más métodos de delegado. Como está por dealloc y desaparecer en el éter, querrá asegurarse de que nada pueda enviarle más mensajes por accidente. Recuerde que self.someObject podría ser retenido por otro objeto (podría ser un singleton o en el pool de autorrelease o lo que sea) y hasta que diga “¡dejen de enviarme mensajes!”, Cree que su objeto justo a punto de ser liberado es juego limpio.

Entrar en este hábito te salvará de muchos accidentes extraños que son difíciles de depurar.

El mismo principio se aplica a Key Value Observation y NSNotifications también.

Editar:

Aún más defensivo, cambio:

 self.someObject.delegate = NULL; 

dentro:

 if (self.someObject.delegate == self) self.someObject.delegate = NULL; 

@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 Objective-C 2.0 Reference de Apple.

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

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

Evitar la liberación automática

Como normalmente (1) no tiene control directo sobre su vida útil, los objetos liberados automáticamente pueden persistir durante un tiempo comparativamente largo y boost innecesariamente la huella de memoria de su aplicación. Mientras que en el escritorio esto puede ser de poca importancia, en plataformas más restringidas esto puede ser un problema importante. En todas las plataformas, por lo tanto, y especialmente en plataformas más restringidas, se considera la mejor práctica para evitar el uso de métodos que podrían conducir a objetos liberados automáticamente y, en su lugar, se recomienda utilizar el patrón alloc / init.

Por lo tanto, en lugar de:

 aVariable = [AClass convenienceMethod]; 

donde sea posible, debes usar:

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

Cuando escribe 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 ser liberado anteponiendo el nombre del método con “nuevo”.

Por lo tanto, en lugar de:

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

podrías 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 de autorrelease locales. Para más información sobre esto, vea Autorelease Pools .

Algunos de estos ya han sido mencionados, pero esto es lo que puedo pensar en la parte superior de mi cabeza:

  • Sigue las reglas de nombres de KVO. Incluso si no usa KVO ahora, en mi experiencia muchas veces todavía es beneficioso en el futuro. Y si está utilizando KVO o enlaces, necesita saber que las cosas van a funcionar de la manera en que se supone que deben hacerlo. Esto abarca no solo los métodos de acceso y las variables de instancia, sino también muchas relaciones, validación, notificación automática de claves dependientes, etc.
  • Pon los métodos privados en una categoría. No solo la interfaz, sino también la implementación. Es bueno tener cierta distancia conceptual entre los métodos privados y no privados. Incluyo todo en mi archivo .m
  • Ponga métodos de hilo de fondo en una categoría. Lo mismo que arriba. Descubrí que es bueno mantener una clara barrera conceptual cuando piensas en lo que está en el hilo principal y lo que no.
  • Use #pragma mark [section] . Usualmente agrupo por mis propios métodos, las anulaciones de cada subclase y cualquier información o protocolo formal. Esto hace que sea mucho más fácil saltar a exactamente lo que estoy buscando. Sobre el mismo tema, agrupe métodos similares (como los métodos delegates de una vista de tabla) juntos, no los coloque en ningún lado.
  • Prefijo métodos privados y ivars con _. Me gusta cómo se ve, y es menos probable que use un ivar cuando me refiero a una propiedad por accidente.
  • No use métodos / propiedades de mutador en init & dealloc. Nunca he tenido nada malo por eso, pero puedo ver la lógica si cambias el método para hacer algo que depende del estado de tu objeto.
  • Poner IBOutlets en las propiedades. De hecho acabo de leer este, pero voy a comenzar a hacerlo. Independientemente de los beneficios de memoria, parece mejor estilísticamente (al menos para mí).
  • Evite escribir código que no necesita absolutamente. Esto realmente cubre muchas cosas, como hacer ivars cuando un #define servirá, o almacenar en caché una matriz en lugar de clasificarla cada vez que se necesiten datos. Hay muchas cosas que puedo decir sobre esto, pero lo importante es no escribir código hasta que lo necesite, o el generador de perfiles se lo diga. Hace las cosas mucho más fáciles de mantener en el largo plazo.
  • Termina lo que comienzas Tener un montón de código a medio terminar es la forma más rápida de matar un proyecto. Si necesita un método stub que esté bien, simplemente indíquelo poniendo NSLog( @"stub" ) adentro, o como quiera que haga un seguimiento de las cosas.

Escribir pruebas unitarias Puede 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 y confiar en que funcionarán cuando se usen. Y puede configurar el estado e invocar fácilmente los métodos de delegado para probarlos.

Tampoco tiene visibilidad de método público frente a protegido versus privado que se interpone en el proceso de redacción de pruebas para su funcionamiento interno.

Regla de Oro: ¡Si alloc entonces release !

ACTUALIZAR: A menos que esté usando ARC

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. Hubo un montón de AbstractFooFactory y FooFactory y IFoo y Foo volando cuando todo lo que realmente necesitaban era una clase Foo y posiblemente un protocolo Fooable.

Parte de garantizar que no hagas esto es realmente entender 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 la clase Objective-C se envían de forma tan dinámica como los métodos de instancia, y pueden anularse en subclases.

Asegúrate de marcar la página de Debugging Magic . Esta debería ser su primera parada cuando golpee su cabeza contra la pared mientras trata de encontrar la fuente de un error de Cocoa.

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

Ordenar cadenas como quiera el usuario

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

Para obtener más información, consulte Buscar, comparar y ordenar cadenas .

Trata de evitar lo que ahora he decidido llamar Newbiecategoryaholism. Cuando los recién llegados a Objective-C descubren categorías, a menudo se vuelven locos, agregando pequeñas categorías útiles a todas las clases existentes ( “¿Qué? ¡Puedo agregar un método para convertir un número a números romanos en NSNumber rock on!” ).

No hagas esto

Su código será más portátil y más fácil de comprender, con docenas de pequeños métodos de categoría salpicados sobre dos docenas de clases de base.

La mayoría de las veces, cuando realmente piensas que necesitas un método de categoría para ayudar a simplificar algún código, nunca terminarás reutilizando el método.

También hay otros peligros, a menos que esté espaciando los métodos de su categoría (¿y quién además de ddribin completamente loco?) Existe la posibilidad de que Apple, o un complemento, o algo más que se ejecute en su espacio de direcciones también defina la misma categoría método con el mismo nombre con un efecto secundario ligeramente diferente ….

DE ACUERDO. Ahora que has sido advertido, ignora el “no hagas esta parte”. Pero ejercite la moderación extrema.

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

Por ejemplo, en Java, usted usa instancias de subclases de *Listener anónimas mucho y en .NET utiliza mucho sus subclases EventArgs . En Cocoa, tampoco lo hace; en su lugar, se usa la acción objective.

Propiedades declaradas

Por lo general, debe utilizar la característica de propiedades declaradas de Objective-C 2.0 para todas sus propiedades. Si no son públicos, agréguelos a una extensión de clase. El uso de las propiedades declaradas hace que la semántica de la gestión de la memoria sea inmediata y facilita la comprobación del método dealloc. Si agrupa las declaraciones de propiedades, puede escanearlas rápidamente y compararlas con la implementación de su método dealloc.

Debería pensar mucho antes de no marcar las propiedades como “no atómicas”. Como se señala en la Guía de lenguaje de progtwigción de Objective C , las propiedades son atómicas por defecto e implican una sobrecarga considerable. Además, simplemente hacer que todas sus propiedades sean atómicas no hace que su aplicación sea segura para subprocesos. También tenga en cuenta, por supuesto, que si no especifica ‘no atómico’ e implementa sus propios métodos de acceso (en lugar de sintetizarlos), debe implementarlos de forma atómica.

Piensa en valores nulos

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

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

Simple pero a menudo olvidado. De acuerdo con 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 comstackdor para permitir el enlace dynamic.

en cuyo caso se considerará que todos los mismos selectores nombrados, incluso en clases diferentes , tienen idénticos tipos de retorno / argumento. 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; } 

If you’re using Leopard (Mac OS X 10.5) or later, you can use the Instruments application to find and track memory leaks. After building your program in Xcode, select Run > Start with Performance Tool > Leaks.

Even if your app doesn’t show any leaks, you may be keeping objects around too long. In Instruments, you can use the ObjectAlloc instrument for this. Select the ObjectAlloc instrument in your Instruments document, and bring up the instrument’s detail (if it isn’t already showing) by choosing View > Detail (it should have a check mark next to it). Under “Allocation Lifespan” in the ObjectAlloc detail, make sure you choose the radio button next to “Created & Still Living”.

Now whenever you stop recording your application, selecting the ObjectAlloc tool will show you how many references there are to each still-living object in your application in the “# Net” column. Make sure you not only look at your own classes, but also the classes of your NIB files’ top-level objects. For example, if you have no windows on the screen, and you see references to a still-living NSWindow, you may have not released it in your code.

Clean up in dealloc.

This is one of the easiest things to forget – esp. when coding at 150mph. Always, always, always clean up your attributes/member variables in dealloc.

I like to use Objc 2 attributes – with the new dot notation – so this makes the cleanup painless. Often as simple as:

 - (void)dealloc { self.someAttribute = NULL; [super dealloc]; } 

This will take care of the release for you and set the attribute to NULL (which I consider defensive programming – in case another method further down in dealloc accesses the member variable again – rare but could happen).

With GC turned on in 10.5, this isn’t needed so much any more – but you might still need to clean up others resources you create, you can do that in the finalize method instead.

All these comments are great, but I’m really surprised nobody mentioned Google’s Objective-C Style Guide that was published a while back. I think they have done a very thorough job.

Also, semi-related topic (with room for more responses!):

What are those little Xcode tips & tricks you wish you knew about 2 years ago? .

Don’t forget that NSWindowController and NSViewController will release the top-level objects of the NIB files they govern.

If you manually load a NIB file, you are responsible for releasing that NIB’s top-level objects when you are done with them.

One rather obvious one for a beginner to use: utilize Xcode’s auto-indentation feature for your code. Even if you are copy/pasting from another source, once you have pasted the code, you can select the entire block of code, right click on it, and then choose the option to re-indent everything within that block.

Xcode will actually parse through that section and indent it based on brackets, loops, etc. It’s a lot more efficient than hitting the space bar or tab key for each and every line.

I know I overlooked this when first getting into Cocoa programming.

Make sure you understand memory management responsibilities regarding NIB files. You are responsible for releasing the top-level objects in any NIB file you load. Read Apple’s Documentation on the subject.

Turn on all GCC warnings, then turn off those that are regularly caused by Apple’s headers to reduce noise.

Also run Clang static analysis frequently; you can enable it for all builds via the “Run Static Analyzer” build setting.

Write unit tests and run them with each build.

Variables and properties

1/ Keeping your headers clean, hiding implementation
Don’t include instance variables in your header. Private variables put into class continuation as properties. Public variables declare as public properties in your header. If it should be only read, declare it as readonly and overwrite it as readwrite in class continutation. Basically I am not using variables at all, only properties.

2/ Give your properties a non-default variable name, example:

 @synthesize property = property_; 

Reason 1: You will catch errors caused by forgetting “self.” when assigning the property. Reason 2: From my experiments, Leak Analyzer in Instruments has problems to detect leaking property with default name.

3/ Never use retain or release directly on properties (or only in very exceptional situations). In your dealloc just assign them a nil. Retain properties are meant to handle retain/release by themselves. You never know if a setter is not, for example, adding or removing observers. You should use the variable directly only inside its setter and getter.

Puntos de vista

1/ Put every view definition into a xib, if you can (the exception is usually dynamic content and layer settings). It saves time (it’s easier than writing code), it’s easy to change and it keeps your code clean.

2/ Don’t try to optimize views by decreasing the number of views. Don’t create UIImageView in your code instead of xib just because you want to add subviews into it. Use UIImageView as background instead. The view framework can handle hundreds of views without problems.

3/ IBOutlets don’t have to be always retained (or strong). Note that most of your IBOutlets are part of your view hierarchy and thus implicitly retained.

4/ Release all IBOutlets in viewDidUnload

5/ Call viewDidUnload from your dealloc method. It is not implicitly called.

Memoria

1/ Autorelease objects when you create them. Many bugs are caused by moving your release call into one if-else branch or after a return statement. Release instead of autorelease should be used only in exceptional situations – eg when you are waiting for a runloop and you don’t want your object to be autoreleased too early.

2/ Even if you are using Authomatic Reference Counting, you have to understand perfectly how retain-release methods work. Using retain-release manually is not more complicated than ARC, in both cases you have to thing about leaks and retain-cycles. Consider using retain-release manually on big projects or complicated object hierarchies.

Comentarios

1/ Make your code autodocumented. Every variable name and method name should tell what it is doing. If code is written correctly (you need a lot of practice in this), you won’t need any code comments (not the same as documentation comments). Algorithms can be complicated but the code should be always simple.

2/ Sometimes, you’ll need a comment. Usually to describe a non apparent code behavior or hack. If you feel you have to write a comment, first try to rewrite the code to be simpler and without the need of comments.

Indentation

1/ Don’t increase indentation too much. Most of your method code should be indented on the method level. Nested blocks (if, for etc.) decrease readability. If you have three nested blocks, you should try to put the inner blocks into a separate method. Four or more nested blocks should be never used. If most of your method code is inside of an if, negate the if condition, example:

 if (self) { //... long initialization code ... } return self; 
 if (!self) { return nil; } //... long initialization code ... return self; 

Understand C code, mainly C structs

Note that Obj-C is only a light OOP layer over C language. You should understand how basic code structures in C work (enums, structs, arrays, pointers etc). Ejemplo:

 view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20); 

es lo mismo que:

 CGRect frame = view.frame; frame.size.height += 20; view.frame = frame; 

Y muchos más

Mantain your own coding standards document and update it often. Try to learn from your bugs. Understand why a bug was created and try to avoid it using coding standards.

Our coding standards have currently about 20 pages, a mix of Java Coding Standards, Google Obj-C/C++ Standards and our own addings. Document your code, use standard standard indentation, white spaces and blank lines on the right places etc.

Be more functional .

Objective-C is object-oriented language, but Cocoa framework functional-style aware, and is designed functional style in many cases.

  1. There is separation of mutability. Use immutable classes as primary, and mutable object as secondary. For instance, use NSArray primarily, and use NSMutableArray only when you need.

  2. There is pure functions. Not so many, buy many of framework APIs are designed like pure function. Look at functions such as CGRectMake() or CGAffineTransformMake() . Obviously pointer form looks more efficient. However indirect argument with pointers can’t offer side-effect-free. Design structures purely as much as possible. Separate even state objects. Use -copy instead of -retain when passing a value to other object. Because shared state can influence mutation to value in other object silently. So can’t be side-effect-free. If you have a value from external from object, copy it. So it’s also important designing shared state as minimal as possible.

However don’t be afraid of using impure functions too.

  1. There is lazy evaluation. See something like -[UIViewController view] property. The view won’t be created when the object is created. It’ll be created when caller reading view property at first time. UIImage will not be loaded until it actually being drawn. There are many implementation like this design. This kind of designs are very helpful for resource management, but if you don’t know the concept of lazy evaluation, it’s not easy to understand behavior of them.

  2. There is closure. Use C-blocks as much as possible. This will simplify your life greatly. But read once more about block-memory-management before using it.

  3. There is semi-auto GC. NSAutoreleasePool. Use -autorelease primary. Use manual -retain/-release secondary when you really need. (ex: memory optimization, explicit resource deletion)