Preface: I read this book for the first time about a year and a half ago. I found the electronic version on the Internet and read it temporarily for one night. Then I didn’t read it again. In August, I decided to take half a month or so to read the book (but I only read the first five chapters during the two weeks I spent working on a new version of my company’s project). I benefited a lot after reading it. Today, I find time to sort out part of the notes I made before and make a record and share.


  • Object memory is always allocated in the heap space, never allocated on the stack. OC objects cannot be allocated on the stack.

  • Sometimes they encounter variables that do not contain * in their definition, and they may use stack space instead. These variables do not hold OC objects, such as CGRect, which is a structure;

  • Creating objects requires additional overhead, such as allocating and freeing memory;

  • If in a class file, just need to know the name of the class of another, without the need to use the class interface, try to use forward declaration @ class rather than # import “” introduction of header files, will introduce a header file time delay as far as possible, so that we can reduce the compile time, also can avoid the circular reference, lead to two classes in a class can not be compiled.

  • Use literal syntax for arrays and dictionaries. It is safer to use literal syntax for arrays and dictionaries. When an object in a collection is empty, it will throw an exception

  • Preprocessor constants have no type information. 2. Try to declare preprocessors in implementation files rather than declarations

  • Enumerations that need to be combined by bits or operations should be defined using NS_OPTIONS. Enumerations that do not need to be combined with each other should be defined using NS_ENUM. Both macros are backward compatible using the #define preprocessor. Reason: in C++ compilation mode, it is assumed that the data type of the result of a bitwise operation should be the underlying data type of the enumeration, and C++ does not allow “implicit conversion” of this underlying type to the enumeration type itself. If you use the NS_ENUM macro to define combinatorial enumerations, you may get an error

  • If you use enumerations to define state machines in switch statements, it is best not to have the default branch. That way, if a state is later added, the compiler will warn that the new state is not being processed in the switch statement, keeping the code accurate. Otherwise, the system automatically enters the default branch for processing without warning.

  • In iOS development, almost all properties are declared as nonatomic, for historical reasons: using synchronous locks in iOS development is expensive and can cause performance problems. In general, attributes are not required to be “atomic” because they are not “thread-safe” and a deeper locking mechanism is required for thread-safe operations.

  • Both “collection” and “set” are called “collection” in Chinese. The former is the general name of data structures such as Array, Dictionary, and set.

  • The object equality “==” operator compares two Pointers rather than the object to which the Pointers point, which is less accurate. “IsEqualToString” is faster than “isEqual”, which also performs other operations; Basic data types determine equality use: use “= =” judging equality priority: “isEqualToString/Array/Dictionary” > “isEqual” > “= =”

  • There are many class families in the system framework, especially collection classes, such as arrays, dictionaries, and so on. The main idea of using “class family pattern” is to hide the internal implementation details of the base class through inheritance, open the public interface, easy to call, easy to maintain; For example, in the project project, create the parent class ListViewController for all viewController classes containing list views, unify the interface and management through inheritance, and simplify the code; As there are more and more subclasses, the advantages of class families become more and more obvious, and developers need not worry about other issues, just need to add the initialization interface of the base class to the implementation method. The various attribute definitions and method implementations are called from the common interface of the base class;

  • Associated object Setting Associated object: objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, <#objc_AssociationPolicy policy#>) get the corresponding associated object: Objc_getAssociatedObject (<#id object#>, <#const void *key#>) removes all associated objects: The set object associated with the key is “opaque pointer”, is not confined to a particular type of pointer, if want to make the two keys match to the same value, must be exactly the same pointer, so when setting a static global variable, usually using a static global variable do key, also can use the selector to wait, to ensure equality. Associative objects are generally used only when nothing else works, because misuse of associative objects can lead to “retention loops” that run amok with code and crash programs

  • C language using static binding, at compile time can determine at run time should call the function in the OC, if to give a message to an object, dynamic binding mechanism is used to determine the need to call the method to a particular object to send messages, after seeing this message compiler, will transform it into a standard C language function calls, The function called is the core message passing function: objc_msgSend(); Void (*)(id,SEL,id,,))objc_msgSend)(self,@selector(selector),object1,,,); The objc_msgSend function performs the order of method calls: in the list of methods of the recipient’s class, find a method with the same name as the selector and call it; Failed to find — “progressive search for the parent of the recipient’s class; After a match is successful, objc_msgSend will cache the match result in the Fast Mapping table, which will be called again much faster

  • Use Method deployment techniques to swap implementations of the two methods: Method method1 = class_getInstanceMethod([self class], @selector(testMethodWithInfo:)); Method method2 = class_getInstanceMethod([self class], @selector(test)); method_exchangeImplementations(method1, method2); The system calls method2 when it calls method1 and calls method1 when it calls method2. With this approach, you can add logging capabilities to black-box methods that are “completely unaware of their implementation,” which is very helpful for program debugging, but is generally only used when debugging programs.

  • Apple claims that it reserves the right of all “two-letter prefixes”, so in order to avoid “duplicate symbol error”, the application should add “three-letter prefixes” when declaring the class name. If the company is Ali, and you want to customize a PayView class, you should name it ALiPayView.

  • Prefix the names of private methods, such as p_ (p for private), to distinguish them from public methods; Don’t use a single underscore as a prefix. This is apple’s reserved approach, which can cause conflicts.

  • The content after a shallow copy refers to the same object as the original, while the object after a deep copy refers to a copy of the related object in the original. That is, when the value of the copied object is changed after a shallow copy, the original content is also changed. However, when the value of the copied object is changed after a deep copy, the original content is not changed.

  • For immutable NSArray and mutable NSMutableArray, the following relationship always holds: [NSMutableArray copy] =>NSArray [NSArray mutableCopy] =>NSMutableArray

  • When there are too many methods in the implementation of a class, resulting in code redundancy, the method of “classification” can be used to classify the methods in the class as needed and divide them into several partitions for easy management and maintenance.

  • In programming library for sharing, if there are several ways, they are not part of the public API, however, is well suited for use within libraries, we should create a private classification at this moment, when some parts of the library need to use these methods, import the classification of header files, and set the header file does not open together with the library.

  • When adding classes to third party classes (public apis, such as NSString) : 1. Always prefix their names with your own names to avoid class name conflicts. 2, always add your own prefix to the method name to avoid method overwriting; Note: If you create multiple classes for third-party classes in your project and all declare and implement methods with the same method name, then when you call that method in your program, the method in the last class created is implemented. 3. Do not define attributes in categories

  • Retention ring (circular reference) : When two or more objects refer to each other in a loop, memory cannot be freed because the reference count of the objects in the loop does not drop to zero, resulting in a memory leak.

  • The following modifiers can be used to change the semantics of local and instance variables: __strong: the default semantics, retain this value. __unsafe_unretained: Do not retain this value. This may not be safe because by the time a variable is used again, its object may have been retrieved. __weak: This value is not kept, but the variable is safe to use because if the object is reclaimed, the variable is automatically empty. __autoreleasing: This special modifier is used when passing objects “by reference” to methods. This value is released automatically when the method returns.

So when a program calls the block syntax, because the block automatically preserves all objects it captures, if one of these objects preserves the block itself (such as self), it may result in circular references (retaining rings). When self is modified with __weak, the reference count of weakSelf will be automatically cleared, which will not lead to the generation of reserve rings.

  • ARC is only responsible for managing the memory of oc objects. It is important to note that CoreFoundation objects are not managed by ARC and developers must call CFRetain/CFRelease when appropriate.

  • All observation behaviors configured for objects should be unregistered in Dealloc. ARC automatically executes the parent class’s Dealloc method, so there is no need to manually call [super Dealloc] when implementing the dealloc method in ARC.

  • When the system recycles an object, it can convert it to a zombie object instead of actually recycling it. You can enable this function by using the environment variable NSZombieEnable.

  • The system modifies the ISA pointer of an object to point to a special zombie class, thus turning the object into a zombie object. The zombie class can respond to all selectors by printing a message containing the message content and its recipient, and then terminating the application.