Effective Objective-C 2.0 by Matt Galloway

Effective Objective-C 2.0

6.5/106 min read

3/18/20

  • The syntax may appear alien because it uses a messaging structure rather than function calling

  • With messaging, the lookup is always at runtime and uses dynamic binding

  • The memory for objects are always allocated in heap space and never on the stack

  • Creating another variable pointing to the same location does not create a copy but rather yields two variables pointing to the same object

  • Pointers are allocated on the stack

  • When non-object types (int, float, double, char, etc.) are the only data to be held, a structure, such as CGRect, is usually used

  • Objective-C is a superset of C, adding object-oriented features

  • If you only need to know that a class exists rather than the full details, use @class to forward declare the class rather than import the class's header file. Then important the header file in the implementation file so you know how to use it

  • You must import the header that defines the superclass from which you are inheriting

  • If you declare any protocols that your class conforms to, they have to be fully defined and not forward declared

  • The complier needs to be able to see the methods the protocol defines rather than simply that a protocol does exist from a forward declaration

  • If you are creating an array using the literal syntax, if any of the objects is nil, an exception is thrown

  • If you want to make a mutable variant of a literal syntax variable, you must make a mutableCopy of the variable

  • There is always a better to define a constant than using a preprocessor define

  • The usual convention for constants is to prefix with the letter k for constants that are local to a translation unit

  • A constant that does not need to be exposed to the outside world should be defined in the implementation file where it is used

  • Static means the variable is local to the translation unit in which it is defined

  • A translation unit is the input the compiler receives to geenerate one object file. In the case of Objective-C, this is usually the implementation file

  • For global constants, declare them in the header file with extern <type> *const variableName; and define them in the implementation file with <type> *const variableName = value;

  • For external constants, prefix the name with the name of the class that the constant relates to to help avoid potential clashes

  • Avoid preprocessor defines. They don't contain any type information and are simply a find and replace executed before compilation

  • Use enumerations to give readable names to values used for the states of a state machine, options passed to methods, and error status codes

  • An enumeration is nothing more than a way of naming constant values

  • Add a typedef to the enumeration definition so the type can be used instead of the full enum

  • When used for switching on an enumeration that defines a state machine, it is best not to have a default entry. This helps if you add to the enumeration, because the compiler will warn that the switch does not handle all the values

  • You will usually want to use nonatomic properties on iOS

  • Direct access to instance variables is faster, as it does not have to go through Objective-C method dispatch

  • Always use direct access to instance variables within an initializer method

  • The == operator compares the pointers themselves rather than the objects to which they point

  • Use the isEqual: instead

  • Rather than checking equality of class objects, use isKindOfClass:

  • Class clusters have init methods to return an object of various subclasses based on the type passed into the init method and then overriding methods in the subclasses

  • There should be just one designated initializer that all other initializers call

  • You should always override the designated initializer of your superclass if you have a designated initializer with a different name

  • Implement the description method to be able to log the object with NSLog(@"%@")

  • Create objects that are immutable

  • Provide methods to mutate collections held by objects rather than exposing a mutable collection as a property

  • If a method returns a newly created value, the first word in the method name should be its type

  • A parameter should be immediately preceded by a noun describing its type

  • Avoid abbreviations and instead use full names

  • Methods that return a Boolean should be prefixed by either has or is

  • Avoid abbreviations of types in method names

  • Prefix private method names, i.e. _ or p_

  • Private methods only need to be declared in the implementation file

  • NSError objects contain an error domain, an error code, and user info

  • Implement copyWithZone:zone to implement the NSCopying protocol for your own classes

  • The contents of a shallow copy point to the same objects as the original. The contents of a deep copy point to copies of the original contents

  • Objective-C does not have multiple inheritance, so protocols provide a way to define a set of methods that a class should implement

  • Protocols are a good way of documenting an interface to your code

  • Categories provide you with a way to add methods to a class without having to subclass it

  • Use delegate and data source protocols for interobject communication

  • The Delegate pattern defines an interface that any object can conform to in order to become the delegate of another object. This other object talks back to its delegate to get some information or to inform the delegate when interesting things happen

  • A delegate property will usually be defined using a weak attribute

  • Implementing the delegate is a matter of declaring that your class implements the delegate protocol and then implementing any methods you want from the protocol

  • You can declare that a class implements a protocol in either the interface or the class continuation category

  • Before any optional method is called on the delegate, introspection should be used to determine whether the delegate responds to that selector

  • Use categories to split a class implementation into more manageable fragments

  • Use the class-continuation category to hide private instance variables and methods

  • Automatic Reference Counting adds in the retains and releases for you

  • You should never call dealloc

  • You should only us dealloc to release references to other objects and to unregister anything that needs to be, such as Key-Value Observing (KVO) or NSNotificationCenter notifications

  • If you don't own an object, you should not retain it and instead use __weak

  • Sending a message to a deallocated object is completely unsafe

  • Blocks can use anything from the scope in which they are defined

  • block type syntax: return_type (^block_name)(parameters) = ^{...}

  • Use the dispatch queue to ensure synchronization

  • Use [object performSelector:@selector(selectorName)] to dynamically call a method at runtime. This can cause a memory leak. Can also use it with up to two parameters with withObject:. Can combine with afterDelay:.

  • dispatch_async(dispatch_get_main_queue(), ^{ [self doSomething]; });

  • Use dispatch_once for thread-safe single-time code execution

  • enumerateObjectsUsingBlock and enumerateKeysAndObjectsUsingBlock to enumerate over objects