super
In Objective-C, if we need to call a parent method in a class method, we usually use super as follows:
@interface MyViewController: UIViewController
@end
@implementation MyViewController
-(void) viewDidLoad {
[super viewDidLoad];
// do something
...
}
@end
We all know how to use super. The question is, how does it work?
The first thing we need to know is that super is different from self. self is a hidden parameter of the class, and the first parameter of each method implementation is self. Super is not a hidden parameter. It is actually just a "compiler identifier". It is responsible for telling the compiler to call the method of the parent class instead of the method in this class when calling the viewDidLoad method. And it actually points to the same message receiver as self. To understand this, let's first look at the definition of super:
struct objc_super {id receiver; Class superClass;};
This structure has two members:
receiver: the actual receiver of the message
superClass: pointer to the parent class of the current class
When we use super to receive messages, the compiler generates an objc_super structure. In the above example, the receiver of this structure is the MyViewController object, which is the same as self; superClass points to UIViewController, the parent class of MyViewController.
Next, when sending a message, instead of calling the objc_msgSend function, call the objc_msgSendSuper function, which is declared as follows:
id objc_msgSendSuper (struct objc_super * super, SEL op, ...);
The first parameter of the function is the objc_super structure generated earlier, and the second parameter is the selector of the method. The actual operation of this function is: from the list of methods of the superClass pointed to by the objc_super structure, search for the selector of viewDidLoad, and then call this selector with objc-> receiver.
objc_msgSend (objc_super-> receiver, @selector (viewDidLoad))
Since objc_super-> receiver is self itself, this method is actually the same as this call:
objc_msgSend (self, @selector (viewDidLoad))
To facilitate understanding, we look at the following examples:
@interface MyClass: NSObject
@end
@implementation MyClass
-(void) test {
NSLog (@ "self class:% @", self.class);
NSLog (@ "super class:% @", super.class);
}
@end
After calling the test method of MyClass, the output is:
2014-11-08 15: 55: 03.256 [824: 209297] self class: MyClass
2014-11-08 15: 55: 03.256 [824: 209297] super class: MyClass
As you can see from the above example, the output of both is MyClass. You can use the content introduced above to sort it out yourself.
Library-related operations
Library-related operations are mainly used to obtain library-related information provided by the system, and mainly include the following functions:
// Get the names of all loaded Objective-C frameworks and dynamic libraries
const char ** objc_copyImageNames (unsigned int * outCount);
// Get the dynamic library where the specified class is located
const char * class_getImageName (Class cls);
// Get the class names of all classes in the specified library or framework
const char ** objc_copyClassNamesForImage (const char * image, unsigned int * outCount);
Through these functions, we can understand all the libraries of a certain class, and which classes are contained in a certain library. As shown in the following code:
1
2
3
4
5
6
7
8
9
NSLog (@ "Get the dynamic library where the specified class is located");
NSLog (@ "UIView ‘s Framework:% s", class_getImageName (NSClassFromString (@ "UIView")));
NSLog (@ "Get the class name of all classes in the specified library or framework");
const char ** classes = objc_copyClassNamesForImage (class_getImageName (NSClassFromString (@ "UIView")), & outCount);
for (int i = 0; i <outCount; i ++) {
NSLog (@ "class name:% s", classes [i]);
}
The output is as follows:
2014-11-08 12: 57: 32.689 [747: 184013] Get the dynamic library where the specified class is located
2014-11-08 12: 57: 32.690 [747: 184013] UIView ‘s Framework: /System/Library/Frameworks/UIKit.framework/UIKit
2014-11-08 12: 57: 32.690 [747: 184013] Get the class names of all classes in the specified library or framework
2014-11-08 12: 57: 32.691 [747: 184013] class name: UIKeyboardPredictiveSettings
2014-11-08 12: 57: 32.691 [747: 184013] class name: _UIPickerViewTopFrame
2014-11-08 12: 57: 32.691 [747: 184013] class name: _UIOnePartImageView
2014-11-08 12: 57: 32.692 [747: 184013] class name: _UIPickerViewSelectionBar
2014-11-08 12: 57: 32.692 [747: 184013] class name: _UIPickerWheelView
2014-11-08 12: 57: 32.692 [747: 184013] class name: _UIPickerViewTestParameters
...
Block operation
We all know that blocks bring us great convenience, and Apple continues to provide new APIs that use blocks. At the same time, Apple also provides some functions in runtime to support block-oriented operations. These functions include:
// Create a pointer to a pointer function, this function will call a specific block
IMP imp_implementationWithBlock (id block);
// return the block related to IMP (created with imp_implementationWithBlock)
id imp_getBlock (IMP anImp);
// Disassociate the block from the IMP (created using imp_implementationWithBlock) and release the copy of the block
BOOL imp_removeBlock (IMP anImp);
● imp_implementationWithBlock function: The signature of the parameter block must be of the form method_return_type ^ (id self, method_args…). This method allows us to use blocks as IMPs. As shown in the following code:
@interface MyRuntimeBlock: NSObject
@end
@implementation MyRuntimeBlock
@end
// test code
1
2
3
4
5
6
7
8
IMP imp = imp_implementationWithBlock (^ (id obj, NSString * str) {
NSLog (@ "% @", str);
});
class_addMethod (MyRuntimeBlock.class, @selector (testBlock :), imp, "[email protected]: @");
MyRuntimeBlock * runtime = [[MyRuntimeBlock alloc] init];
[runtime performSelector: @selector (testBlock :) withObject: @ "hello world!"];
The output is
2014-11-09 14: 03: 19.779 [1172: 395446] hello world!
Weak reference operation
// Load the object referenced by the weak reference pointer and return
id objc_loadWeak (id * location);
// Store the new value of the __weak variable
id objc_storeWeak (id * location, id obj);
● objc_loadWeak function: This function loads an object referenced by a weak pointer and returns it after performing retain and autoreleasing operations on it. This way, the object can maintain a long enough life cycle when the caller uses it. This function is typically used in any expression that uses the __weak variable.
● objc_storeWeak function: This function is typically used when the __weak variable is used as an assignment object.
The specific implementation of these two functions is not an example here. Interested partners can refer to the introduction of __weak implementation in Objective-C Advanced Programming: iOS and OS X Multithreading and Memory Management.
Macro definition
In runtime, we also define some macro definitions for our use. Some values we will often use, such as YES / NO for BOOL values, and some values are not commonly used, such as OBJC_ROOT_CLASS. Here we make a brief introduction.
Boolean value
#define YES (BOOL) 1
#define NO (BOOL) 0
These two macro definitions define constants representing Boolean values. It should be noted that the value of YES is 1, not the value of non-0.
Null value
#define nil __DARWIN_NULL
#define Nil __DARWIN_NULL
Where nil is used for empty instance objects and Nil is used for empty class objects.
Distribution function prototype
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
This macro indicates whether the dispatch function must be converted to the appropriate function pointer type. When the value is 0, conversion must be performed
Objective-C root class
#define OBJC_ROOT_CLASS
If we define an Objective-C root class, the compiler will report an error indicating that the class we defined does not specify a base class. In this case, we can use this macro definition to avoid this compilation error. This macro is available after iOS 7.0.
In fact, in the declaration of NSObject, we can see the figure of this macro as follows:
__OSX_AVAILABLE_STARTING (__ MAC_10_0, __IPHONE_2_0)
OBJC_ROOT_CLASS
OBJC_EXPORT
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
We can refer to this way to define our own root class.
Local variable storage duration
#define NS_VALID_UNTIL_END_OF_SCOPE
This macro indicates that the values stored in some local variables should not be freed by the compiler during optimization.
We mark local variables as type ids or pointers to ObjC object types, so that the values stored in these local variables are not forced to be released by the compiler during optimization. Instead, these values are stored until the variable is assigned again or until the scope of the local variable ends.
Associated Object Behavior
enum {
OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403
};
These values have been introduced previously and will not be repeated here.
to sum up
At this point, the finishing of the runtime in this series is over. Of course, this is just an induction of some basic knowledge of runtime, trying to play a role in attracting a lot of attention. There are many interesting things about runtime that the reader needs to explore by himself.
Objective-C Runtime Runtime 6: Findings