The first day of admission to Objective-C Runtime at the ISA hospital and Class

The first day of admission to Objective-C Runtime at the ISA hospital and Class


The first time I began to pay attention to Objective-C Runtime is from November 1, 2014, @ Tang Qiao teacher in micro-blog issued a micro-blog started.

The first day of admission to Objective-C Runtime at the ISA hospital and Class

This is a sunnyxx online sharing. 4 questions were also given at the meeting.

The first day of admission to Objective-C Runtime at the ISA hospital and Class

These 4 questions to my knowledge, a lot of uncertainty, not allowed. From the entrance examination, the successful admission. Later, the understanding of the two years of Runtime gradually increased, and intend to sum up today, I have always been lying in my notes notes. Some people may have doubts, learning what is the use of Runtime in the end, usually does not seem to use. I hope to see this summary, the heart can solve some doubts.


  • 1.Runtime profile
  • 2.NSObject origin (1) the specific implementation of the isa_t structure () (class_data_bits_t) concrete implementation of cache_t (3)
  • 3 admission examination

I. Runtime profile

Runtime also known as run-time, is a set of the underlying C language API, is one of the core of the iOS system. Developers in the encoding process, can give an arbitrary object to send a message, at compile time just determined to send the message receiver, and the receiver will be how to respond to and deal with this message, then take a look at run time to decide.

C language, in the compilation period, the function of the call will decide which function to call.
and OC function, belonging to the dynamic call process, the compiler can not determine what the function of the real call, only in the real run will be based on the name of the function to find the corresponding function to call.

Objective-C is a dynamic language, which means that it needs not only a compiler, but also a run-time system to dynamically create classes and objects, message passing and forwarding.

Objc interacts with the Runtime system at three levels:

The first day of admission to Objective-C Runtime at the ISA hospital and Class
1 through the Objective-C source code

Only general developers write OC code, the Runtime system automatically behind the scenes we write the source code at compile time into the runtime code, determine the corresponding data structure and call specific methods at runtime.

2 the NSObject class defined by the Foundation framework

In the OC world, all classes are subclasses of NSObject except for the NSProxy class. In the Foundation framework, NSObject and NSProxy are two base classes that define the common interfaces and behaviors of all classes in the class hierarchy. NSProxy is dedicated to the realization of the proxy object class, this class is temporarily not mentioned in this article. These two classes follow the NSObject protocol. In the NSObject protocol, a common method for declaring all OC objects.

In the NSObject protocol, there are 5 methods that can be obtained from the Runtime information, so that the object for self-examination.

- (Class) class OBJC_SWIFT_UNAVAILABLE ("use'anObject.dynamicType'instead"); - (BOOL) isKindOfClass: (Class) - (BOOL) aClass; isMemberOfClass: (aClass; Class) - (BOOL) conformsToProtocol: (Protocol * aProtocol); - (BOOL) respondsToSelector: (SEL) aSelector;

The -class method returns an object of class
; -isKindOfClass: and -isMemberOfClass: method to check whether the object exists in the specified class inheritance system (whether subclass or superclass or the current class member variables);
-respondsToSelector: to check whether the specified message like response;
-conformsToProtocol: to check whether the object implements the methods specified protocol class;

A method is also defined in the NSObject class

(IMP) methodForSelector: (SEL) aSelector;

This method returns the address of the specified method implementation IMP.

These methods will be analyzed in detail in this article.

3 through the direct call to the Runtime library function

On the library function can be in Objective-C Runtime Reference view of the detailed documentation of the Runtime function.

On this point, in fact, there is a small episode. When we introduce objc/Runtime.h and objc/message.h two header files, then we find the Runtime function code is finished, found no code hints, those inside the function parameters and description are not. For developers familiar with Runtime, this is not difficult, because the parameters have long been remembered in the chest. But for the novice, it is rather unfriendly. Moreover, if it is from the beginning of the development of the iOS6 students, vaguely may be able to feel that the specific implementation of the official document on the Runtime less and less? May also doubt whether the illusion. In fact, from the beginning of Xcode5, apple does not recommend that we manually call Runtime API, but also hope that we do not know the underlying implementation. So the default IDE on behalf of a parameter, the prohibition of the Runtime code prompts, source code and documentation also deleted some of the explanations.

Specific settings are as follows:

The first day of admission to Objective-C Runtime at the ISA hospital and Class

If you find that after the introduction of the two library files, there is no hint of code, you need to change the settings here to NO, you can.

Two. Origin of NSObject

From the previous chapter, we know that there are 3 ways to interact with Runtime, the first two are related to NSObject, then we start from the NSObject base class.

The first day of admission to Objective-C Runtime at the ISA hospital and Class

The following source analysis from objc4-680

NSObject is defined as follows

Typedef struct *Class objc_class; @interface < NSObject> {Class isa OBJC_ISA_AVAILABILITY;}

Prior to Objc2.0, objc_class source code is as follows:

Struct objc_class {Class isa OBJC_ISA_AVAILABILITY; #if __OBJC2__ Class super_class OBJC2_UNAVAILABLE! Const char *name; OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; struct objc_method_list **methodLists OBJC2_UNAVAILABLE; struct objc_cache *cache OBJC2_UNAVAILABLE; struct objc_protocol_list *prot Ocols OBJC2_UNAVAILABLE; #endif} OBJC2_UNAVAILABLE;

Here you can see that in a class, there are pointers to super class, class name, version information.
Ivars is a pointer to the list of objc_ivar_list member variables; methodLists is a pointer to the objc_method_list pointer. *methodLists is a pointer to the list of methods. Here if the value of the dynamic modification of the *methodLists to add the member method, which is the principle of Category implementation, also explained the reason why Category can not add attributes.

About Category, recommended here 2 articles can be carefully studied.
depth understanding of Objective-C:Category
combined with Category working principle analysis of OC2.0 in runtime

Then after Apple released Objc 2 in 2006, the definition of objc_class became like this.

Typedef struct objc_class *Class; typedef struct objc_object *id; @interface Object {Class isa}; @interface NSObject < NSObject> isa OBJC_ISA_AVAILABILITY {Class} struct {private: objc_object; isa_t isa; objc_class: objc_object {struct} / / Class ISA; Class superclass; cache_t cache; cache pointer and VTable class_data_bits_t / / formerly / / class_rw_t * bits; plus custom rr/alloc flags union isa_t (isa_t) {} {} isa_t (uintptr_t value): bits (value) {} Class CLS; uintptr_t bits;}
The first day of admission to Objective-C Runtime at the ISA hospital and Class

The definition of the source into a class diagram, is the figure above.

From the above source code, we can see that the Objective-C object is the C language structure to achieve, in objc2.0, all objects will contain a isa_t type structure.

Objc_object is the source typedef into the ID type, which is the type of ID we usually encounter. This structure contains only one isa_t type structure. This structure will be analyzed in detail below.

Objc_class inherited from objc_object. So in objc_class will also contain isa_t type structure isa. At this point, it can be concluded that the class in Objective-C is also an object. In objc_class, in addition to ISA, there are 3 member variables, one is the parent class pointer, one is the method cache, the last instance of this class method list.

Object class and NSObject class which contains a objc_class type of isa.

The description of the left half of the graph is described, followed by isa.

When an instance method of an object is called, the corresponding class is found by ISA, and then the method is found in the class_data_bits_t of the class. Class_data_bits_t is a data region that points to a class object. Finding the corresponding implementation of the corresponding method in the data area.

But what are the ISA of a class object when we call a class method? Here in order to consistent mechanism and object lookup method, then introduces the concept of metaclass (meta-class).

A class can more detailed study of this article What is a meta-class in Objective-C?

In the introduction of metaclasses after mechanism object and object search method is completely unified.

When an instance method call of an object is passed, the method of obtaining the object in the class by the ISA of the object is realized. Call the
method of the object class, through the realization of class isa acquisition method in the class.

Meta-class is important because it stores all the methods of a class. Each class will have a separate meta-class, because the class method of each class can not be exactly the same.

The corresponding relationship between the figure below, this is a good description of the object, the relationship between the class:

The first day of admission to Objective-C Runtime at the ISA hospital and Class

The solid line is the super_class pointer, the dotted line is the ISA pointer.

  1. Root class (class) is actually a NSObject, NSObject is no superclass, so Root class (class) superclass pointing to nil.
  2. Each Class has a isa pointer pointing to the only Meta class
  3. Root class (meta) superclass points to Root class (class), that is, NSObject, forming a loop.
  4. Each Meta class isa pointer points to Root class (meta).

In fact, we should understand that the class object and the metaclass object is the only object, is can create numerous at run time. And before the implementation of the main method, from dyld to runtime during this period, the class object and the metaclass object is created in this period. Specific can see sunnyxx this iOS program main function before what happened

(1) the concrete realization of isa_t structure

Next, we study the specific realization of the isa. Objc_object inside ISA is isa_t type. By looking at the source code, we can see that isa_t is a union consortium.

Struct objc_object {private: isa_t isa; public: initIsa (should) be / used to init the ISA of new objects only. If object already has an / this isa, use changeIsa (for) correctness. (initInstanceIsa): objects / with no custom RR/AWZ void initIsa (Class CLS /*indexed=false*/); void initInstanceIsa (Class CLS, bool hasCxxDtor private: void (Class); initIsa newCls, bool indexed, bool hasCxxDtor);}

Then start with the initIsa method. Take arm64 as an example.

Inline void objc_object:: initInstanceIsa (Class CLS, bool hasCxxDtor) {initIsa (CLS, true, hasCxxDtor);} inline void objc_object:: initIsa (Class CLS, bool indexed, bool hasCxxDtor) {if (! Indexed) {isa.cls} {isa.bits = CLS; else = ISA_MAGIC_VALUE; isa.has_cxx_dtor = hasCxxDtor; isa.shiftcls = (uintptr_t CLS > > 3);}}

InitIsa second parameters into a true, so initIsa will execute the statement inside the else.

If __arm64__ define ISA_MASK 0x0000000ffffffff8ULL # # # define ISA_MAGIC_MASK 0x000003f000000001ULL define ISA_MAGIC_VALUE 0x000001a000000001ULL struct uintptr_t # {indexed: 1; uintptr_t: 1; has_assoc: 1; uintptr_t has_cxx_dtor uintptr_t shiftcls: 33; / / MACH_VM_MAX_ADDRESS 0x1000000000 uintptr_t magic uintptr_t: 6; weakly_referenced: 1; uintptr_t: 1; deallocating: 1; uintptr_t has_sidetable_rc uintptr_t extra_rc: 19 # define; RC_ONE (1ULL< < 45) # define RC_HALF (1ULL< < 18;}); elif __x86_64__ define ISA_MASK 0x00007ffffffffff8ULL # # # define ISA_MAGIC_MASK 0x001f800000000001ULL define ISA_MAGIC_VALUE 0x001d800000000001ULL struct uintptr_t # {indexed: 1; uintptr_t: 1; has_assoc: 1; uintptr_t has_cxx_dtor uintptr_t shiftcls: 44; / / MACH_VM_MAX_ADDRESS 0x7fffffe00000 uintptr_t magic uintptr_t: 6; weakly_referenced: 1; uintptr_t: 1; deallocating: 1; uintptr_t has_sidetable_rc uintptr_t extra_rc: 8; define # RC_ONE (1ULL< < 56) # define RC_HALF (1ULL< < 7)};
The first day of admission to Objective-C Runtime at the ISA hospital and Class

ISA_MAGIC_VALUE = 0x000001a000000001ULL is converted into binary 11010000000000000000000000000000000000001, the structure as shown below:

The first day of admission to Objective-C Runtime at the ISA hospital and Class

Description of parameters:

The first index, whether to open the ISA pointer optimization. Index = 1, representing open isa pointer optimization.

In September 2013, Apple launched the iPhone5s, at the same time, iPhone5s is equipped with a first using the 64 bit architecture of the A7 dual core processor, in order to save memory and improve the efficiency, Apple introduced the concept of Tagged Pointer. For the 64 bit program, the introduction of Tagged Pointer, the relevant logic can reduce the memory footprint, as well as 3 times the speed of access, the creation of 100 times, the destruction of speed.

In WWDC2013’s Session 404 Advanced Objective-C video, Apple introduced the Tagged Pointer in. Tagged Pointer exists mainly in order to save memory. We know that the object pointer size is generally associated with the machine word, in a 32 bit system, a pointer size is 32 bits (4 bytes), and in the 64 bit system, a pointer size is 64 bits (8 bytes).

Suppose we want to store a NSNumber object whose value is an integer. Under normal circumstances, if the integer is just a NSInteger of the ordinary variables, then it is occupied by the memory is related to the number of CPU, in the 32 bit CPU accounted for 4 bytes, in the case of the 64 bit CPU is accounted for by the. The size of the pointer type is usually associated with the CPU bit, a pointer to the memory occupied by the 32 bit CPU for the next 4 bytes, in the 64 bit CPU is also a byte of 8. If there is no Tagged Pointer object, from the 32 machine to the 64 bit machine, although there is no change in the logic, but this kind of NSNumber, NSDate objects such as the amount of memory will be doubled. As shown in the following figure:

The first day of admission to Objective-C Runtime at the ISA hospital and Class

Apple raised the Tagged Pointer object. Because NSNumber, NSDate type of variable value itself needs memory size to 8 bytes often take integer, 4 bytes represent unsigned integer can reach about 2000000000 (Note: 2^31=2147483648, the other 1 as the sign bit), can be dealt with for the vast majority of cases. So, after the introduction of the Tagged Pointer object, 64 bit CPU under the NSNumber memory map becomes the following:

The first day of admission to Objective-C Runtime at the ISA hospital and Class

About Tagged Pointer technology in detail, you can see the link above that article.

The has_assoc
object contains or has ever been associated with an associated reference, which can be freed more quickly without the associated reference

indicates whether the object has a C++ or Objc destructor

class pointer. There are 33 bits in the arm64 architecture that can store pointers.

The source code of isa.shiftcls (uintptr_t) = CLS > >
3; the main reason is the current address right three bits for the Class pointer in useless after the three removal reduces memory consumption, because the pointer to the byte aligned memory (8 bits), which refers to the needle after three are not the significance of the 0. Specific can be seen from the initial understanding of ISA NSObject this article inside the shiftcls analysis.

to determine whether the object is initialized to complete, in the arm64 0x16 debugger is to determine whether the current object is a real object or not initialized space.

The weakly_referenced
object is pointed to or has been pointed to a weak variable of ARC, and the object without a weak reference can be released more quickly

object is freeing memory

to determine whether the object’s reference count is too large, if it is too large will need other hash table to store.

The results of the extra_rc
store the reference value of the object after a reduction. The reference count of the object is more than 1, and there will be this. If the reference count is 10, the value of extra_rc is about 9.

ISA_MAGIC_MASK and ISA_MASK are obtained by way of the mask MAGIC value and ISA pointer.

Inline Class objc_object:: (ISA) {assert ((isTaggedPointer)); return (Class) (isa.bits & ISA_MASK);}

On the x86_64 architecture, the specific can look at the initial understanding of the article from the ISA NSObject detailed analysis.

(2) the concrete realization of cache_t

Continue to look at the source

Struct cache_t struct bucket_t mask_t {*_buckets; _mask; mask_t _occupied; typedef unsigned int} uint32_t; typedef uint32_t mask_t; arm64 ASM / / x86_64 & are less efficient with 16-bits typedef unsigned long uintptr_t; typedef uintptr_t cache_key_t; struct bucket_t cache_key_t IMP _imp {private: _key;};
The first day of admission to Objective-C Runtime at the ISA hospital and Class

According to the source code, we can know that the cache_t is stored in a bucket_t structure, and two unsigned int variables.

Mask: allocated to cache the total number of bucket.
occupied: indicates the number of currently used cache bucket.

The bucket_t structure is stored in a unsigned long and a IMP. IMP is a function pointer that points to a specific implementation of a method.

Cache_t bucket_t *_buckets is actually a Hash list, used to store the Method list.

The main function of Cache is to optimize the performance of the method call. When the message object receiver method call, according to the receiver isa object pointer to find its corresponding class, then search in the methodLists method, if not found, use the super_class pointer to the parent class in the methodLists search, once found to call a method. If it is not found, it is possible to forward the message, or it may be ignored. But this way to find the efficiency is too low, because often only 20% of a class method is often called, accounting for the total number of calls of 80%. Therefore, the use of Cache to cache the method often call, when the call method, the priority in the Cache search, if not found, then to the methodLists search.

(3) the concrete realization of class_data_bits_t

The source code is as follows:

Struct class_data_bits_t are the FAST_ {/ / Values flags above. uintptr_t bits struct class_rw_t;} {uint32_t flags; uint32_t version; const class_ro_t *ro; method_array_t methods; property_array_t properties; protocol_array_t protocols; Class firstSubclass; Class nextSiblingClass; char *demangledName;} struct {uint32_t class_ro_t flags; uint32_t instanceStart; uint32_t instanceSize #ifdef; __LP64__ uint32_t reserved; #endif const uint8_t * const char * ivarLayout; name; method_list_t * baseMethodList; protocol_list_t * baseProtocols; const ivar_list_t const uint8_t * weakIvarLayout * Ivars; property_list_t; *baseProperties; method_lis T_t *baseMethods () const {return baseMethodList}}};
The first day of admission to Objective-C Runtime at the ISA hospital and Class

Notes in the objc_class structure are written to class_data_bits_t equivalent to the class_rw_t pointer plus the rr/alloc flag.

Class_data_bits_t bits; class_rw_t plus custom rr/alloc flags * /

It provides us with a convenient way to return the class_rw_t * pointer:

Class_rw_t *data () {return ();}

The properties, methods, and protocols of the Objc class are placed in class_rw_t after the obj 2 version. Class_ro_t is a pointer to a constant that stores the attributes, methods, and protocols that the compiler determines. Rw-readwrite, ro-readonly

The class_data_bits_t *data in the structure of the compiler class is directed to a class_ro_t * pointer:

The first day of admission to Objective-C Runtime at the ISA hospital and Class

Call the realizeClass method at run time and do the following 3 things:

  1. Call the data method from class_data_bits_t and force the results from class_rw_t to class_ro_t
  2. Initialize a class_rw_t structure
  3. Set the value of the structure RO and flag

Finally call the methodizeClass method, the class attributes, protocols, methods are loaded.

Struct method_t SEL const char {name; *types; IMP imp; struct SortBySELAddress: public std:: binary_function< const method_t& const, method_t& bool>, bool; operator (const) {(method_t& LHS, const method_t& amp; RHS) {return <;}}};

Method method is defined as above. Which contains 3 member variables. SEL is the name of the method name. Types Type Encoding is a type of encoding, type can refer to Type Encoding, this is not elaborate.

IMP is a function pointer, pointing to the specific implementation of the function. The purpose of message passing and forwarding in runtime is to find the IMP and execute the function.

The entire runtime can be described as follows:

The first day of admission to Objective-C Runtime at the ISA hospital and Class

For more detailed analysis, see @Draveness’s article in-depth analysis of the structure of the ObjC method

To this end, sum up the differences between objc_class 1 and 2.

The first day of admission to Objective-C Runtime at the ISA hospital and Class
The first day of admission to Objective-C Runtime at the ISA hospital and Class

Three. Admission examination

The first day of admission to Objective-C Runtime at the ISA hospital and Class

(a) [self class] and [super class]

The following code output what? @implementation: Father – Son (ID init) {self = [super init]; if (self) {NSLog (“% @ @” NSStringFromClass ([self, class])); NSLog (@ “% @”, NSStringFromClass ([super class]));} return self;} @end

The difference between self and super:

Self is a hidden parameter of the class, and the first parameter of each method is self.

Super is not a hidden parameter, it is really just a “compiler identifier”, which is responsible for telling the compiler that when the method is called, call the parent method, rather than the method in this class.

When calling [super class], runtime calls the objc_msgSendSuper method instead of objc_msgSend

OBJC_EXPORT void objc_msgSendSuper (void struct objc_super *super SEL op / *, * / / / / Specifies the,...) superclass of an instance. struct objc_super Specifies an instance of {/ / / a class. __unsafe_unretained ID receiver Specifies the particular superclass; / / / of the instance to message. #if! Defined (__cplusplus) & & __OBJC2__ For compatibility with old / *! Objc-runtime.h header / __unsafe_unretained Class class; #else __unsafe_unretained Class super_class; #endif is the first class / * super_class to search * /};

In the objc_msgSendSuper method, the first argument is a objc_super structure, this structure has two variables, one is to receive the message receiver, one is the current class of the parent class super_class.

The first reason for the entrance examination error here, mistakenly believe that [super class] is called [super_class class].

The working principle of objc_msgSendSuper should be like this: a list of methods superClass parent class
from the objc_super structure to the selector to start the search, found by objc-> receiver to call the parent class of this selector. Note that the last caller is objc-> receiver, not super_class!

So objc_msgSendSuper finally turned into

Note here is / / from the parent class to msgSend, rather than from the start, thanks to @Josscii and his colleagues point out is described here. Objc_msgSend (objc_super-> receiver, @selector (class)) + (Class) class {return self;}

Due to the class found in the parent class NSObject method IMP, and because of the incoming objc_super-> receiver = self. Self is son, call class, so the parent class method class after the implementation of IMP, the output is still son, the final output of the two are the same, are the output son.

(two) isKindOfClass and isMemberOfClass

What does the following code output? @interface Sark: NSObject @end @implementation Sark @end int main (int argc, const char * argv[]) {@autoreleasepool {BOOL = res1 [(ID) [NSObject class] isKindOfClass:[NSObject class]]; BOOL res2 = [(ID) [NSObject class] isMemberOfClass:[NSObject class]]; BOOL res3 = [(ID) [Sark class] isKindOfClass:[Sark class]]; BOOL res4 = [(ID [Sark class] isMemberOfClass:[Sark class]]); NSLog (“%d%d%d @%d, res1, res2, res3, res4);} return 0;}

First to analyze the source of these two functions of the object to achieve

(Class) + class {return self;} - (Class) class object_getClass (self) {return}; Class object_getClass (ID obj) {if (obj) return obj-> (else); getIsa; return Nil;} inline Class objc_object: (getIsa) {if (isTaggedPointer) (slot = uintptr_t) {((uintptr_t) this > > & TAG_SLOT_MASK; TAG_SLOT_SHIFT) return objc_tag_classes[slot] return (ISA);}}; inline Class (objc_object:: ISA) {assert (isTaggedPointer!) (return) (Class) (isa.bits; & ISA_MASK;}) + (BOOL) isKindOfClass: (Class) {for CLS (Class TCLs = object_getClass (self (ID)); TCLs; TCLs = tcls-> superclass) {if (TCLs = = CLS) return YES return NO;};} - (BOOL) isKindOfClass: (Class) {for (CLS Class TCLs = [self class]; TCLs; TCLs = tcls-> superclass) {if (TCLs = = CLS) return YES return NO;};} + (BOOL) isMemberOfClass: (Class) CLS (object_getClass (ID) {return self = = CLS);} - (BOOL) isMemberOfClass: (Class) CLS {return [self class] = = CLS;}

First of all, NSObject and Sark are called by the class method.

(BOOL) + isKindOfClass: (Class) CLS method, will go to the object_getClass class, and the object_getClass source code to achieve is to call the class obj-> (getIsa), at ISA (meta) to obtain a pointer in class method.

Then there is a cycle in the isKindOfClass, the first to determine whether class is equal to meta class, ranging from continuing to determine whether the loop is equal to super class, ranging from continuing to take super class, so the cycle.

After executing the class] [NSObject call isKindOfClass, first determine NSObject and NSObject first to determine whether class is equal to meta, when meta talked about before class put a very detailed map, from the picture, we can see that the NSObject meta class itself and ranging. Then the second cycle determines whether NSObject is equal to the class of meta superclass. From the above chart we can see: Root class (meta) superclass is Root class (class), which is the NSObject itself. So the second cycle is equal, so the first line of res1 output should be YES.

Similarly, after the [Sark class] executes the first call to isKindOfClass, Meta Class and [Sark for cycle, ranging from class] Sark, second for Sark Meta Class super, class NSObject Meta refers to Class, Sark and Class are not equal. The third for loop, NSObject Meta super class is pointing to NSObject Class, and Sark Class is not equal. For the fourth cycle, the Class super of NSObject class points to nil, and Sark Class is not equal. After fourth cycles, exit the loop, so the output of the third line is NO res3.

If you change the Sark into its instance object, [sark isKindOfClass:[Sark class], then you should output YES. Because in the isKindOfClass function, the meta judge Sark class is their first for cycle Sark class, can output YES.

IsMemberOfClass source code is to get their own isa pointers and their comparison, whether equal.
second line isa points to the NSObject Class of Meta, so it is not equal to NSObject Class. The fourth line, ISA points to the Sark Class Meta, and Sark Class are also different, so the res2 and the second row res4 output NO.

(three) Class and memory address

Which of the following code? Compile Error / Runtime Crash / NSLog… @interface? Sark: NSObject @property (nonatomic, copy) – (void) NSString *name; speak @end; @implementation Sark (void speak) {NSLog (“my name’s @% @”,;} @end @implementation ViewController (void) viewDidLoad [super ID CLS {viewDidLoad]; [Sark = class]; void = &amp *obj; CLS; [(__bridge ID) obj speak] @end;}

There are two difficulties in this problem. One difficulty, obj call speak method, in the end will not crash. Difficulty two, if the speak method does not crash, what should output?

First, we need to talk about the hidden parameters self and _cmd.
message] when the [receiver method is called, the system will run in secretly dynamic incoming two hidden parameters self and _cmd, they are “hidden parameters, because there is no declaration and definition of the two parameters in the source code. Self has been explained in the above, and then talk about _cmd. _cmd represents the current call method, in fact it is a method selector SEL.

One difficulty, can call the speak method?

ID CLS = [Sark class]; void = & CLS; *obj;

The answer is yes. Obj was converted to a pointer to the Sark Class, and then converted to objc_object type using ID. Obj is now an instance of the Sark type. Of course, then you can call the speak method.

Difficult two, if you can call speak, what will be exported?

A lot of people may think that they will output Sark related information. So the answer is wrong.

The correct answer will output

My name is < ViewController: 0x7ff6d9f31c50>

The memory address is different every time, but it must be ViewController. Why?

We change the code and print more information.

- (void) viewDidLoad NSLog ({[super viewDidLoad]; @ ViewController =% @, address =%p, self, & self); ID CLS = [Sark class]; NSLog ("Sark class = @% @ address =%p, CLS, & CLS); void *obj = NSLog (& CLS;" Void @ *obj =% @ address =%p, obj, & obj); [(__bridge ID) obj speak]; Sark *sark = [[Sark alloc]init]; NSLog ("Sark instance = @% @ address =%p, Sark, & Sark); [sark speak];}

We print out the address of the object. Output results:

ViewController = < ViewController: = 0x7fb570e2ad00> class = Sark 0x7fff543f5aa8 address, Sark address = 0x7fff543f5a88 Void *obj = < Sark: = 0x7fff543f5a88> 0x7fff543f5a80 my name is < address; ViewController: 0x7fb570e2ad00> Sark instance = < Sark: = 0x7fb570d20b10> 0x7fff543f5a78 my name is address (null)
The first day of admission to Objective-C Runtime at the ISA hospital and Class
Objc_msgSendSuper2 (takes) the current / search class, not its superclass. OBJC_EXPORT ID objc_msgSendSuper2 (struct objc_super *super SEL, Op,...) __OSX_AVAILABLE_STARTING (__MAC_10_6, __IPHONE_2_0);

The objc_msgSendSuper2 method is a objc_super *super.

Specifies the superclass of an / / / instance. struct objc_super Specifies an instance of {/ / / a class. __unsafe_unretained ID receiver Specifies the particular superclass; / / / of the instance to message. #if! Defined (__cplusplus) & & __OBJC2__ For compatibility with old! / objc-runtime.h header / __unsafe_unretained Class class; #else __unsafe_unretained Class super_class #endif super_class is; / * the first class to search * /}; #endif

So according to the viewDidLoad implementation of the various variables into the stack order from high to self, _cmd, self.class, self, obj.

The first self and second _cmd are hidden parameters. Third self.class and fourth self are the parameters of the [super viewDidLoad] method when executed.

In the call to, the self pointer is essentially a pointer to the high address offset in memory. Below the 32 bit, a pointer is a 4 byte =4*8bit=32bit.

From the print results we can see that obj is the CLS address. Up to 32bit in obj to 0x7fff543f5aa8, this is exactly the ViewController address.

So the output is my name < ViewController: 0x7fb570e2ad00> is;.

So far, what is the object in the Objc?

Substance: the object in Objc is a variable that points to the ClassObject address, i.e. ID obj = & ClassObject, while the object instance variable void = & obj + offset (N)

To deepen the understanding of the above sentence, the following code will output what?

- (void) viewDidLoad NSLog ({[super viewDidLoad]; @ ViewController =% @, address =%p, self, & self); NSString *myName = @ "halfrost"; ID CLS = [Sark class]; NSLog ("Sark class = @% @ address =%p, CLS, & CLS; void) *obj = & CLS; NSLog (" Void *obj = @% @ address =%p, obj, & obj); [(__bridge ID) obj speak]; Sark *sark = [[Sark alloc]init]; NSLog ("Sark instance = @% @ address =%p, Sark, & Sark); [sark speak];}
ViewController = < ViewController: = 0x7fff44404ab0> class = Sark 0x7fff56a48a78 address, Sark address = 0x7fff56a48a50 Void = *obj < Sark: 0x7fff56a48a50> 0x7fff56a48a48 my name is halfrost address = Sark instance = < Sark: 0x6080000233e0 > my name is = 0x7fff56a48a40 address (null)

As a result of the addition of a string, the output will be completely changed, [(__bridge ID) speak] obj; this sentence will output “my name is”

The reason is similar to the above. Press viewDidLoad to execute each variable into the stack order from high to self, _cmd, self.class, self, myName, obj. Obj upward offset 32, is the myName string, so the output becomes the output of the myName.


Admission exam because there is no answer to the question, so the hospital decided to let me stay in hospital for one day observation.

To be continued, please exhibitions.