Chapter One: Familiar Objective-C
Article 1: Understanding the Objective-C
origin of language
Rule 2: In the class header file to minimize the introduction of other headers
background:
Use #import "ClassName.h"
can be introduced into all the details of interfaces to other files.
problem:
- .h header file when compiling a use of certain types of documents need not know all the details of this class, only need to know this class is like.
- A header file the header file is introduced B, C header file header file A is introduced, all of the content B will be incorporated with the file header. If this process continues, we will have to introduce many never use the content, which of course increases the compilation time.
Solution:
Use
@class ClassName
"forward declaration" (forward declaring), there is only a statement of this class, no specific details, you can solve the problem.Unless absolutely necessary, do not include headers. In general, you should use the header file a class forward declaration to mention other classes, and those classes introducing header in the implementation file. This will minimize the coupling between classes (coupling).
Inheritance and comply with agreements not to use forward declarations. Sometimes you can not use the forward declaration, for example, to declare that a class follows an agreement. In this case, try to "follow a certain kind of agreement" this statement to "classify" in. If not, put the protocol in a single header file, then introduced.
Forward declaration of action:
- Never use to prevent the introduction of content, reducing the header file reference details.
- Problem-solving two classes refer to each other.
The timing of the introduction of the first document to delay as much as possible, do have introduced only when needed, thus reducing the number of documents required for the introduction of the first class of users.
Article 3: The method of multi-literal syntax, which is equivalent to less
Use literal syntax (literal syntax) can reduce the length of the source code to make it more readable.
Article 4: multi-type constant, less #define
preprocessing directives
problem:
#define
No constants defined in the type of information, the compiler will perform accordingly find and replace operations before compilation. Even if someone redefines the constant value, the compiler does not generate a warning message, which will lead to inconsistent application of constant values.
Solution:
- Defined "visible only within a compilation unit in the variable" static const used in the implementation file. Since these constants not in the global symbol table, so no need to prefix their name. Code is implemented as follows:
// .h 文件
@interface 类名: 父类名
...
@end
// .m 文件
// 类内使用
static const 类型 常量名 = 常量值;
@implementation 类名
...
@end
- Use extern in the header file to declare global variables and define its value in the associated implementation file. This constant to appear in the global symbol table, so the name should be distinguished, usually prefixed with the class name associated with it.
// .h 文件
// 类外可用声明
extern 类名 const 常量名;
@interface 类名: 父类名
...
@end
// .m 文件
// 类外可用声明
类名 const 常量名 = 常量;
@implementation 类名
...
@end
Constant is the name commonly used nomenclature:
- Only within the class, the letters on the front
k
. - Can also be used outside the class, the class name to the most prefix.
Article 5: enumeration indicates the status, options, status codes
- Use enumeration, since these values to friendly names.
- The enumeration value is defined as a power of 2, a multi-enumerated options can be used simultaneously, can be combined by a bitwise OR operation.
- When enumeration is defined, which specifies the type of underlying data, ease of handling.
- In the process of enumeration types
switch
do not realize statementdefault
branch, the ease of adding new enumeration, the compiler error, know where you want to modify.
Chapter II: Object, messages, run
Article 6: Understanding the "Properties" concept
Article 7: Direct access instance variables as far as possible inside the object
Article 8: Understand "Object equivalence" concept
==
Comparison operators are two pointers per se is not the object to which it refers.NSObject
Protocol declaredisEqual
method of determining the equality of two objects.isEqual
The default implementation: if and only if its "pointer value" completely equal, the two objects are equal.- Equivalence class having a specific determination method.
NSString
:isEqualToString:
NSArray
:isEqualToArray:
NSDIctionary
:isEqualToDictionary:
If the object is not to compare corresponding type, it will throw an exception, crash. - Equivalence determination is performed depending on the depth of the object under test. Comparative array of the same number of objects, the objects corresponding positions are equal, equal to the array, which is called "depth equivalence determination." For performance, we recommend decreasing depth as possible.
- Equivalence class variable container after the determination of an object into a container, and modify its contents, it will be difficult to predict the behavior of the latter, it is recommended not to do so.
Article 9: The "class family mode" hide implementation details
Class model family : the use of inheritance, to achieve sub-class variety of functions, the parent class to create some subclasses by setting different types, to perform their respective functions. Role: The implementation details hidden behind a simple set of common interfaces. It should be noted that what is true is that type instance creation, we need to know
New Cocoa
in NSArray
this subclass class family, you need to follow a few rules:
- Subclass should inherit from the abstract base class class family.
- Subclasses should define its own data storage.
NSArray
Itself is only the cladding on the outside of other hidden object, it only defines the interface for all arrays are required to have. - Need to override the method specified in the superclass subclass should override the document. In each of the abstract base class, there are some methods Subclasses must override.
Article 10: Existing associated object class is used to store custom data
Related information stored in the object:
- Inherited from a subclass of the class the object belongs, and then modify the subclass object.
- By "associated objects" characteristic of an object related to a number of other objects that are distinguished by a "key."
The associated object method:
And a given key storage policy settings associated object is an object value
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
Parameter Description:
object
Source object associated with it.key
Associatedkey
. Typically use static global variables do key.value
Associated withkey
the corresponding value. Chuannil
can remove the existing association.policy
The associated storage strategy, which is corresponding to the memory management semantics, an enumeration.
objc_AssociationPolicy
Enumeration value as follows: | association type | @property equivalent properties | | --- | --- | OBJC_ASSOCIATION_ASSIGN | assign | OBJC_ASSOCIATION_RETAIN_NONATOMIC | nonatomic, retain | OBJC_ASSOCIATION_COPY_NONATOMIC | nonatomic, copy | OBJC_ASSOCIATION_RETAIN | retain | OBJC_ASSOCIATION_COPY | copy |
Gets an object corresponding to a value associated with an object from the given key.
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
Remove all objects associated with the specified object.
objc_removeAssociatedObjects(id _Nonnull object)
Note: only when other methods are not feasible before considering using it. If the abuse, would soon make the code out of control, making it difficult to debug.
Article 11: Understanding objc_msgSend
the role of
OC Method Invocation
Code:
id returnValue = [someObject messageName: paramter];
Code Description:
someObject
recipient.messageName
Select son.And selecting sub-parameters collectively referred to as "message"
Underlying C code implementation:
id returnValue = objc_msgSend(someObject, @selector(messageName:), paramter);
Messaging mechanism core function
Prototype code:
void objc_msgSend(id self, SEL cmd, ...)
This is a "function variable number of parameters", two or more acceptable parameters. Parameter Description:
self
recipient.cmd
Selectors (name of the method).- Those subsequent parameters Parameters Message, the sequence unchanged.
Implementation:
Note: The OC
method call requires many steps, more time-consuming. objc_msgSend
The results will match the cache in the "fast map", each class has such a cache. Although still not as good as "statically bound function call operator" so quickly, but not much slower.
Border situation:
objc_msgSend_stret
Return message to be sent to a structure , to thereby cross-function processing.objc_msgSend_fpret
Return message to be sent to a float , to thereby deposit processing function.objc_msgSendSuper
Superclass give a message, to thereby deposit processing function. Such[super message:parameter]
as: .
Tail call optimization
Objective-C
The method of each object can be seen as a simple C
function prototype is as follows:
<return_type> Class_selector(id self, SEL _cmd, ...)
The prototype and objc_msgSend
function much like to take advantage of " call optimization tail " technology. Order " Skip way to achieve " with this operation simpler.
Use: last operation of a function is call another function return value and will not be used for other purposes. Step: The compiler generates the instruction code modulation transferred to another desired function, people will not push a new "stack frame" to the call stack. Do not optimize consequences:
- Each call
Objective-C
before the method, you need to call theobjc_msgSend
function ready "stack frame", can be seen in the "stack trace" in. - "Stack overflow" phenomenon occurs prematurely.
Article 12: to understand the message forwarding mechanism
Message forwarding: The first stage: Dynamic Analytical Method: consult a recipient (belonging to the class), to see whether it can dynamically add a method to deal with this the "unknown selectors." The second stage: 1. backup receiver: Please recipient to see if there are no other objects (backup receivers) can handle this news. 2. The complete message forwarding mechanism: the runtime system and put all the details related messages are encapsulated into
NSInvocation
an object, to give the recipient last chance to make it to settle the current message has not been processed.
Dynamic method resolution
Whether a new example of a method for selecting sub-processing, call as follows:
// 实例方法
+ (BOOL)resolveInstanceMethod:(SEL)selector
// 类方法
+ (BOOL)resolveClassMethod:(SEL)selector
Use provided: a method for implementing the relevant code has been written, just like when running a dynamic insertion into the class.
Dynamic method of adding function is as follows:
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
Parameter Description:
cls
Add method of the classname
Method name to be addedimp
Function pointer to the method (C language) to be added.type
Method to be added "type code" .
Backup receiver
Are there other object processing this message, call as follows:
- (id)forwardingTargetForSelector:(SEL)selector
If the backup objects found, the method returns to backup objects, otherwise, returns nil
.
Note: We can not operate this step through the forwarded message.
The complete message forwarding mechanism
Creating NSInvocation
object that contains selectors , goals and parameters .
News dispatch call as follows:
- (void)forwardInvocation:(NSInvocation *)invocation
If it is found not a calling operation processing by the class, then looking up until NSObject
. If the last call NSObject
of the method, the method will continue to call doesNotRecognizeSelector:
to throw an exception, indicating selection of sub ultimately failed to be processed.
to sum up:
FIG full message forwarding process is as follows:
Recipients have the opportunity to handle the message at each step. The next step, the greater cost of processing messages.
Message forwarding Code: https://github.com/AlonerOwl/Runtime/tree/master/Runtime/MessageSend
Section 13: The "method of formulation (method swizzling) technology" debugging "black box approach"
Function pointer (IMP):id (*IMP)(id, SEL, ...)
Method Table: a set consisting of a function pointer.
The method of operation of the class table:
- New selectors
Article 12've said.BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
- A method of changing the corresponding selectors achieved
- Switching two selectors are mapped pointer, i.e. two exchange methods. Methods swap function:
Parameters: two methods to be exchanged to achieve acquisition method implemented functions:func method_exchangeImplementations(_ m1: Method, _ m2: Method)
Method class_getInstanceMethod(Class cls, SEL name)
这个方法可以为那些 “完全不知道具体实现” 的黑盒方法增加日志记录功能,这非常有助于程序调试。 若是滥用,反而会令代码变的不易读懂且难于维护。
method swizzling代码:https://github.com/AlonerOwl/Runtime/tree/master/Runtime/MethodSwizzling