The nature of OC objects

#import <Foundation/Foundation.h> #import <objc/runtime.h> @interface LGPerson : NSObject @property (nonatomic, strong) NSString *KCName; @end @implementation LGPerson @end int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!" ); } return 0; }Copy the code

Here we aremain.mDefine one in the fileLGPersonClass, and then open the terminal,cdmain.mFile directory, and then enterclang -rewrite-objc main.m -o main.cppCommand, and you will see that one is generatedmain.cppFile.

Open themain.cppThe file we can see is only a few lines of codemain.mFile, when you generate a c++ file, you’re going to have a bunch of lines of code, and this is just a drag and once you do that you’re going to have over 10,000 lines of code. We go straight to the global searchLGPerson

You can see the LGPerson class here, and the getter and setter methods for the KCName property. You can see here that objects are essentially structures.

In addition to hereKCNameThere is one more propertyNSObject_IVARSProperty, this is actuallyisa. Inherits from the structureNSObject_IMPL, here is pseudo inheritance. Global searchNSObject_IMPL And you can see that it isisa.


We all know that at the OC level, objects ultimately inherit from NSObjec, but here it’s objc_Object, because at the real lower level, objC’s implementation is objC_Object.


static NSString * _I_LGPerson_KCName(LGPerson * self, SEL _cmd) { 
    return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)); 
}
static void _I_LGPerson_setKCName_(LGPerson * self, SEL _cmd, NSString *KCName) {
 (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_KCName)) = KCName;
 }
Copy the code

If we look at the getter method, we’ll see that there are LGPerson * self, SEL _cmd arguments, but we don’t have them when we write the getter method, they’re actually hidden arguments for the OC method. KCName = KCName = KCName = KCName = KCName = KCName = KCName = KCName = KCName = KCName = KCName Setter methods are assigned the same way.


Clang is a lightweight compiler for C, C++, and Objective-C. Source code is published under the BSD protocol. Clang will support its normal lambda expressions, simplified handling of return types, and better handling of constEXPr keywords. Clang is an Apple-led, LLVM-based C/C++/Objective-C compiler. In April 2013,Clang fully supported the C++11 standard and began implementing C++ 1Y features (i.e. C++14, the next minor update to C++). Clang will support its normal lambda expressions, simplified handling of return types, and better handling of constEXPr keywords. [2] Clang is a C/C++/Objective-C/ Objective-C++ compiler written in C++, based on LLVM and published under the LLVM BSD license. It is almost completely compatible with the GNU C language specification (although there are some incompatibables, including some differences in compiler command options) and adds additional syntactical features such as C function overloading (which modifies functions by __attribute__((overloadable)), One of its goals is to go beyond GCC.


Combination field

  1. Case 1

Here we define a structure LGCar1 that represents the direction of the car. It has four directions and requires a total of four bytes, or 32 bits. But actually each direction can be represented by a 1 and a 0, so you only need 4 bits, but a byte is 8 bits, so you need 1 byte of space. There’s going to be 3 bytes wasted. So how do you optimize? There’s a bit-field approach.

  1. Case 2

As you can see, the bit-field approach takes up only one byte (in fact, only four bits are used, 0000 1111). Greatly optimized memory.



3. Case 3

By printing, we can see that teacher2 can only have a value for one property at a time compared to Teacher1, due to the mutually exclusive nature of unions.

A union is a kind of data structure similar to a struct to some extent. A union and a struct can also contain a variety of data types and variables.

However, the difference is also quite obvious: all variables in a struct “coexist” — the advantage is “large”, comprehensive; The disadvantage is that the allocation of struct memory space is extensive, regardless of use, full allocation. In a union, variables are mutually exclusive — the disadvantage is that they are not “inclusive” enough. But the advantage is that memory usage is more delicate and flexible, and also saves memory space.


isa

As we talked about in iOS Object Explorer 1, when we get to this point we’re going to bind the heap memory request structure pointer to the Class Class. So how is ISA implemented? Let’s go into the code here.

In objc_object::initIsa(Class CLS, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor) method we can see isa_t, here let’s look at isa_t again.

You can see here that ISA_t is essentially a union. Here you can see the constructor for ISA_t, along with the bits, CLS attribute.

We all know that the pointer type is 8 bytes, but on a 64-bit system it’s 8 * 8 64 bytes. If 64-bit all just store a pointer, there would be a waste of space, and basically every class basically has ISA, so can this be optimized? So Apple stores everything related to classes in 64 bits, such as reference counts, whether they are being released, weak, associated objects, destructors, etc. So there’s the concept of nonPointerIsa. Is it stored in this way? Let’s take a look inside ISA_BITFIELD.

0: pure ISA pointer, 1: isa contains not only the address of the class object, but also the reference count of the object. // Has_ASsoc associated object flag, 0: none, 1: Has_cxx_dtor specifies whether the object has a destructor for C++ or Objc. If it does, the destructor logic needs to be done. If it does not, the object can be freed faster. // Shiftcls stores the value of the class pointer. With pointer optimization turned on, 33 bits are used to store class Pointers in the ARM64 architecture. // magic: Used by the debugger to determine whether the current object is a real object or has no space to initialize. // Weakly_referenced Indicates whether an object is pointed to or has been pointed to an ARC weak variable. Objects without weak references can be released faster. // deallocating: Indicates whether the object is freeing memory. // unused: indicates whether a hash is being used. // has_sideTable_rc: when the object reference count is greater than 10, it needs to be borrowed to store the carry. When representing the reference count value of this object, the reference count value is actually reduced by 1. For example, if the object's reference count is 10, extra_rc is 9. If the reference count is greater than 10, the following has_sideTABLE_rc is used.Copy the code

Here we can see the stored information of the union under ARM64 bits, and the meaning of the stored values under the associated bit fields.