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

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

Hay algunas cosas que he comenzado a hacer que no creo son estándar:

1) Con la llegada de las properties, ya no uso "_" para prefijar variables de class "privadas". Después de todo, si otras classs pueden acceder a una variable, ¿no debería haber una propiedad para ella? Siempre me ha disgustado el prefijo "_" para hacer que el código sea más feo, y ahora puedo dejarlo fuera.

2) Hablando de cosas privadas, prefiero ubicar definiciones de methods privados dentro del file .m en una extensión de class como tal:

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

¿Por qué desorderar el file .h con cosas de las que los extranjeros no deberían importarle? El vacío () funciona para categorías privadas en el file .m y emite advertencias de compilation si no implementa los methods declarados.

3) Me he tomado a poner dealloc en la parte superior del file .m, justo debajo de las directivas @synthesize. ¿No deberías estar en lo más alto de la list de cosas en las que quieres pensar en una class? Esto 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 performance. Eso significa establecer el color de background apropiado en todo.

3.6) Al usar una NSURLConnection, por regla general, es posible que desee implementar el método de 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 la exception que la regla en la que querrás respuestas almacenadas en caching, especialmente para llamadas de service web. La implementación del método como se muestra deshabilita el almacenamiento en caching de respuestas.

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

4) Solo use doble precisión si es necesario, como cuando se trabaja con CoreLocation. Asegúrate de terminar tus constantes en 'f' para que gcc las almacene como flotantes.

 float val = someFloat * 2.2f; 

Esto es principalmente importante cuando someFloat puede ser un doble, no necesitas las matemáticas de modo mixto, ya que estás perdiendo precisión en 'val' en almacenamiento. Si bien los numbers de punto flotante son compatibles con el hardware en iPhones, aún puede tomar más time para hacer aritmética de doble precisión en comparación con la precisión única. Referencias:

  • Doble vs flotante en el iPhone
  • Matemáticas de precisión doble iPhone / iPad

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

5) Establezca sus properties como no nonatomic . Son atomic de forma pnetworkingeterminada y, tras la síntesis, se creará un código de semáforo para evitar problemas de subprocesss múltiples. El 99% de usted probablemente no necesita preocuparse por esto y el código es mucho less hinchado y más eficiente en memory cuando se establece en no atómico.

6) SQLite puede ser una manera muy, muy rápida de almacenar en caching grandes sets de datos. Una aplicación de maps, por ejemplo, puede almacenar en caching sus mosaicos en files SQLite. La parte más cara es la E / S de disco. Evite muchas escrituras pequeñas enviando BEGIN; y COMMIT; entre grandes bloques. Usamos un timer de 2 segundos, por ejemplo, que se restablece en cada nuevo envío. Cuando expire, enviaremos COMMIT; , lo que hace que todas sus escrituras se envíen en una gran parte. SQLite almacena los datos de la transacción en el disco y al hacer este ajuste Begin / End evita la creación de muchos files de transactions, agrupando todas las transactions en un solo file.

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 objects estáticos y ejecutar su SQL en un hilo separado. Asegúrate de envolver cualquier cosa que modifique la database para cadenas de consulta en @synchronize() {} bloques. Para las consultas cortas, simplemente deje las cosas en el hilo principal para una mayor comodidad.

Más consejos de optimization de SQLite están aquí, aunque el documento parece anticuado, muchos de los puntos probablemente sigan siendo buenos;

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

No utilice cadenas desconocidas como cadenas de formatting.

Cuando los methods o funciones toman un argumento de cadena de formatting, debe asegurarse de tener control sobre el contenido de la cadena de formatting.

Por ejemplo, al registrar cadenas, es tentador pasar la variable de cadena como único argumento a 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 formatting. Esto puede generar salidas erróneas, fallas y problemas de security. En su lugar, debe sustituir la variable de cadena en una cadena de formatting:

  NSLog(@"%@", aString); 

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

Ejemplos de qué hacer y qué no hacer:

  • No declarar id m_something; en la interfaz de un object y lo llaman una variable o campo miembro ; use something o _something por su nombre y _something una variable de instancia .
  • No nombre un getter -getSomething ; el nombre apropiado de Cocoa es solo -something .
  • No nombre un setter -something: debería ser -setSomething:
  • El nombre del método se intercala con los arguments e incluye dos puntos; es -[NSObject performSelector:withObject:] , no NSObject::performSelector .
  • Use inter-caps (CamelCase) en nombres de methods, parameters, variables, nombres de classs, etc. en lugar de barras inferiores (guiones bajos).
  • Los nombres de las classs comienzan con una letra mayúscula, una variable y nombres de método con minúsculas.

Sea lo que sea que hagas, no uses la notación húngara estilo Win16 / Win32. Incluso Microsoft renunció a eso con la mudanza a la plataforma .NET.

IBOutlets

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

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

El uso de properties hace que la semántica de gestión de memory sea clara; También proporciona un patrón consistente si usa la síntesis de variables de instancia.

Use el analizador estático LLVM / Clang

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

Utiliza Clang Static Analyzer para, como era de esperar, analiza tu código C y Objective-C (aún no C ++) en Mac OS X 10.5. Es trivial instalar y usar:

  1. Descargue la última versión de esta página .
  2. Desde la command-line, cd al directory del proyecto.
  3. Ejecute scan-build -k -V xcodebuild .

(Hay algunas restricciones adicionales, etc., en particular, debería analizar un proyecto en su configuration "Depuración" – vea http://clang.llvm.org/StaticAnalysisUsage.html para más detalles, pero eso es más o less a qué se networkinguce.)

Luego, el analizador produce un set de páginas web para usted que muestra la probable administración de memory y otros problemas básicos que el comstackdor no puede detectar.

Esto es sutil, pero práctico. Si se pasa como delegado a otro object, restablezca el delegado de ese object antes de que se dealloc .

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

Al hacer esto, se asegura de que no se enviarán más methods de delegado. Cuando estás a punto de dealloc y desaparecer en el éter, quieres asegurarte de que nada pueda enviarte más posts por crash. Recuerde que self.someObject podría ser retenido por otro object (podría ser un singleton o en la agrupación de autorelease o lo que sea) y hasta que le diga "¡deje de enviarme posts!", Piensa que su object justo para ser desasignado es un juego justo

Entrar en este hábito te salvará de muchos crashs extraños que son un dolor de debugging.

El mismo principio se aplica a la observación del valor key, y NSNotificaciones también.

Editar:

Incluso 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 class se describen en Referencia de Objective-C 2.0 de Apple.

"Las extensiones de class le permiten declarar la API requerida adicional para una class en ubicaciones que no estén dentro del bloque @interface de la class primaria"

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

Evite autorelease

Como típicamente (1) no tiene control directo sobre su vida útil, los objects autoelevados pueden persistir por un time comparativamente largo y boost innecesariamente la huella de memory de su aplicación. Si bien en el escritorio esto puede tener pocas consecuencias, en plataforms más restringidas esto puede ser un problema importante. En todas las plataforms, por lo tanto, y especialmente en plataforms más restringidas, se considera una mejor práctica evitar utilizar methods que lleven a objects autoelegidos y, en su lugar, se recomienda utilizar el patrón alloc / init.

Por lo tanto, en lugar de:

 aVariable = [AClass convenienceMethod]; 

donde sea capaz, debe usar:

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

Cuando está escribiendo sus propios methods que devuelven un object recién creado, puede aprovechar la convención de nomenclatura de Cocoa para señalar al receptor que debe liberarse al anteponer 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 object recibido (ver, por ejemplo, el método newObject de newObject ).

(1) Puede tomar el control mediante el uso de sus propias agrupaciones autorelease locales. Para get más información sobre esto, consulte Autorelease Pools .

Algunos de estos ya han sido mencionados, pero esto es lo que se me ocurre:

  • Sigue las reglas de denominación 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 que se supone que deben hacerlo. Esto abarca no solo los methods de acceso y las variables de instancia, sino también muchas relaciones, la validation, la notificación automática de keys dependientes, etc.
  • Coloque los methods privados en una categoría. No solo la interfaz, sino también la implementación. Es bueno tener cierta distancia conceptualmente entre methods privados y no privados. Incluyo todo en mi file .m.
  • Coloque los methods de hilo de background en una categoría. Lo mismo que arriba. He descubierto que es bueno tener una barrera conceptual clara cuando estás pensando en lo que está en el hilo principal y lo que no.
  • Use #pragma mark [section] . Por lo general, me agrupo según mis propios methods, las anulaciones de cada subclass y cualquier información o protocolos formales. Esto hace que sea mucho más fácil saltar a exactamente lo que estoy buscando. En el mismo tema, agrupe methods similares (como los methods delegates de una vista de tabla) juntos, no los coloque en cualquier lugar.
  • Prefijos methods privados y ivars con _. Me gusta como parece, y tengo less probabilidades de usar un ivar cuando me refiero a una propiedad por crash.
  • No utilice los methods / properties de mutator en init & dealloc. Nunca he tenido nada malo debido a eso, pero puedo ver la lógica si cambias el método para hacer algo que depende del estado de tu object.
  • Ponga IBOutlets en properties. En realidad, acabo de leer esto aquí, pero voy a comenzar a hacerlo. Independientemente de los beneficios de memory, parece mejor estilísticamente (al less para mí).
  • Evita escribir código que no necesitas absolutamente. Esto realmente cubre muchas cosas, como hacer ivars cuando un #define hará, o almacenar en caching una matriz en lugar de orderarla cada vez que se necesitan datos. Hay mucho que podría decir al respecto, pero la conclusión es que no escriba código hasta que lo necesite, o el profiler le dice que lo haga. Hace que las cosas sean mucho más fáciles de mantener a largo ploop.
  • Termina lo que comienzas. Tener una gran cantidad de código buggy a medio terminar es la forma más rápida de matar un proyecto muerto. Si necesita un método stub que esté bien, simplemente indíquelo colocando NSLog( @"stub" ) interior, o como quiera hacer un seguimiento de las cosas.

Escribir testings unitarias. Puede probar muchas cosas en Cocoa que podrían ser más difíciles en otros frameworks. Por ejemplo, con el código de la interfaz de usuario, generalmente puede verificar que las cosas estén conectadas como deberían y confiar en que funcionarán cuando se utilicen. Y puede configurar fácilmente los methods de estado e invocar delegates para probarlos.

Tampoco tiene una visibilidad pública vs. protegida frente a un método privado que se interpone en la escritura de testings para sus componentes internos.

Regla dorada: si alloc , ¡ release !

ACTUALIZACIÓN: A less que esté usando ARC

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

Una vez vi a un equipo que solía escribir aplicaciones web Java EE tratar de escribir una aplicación de escritorio Cocoa. Como si se tratara de una aplicación web Java EE. Había una gran cantidad de AbstractFooFactory y FooFactory, y IFoo y Foo volaban cuando lo único que realmente necesitaban era una class Foo y posiblemente un protocolo Fooable.

Parte de asegurar que no hagas esto es comprender realmente las diferencias en el idioma. Por ejemplo, no necesita las classs abstractas de fábrica y de fábrica anteriores porque los methods de class Objective-C se envían de manera tan dinámica como los methods de instancia, y se pueden replace en subclasss.

Asegúrate de marcar la página de debugging mágica . Esta debería ser su primera parada cuando golpea la cabeza contra una panetworking mientras trata de encontrar la fuente de un error de cocoa.

Por ejemplo, le dirá cómo encontrar el método en el que primero asignó la memory que más tarde está causando fallas (como durante la terminación de la aplicación).

Ordenar cadenas como el usuario quiere

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

Para get más detalles, consulte Búsqueda, comparación y sorting de 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 classs existentes ( "¿Qué? Puedo agregar un método para convertir un número a numbers romanos a NSNumber rock on!" ).

No lo hagas.

Su código será más portátil y más fácil de comprender, sin docenas de pequeños methods de categoría espolvoreados sobre dos docenas de classs básicas.

La mayoría de las veces cuando realmente crees que necesitas un método de categoría para ayudar a optimizar un código, encontrarás que nunca terminas de reutilizar el método.

También hay otros peligros, a less que se trate de nombres que espacien sus methods de categoría (y ¿quién además del ddribin completamente loco es?) Existe la posibilidad de que Apple, un complemento o cualquier otra cosa que se ejecute en su espacio de direcciones también definirá la misma categoría método con el mismo nombre con un efecto secundario ligeramente diferente …

DE ACUERDO. Ahora que te han advertido, ignora el "no hagas esta parte". Pero ejerza una restricción extrema.

Resiste subclassando al mundo. En Cocoa se hace mucho a través de la delegación y el uso del time de ejecución subyacente que en otros frameworks se realiza a través de subclasss.

Por ejemplo, en Java se utilizan instancias de subclasss anónimas *Listener mucho y en .NET se usan mucho las subclasss EventArgs . En Cocoa, tampoco lo hace; en su lugar, se utiliza la acción de destino.

Propiedades declaradas

Por lo general, debe utilizar la característica Propiedades declaradas de Objective-C 2.0 para todas sus properties. Si no son públicos, agréguelos en una extensión de class. El uso de las properties declaradas hace que la semántica de administración de memory se borre de inmediato y facilita el control del método dealloc. Si agrupa las declaraciones de properties juntas, puede escanearlas rápidamente y compararlas con la implementación de su método dealloc.

Debes pensar mucho antes de no marcar las properties como 'no atómicas'. Como señala la Guía de lenguaje de progtwigción Objective C , las properties son atómicas de forma pnetworkingeterminada e incurren en una sobrecarga considerable. Además, simplemente hacer que todas tus properties sean atómicas no hace que tu aplicación sea segura para subprocesss. También tenga en count, por supuesto, que si no especifica 'no atómico' e implementa sus propios methods de acceso (en lugar de sintetizarlos), debe implementarlos de manera atómica.

Piensa en valores nulos

Como se observa en esta pregunta , los posts a nil son válidos en Objective-C. Si bien con frecuencia es una ventaja, lo que lleva a un código más limpio y más natural, la característica puede ocasionalmente dar lugar a errores particulares y difíciles de rastrear si obtienes un valor nil cuando no lo esperabas.

Utiliza NSAssert y amigos. Uso nil como object válido todo el time … especialmente enviar posts a nil es perfectamente válido en Obj-C. Sin embargo, si realmente quiero asegurarme del estado de una variable, uso NSAssert y NSParameterAssert, lo que ayuda a rastrear problemas fácilmente.

Simple but oft-forgotten one. According to spec:

In general, methods in different classes that have the same selector (the same name) must also share the same return and argument types. This constraint is imposed by the compiler to allow dynamic binding.

in which case all the same named selectors, even if in different classes , will be regarded as to have identical return/argument types. Here is a simple example.

 @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 networkinguce 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 hundnetworkings 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); 

is the same as:

 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 shanetworking 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 shanetworking 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)