23. Communicate between objects through delegate and data source protocol

We already use protocol’s techniques a lot when we actually code.

When defining proxy attributes, use weak rather than strong to avoid “reserved rings”

@property (nonatomic, weak) id<EOCSomeDelegate> delegate;
Copy the code

24. Split the implementation code of a class into manageable categories

To avoid an implementation file that is too large and has too many implementation methods, you can divide the implementation of a class into different categories based on functionality.

The EOCPerson class can be split into several different implementation files:

EOCPerson+Friendship(.h/.m) EOCPerson+Work(.h/.m) EOCPerson+Play(.h/.m)

If you want to use the methods in the classification, remember to introduce the header file for the classification.

The benefits of this dispersion into classification are:

  1. To facilitate debugging, the compiled symbol table shows the name of the class in the method symbol of the class.
  2. If you put a Private method in a class named Private, it’s easy to see why debugging errors are going wrong, and when you write a generic library for others to use, the header file for the Private class is not public and can only be used by the library itself.

25. Prefix the class names of third-party classes

Classification mechanisms are often used to add functionality to classes that have no source code.

Adding classification methods to the source class is done at runtime when the system loads the classification.

If the method name in the classification is the same as an existing method name in the class, the method in the classification overrides the original implementation. The solution is to prefix methods.

Throughout the application, each instance of a class can call a classified method.

26. Do not declare attributes in categories

With the exception of the “class-cotinuation classification “, none of the other classifications can add instance variables to a class. They cannot combine the instance variables needed to implement properties.

Of course, using associative objects solves this problem of not synthesizing instance variables:

#import <objc/runtime.h> static const char *kFriendsPropertyKey = "kFriendsPropertyKey"; @implementation EOCPerson (Friendship) - (NSArray *)friends { return objc_getAssociatedObject(self,kFriendsPropertyKey);  } - (void)setFriends:(NSArray *)friends { objc_setAssociatedObject(self,kFriendsPropertyKey, friends,OBJC_ASSOCIATION_RETAIN_NONATOMIC); }Copy the code

This is not ideal, however, because memory management semantics are error-prone. In case you change the memory management semantics of a property, remember to change the memory management semantics used by the associated object in the Settings method. So it’s not recommended.

Properties should be defined in the main interface. The purpose of classification is to extend functionality, not to encapsulate data.

27. Use the “class-Continuation classification” to hide implementation details

The “class-continuation class “is the kind of code we often write in our implementation file:

@interface EOCPerson ()
//property here
@end
Copy the code

In this way, methods or instance variables can be hidden for use in this class without being exposed to the public interface.

If a property is declared read-only in the main interface and its value is being modified inside the class, you can extend it to read and write in the class-Continuation class.

28. Provide anonymous objects by protocol

Protocols can provide anonymous typing to some extent. The specific object type can be diluted to an ID type that complies with a protocol.

Use anonymous objects to hide type names.

If the specific type is not important, but the object’s ability to respond to a particular method is, then anonymous objects can be used.

29. Reference counting

When the reference count goes to zero it “might” free up memory, but it’s really just put back into the “available pool”, which can still be accessed if it’s not overwritten, but this is dangerous because it can cause wild Pointers and crash the program.

Weak references avoid retaining rings.

30. Simplify reference counting with ARC

ARC will automatically perform retain, release, and autorelease, so you cannot directly call the memory management method in ARC mode.

  • retain
  • release
  • autorelease
  • dealloc

Instead of using OC’s messaging mechanism, ARC actually calls the underlying C language version such as Objc_retain. You can save a lot of CPU cycles.

If the method name begins with the following word, the returned object is the property of the caller, that is, the calling code is responsible for releasing the object.

  • alloc
  • new
  • copy
  • mutableCopy

If the method name does not start with the preceding four words, the returned object does not belong to the caller and will be released automatically.

The memory management required by these rules is handled automatically by ARC.

ARC can also be optimized at run time. For example, in cases where retain is called immediately after autorelease, ARC can detect this redundant operation at run time and use a flag bit in the global data structure to determine whether the AUTOrelease and retain operations actually need to be performed.

ARC only manages the memory of OC objects. CoreFoundation objects are not managed by ARC and require developers to call CFRetain/CFRelease as appropriate.

31. In the dealloc method, only the reference is released and the listener is unlistener

The dealloc method is executed once and only once at the end of each object’s life cycle, which is eventually reclaimed by the system.

Release all references owned by the object in this method, and ARC automatically generates the. Cxx_destruct method.

One important thing this method does is to clean up all the configured Observation behaviors, such as NSNotificationCenter subscribing to some notification for this object, which should be unregistered. Otherwise, continuing to send notifications to the object will cause a crash.

- (void)dealloc {
    CFRelease(coreFoundationObject);
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
Copy the code

In non-ARC mode, the final call to [super dealloc] is not required in ARC mode.

For resources that are expensive or scarce on the system (such as file descriptors, sockets, chunks of memory, etc.), you should use a “cleanup method” instead of dealloc to free them. For example, after the network connection is used, call the close method. The reasons for this are:

  1. Avoid holding on to scarce resources for too long.
  2. In order to optimize program efficiency, the system does not guarantee that every object’s dealloc method will be executed.

In Dealloc, you can detect if a resource has been cleaned up, and if not, you can print an error message and perform a cleanup.

Some methods should not be called in the dealloc method, for example

  • Method for executing asynchronous tasks
  • Methods that need to be switched to execution by a particular thread
  • Property access method

32. Be aware of memory management issues when writing exception safe code

Although exceptions in OC should only occur in serious errors, sometimes you need to write code to catch exceptions.

Manage memory while catching exceptions to prevent leaks.

Comparing the following two methods, it is obvious that the latter is more appropriate:

(1)

@try { EOCSomeClass *object = [[EOCSomeClass alloc] init]; [object doSomethingThatMayThrow]; [object release]; } @catch (...) { NSLog(@"exception"); }Copy the code

(2)

EOCSomeClass *object; @try { object = [[EOCSomeClass alloc] init]; [object doSomethingThatMayThrow]; } @catch (...) { NSLog(@"exception"); } @finally { [object release]; // This is always executed. }Copy the code

If this is done in non-ARC mode, try/catch would be a big problem, because ARC doesn’t automatically process release in this case, and it would be expensive to do so. However, ARC can still generate code to handle exceptions safely by turning on the -fobjc-Arc-Exceptions compiler flag.

So, in general, if you must catch exceptions in non-ARC mode, try to make sure your code cleans up the object; If you must catch exceptions from ARC, turn on the -fobjc-arc-exceptions flag. Of course, if you find that your program has a lot of exception catching, your code needs to be refactored.