We have explored the properties, member variables, class methods and object method storage locations of classes. We have roughly understood some principles of classes. So this article we go to explore the relationship between attributes, member variables and instance variables. How does the system assign values to attributes?
Relationships between attributes and member variables
Property = member variable + setter + getter
- For example: @property(nonatomic,copy) NSString *name; The property here
name
Is equal to_name
(Member variable)+-(void)setName:(NSString *)name
+-(NSString *)name
.
2. The member variable system does not actively generate setter and getter methods for us.
Instance variables are member variables, such as NSObject *_obj, where _obj is the instance variable, and instance variables are member variables other than the basic data types.
The relationship between attributes, member variables and instance variables is summarized as follows:
Attributes of a class
1. In this section we’ll explore storing and valuing attributes of a class. We’ll create a class named KGPerson that inherits from NSObject and declare some member variables and attributes as follows:
Kgperson. m file (clang-rewrite-objc kgPerson. m -o kgPerson. CPP);
Extern “C” unsigned long OBJC_IVAR_$_KGPerson$_ property name; extern “C” unsigned long OBJC_IVAR_$_KGPerson$_ property name This code, when used extern with “C”, tells the compiler to look for the declaration in another file when using the OBJC_IVAR_$_KGPerson$_ attribute name, because when we use variables in a function, we must ensure that the variable is already declared and not externally accessible in the header file. So extern can be used from the declaration to the end of the file.
Setters and getters for class properties
5. We can see that there are both setters and getters for properties in pairs, but there is a detail, which is also an NSString property, but some of them use displacement to assign values, and some of them use objc_setProperty to assign values, so this is a problem. When does this happen? What factors affect it? Let’s modify the KGPerson class as follows:
6. Then we compile the.cpp file from clang.
7. From the above, we can basically draw the following conclusions:
Atomicity or not | The modifier | The results of |
---|---|---|
nonatomic | strong | Translation memory |
nonatomic | copy | objc_setProperty |
nonatomic | retain | objc_setProperty |
nonatomic | readonly | Translation memory |
nonatomic | readwrite | Translation memory |
nonatomic | assign | Translation memory |
atomic | strong | Translation memory |
atomic | copy | objc_setProperty |
atomic | retain | objc_setProperty |
atomic | readonly | Translation memory |
atomic | readwrite | Translation memory |
atomic | assign | Translation memory |
8. Then we look in the LLVM source code, we can find the following code:
LLVM ::FunctionCallee getSetPropertyFn() = LLVM ::FunctionCallee getSetPropertyFn() = LLVM ::FunctionCallee getSetPropertyFn()
10. Then we continue to find where the GetPropertySetFunction function is called, and finally we find the following code:
11. Then this code is mainly judged by the case branch, and we focus on the PropertyImplStrategy because it is all conditional judged around it. After searching, we can see the following definition:
12. In the code above, the system explicitly states that if we use copy, we must use getProperty/setProperty. So here we once again prove the content of the table sorted out above, and the exploration of attributes also ends here.
Extended-coding
We can see the following types of code in the compiled kgPerson. CPP file, which looks familiar, but some are not familiar:
{{(struct objc_selector *)”sayHello”, “v16@0:8”, (void *)_I_KGPerson_sayHello} We can see that the first part is the method, but the following v16@0:8 stands for what? Here’s a picture to illustrate:
3, we can find the corresponding interpretation of what this symbol represents in the type encoding.
Attribute assignment
1. As we all know, there are many ways to assign values to attributes, as shown in the following figure:
2. Then let’s see how the system does the assignment. Clang-rewrite-objc main.m -o main. CPP convert main.m to main. CPP
3. We can see this in the main. CPP file. Either using person.name = @”KG” or [person setHomeTown:@”China”] or [person setValue:@”🌰 🌰 🌰 🌰 port 🌰” ForKey :@”nikeName”] to assign a value to a class attribute or member variable, the system will compile objc_msgSend(person, sel_registerName(“setName:”), @”KG”). The message is sent through objc_msgSend.
Sel_registerName = sel_registerName = sel_registerName = sel_registerName = sel_registerName = sel_registerName = sel_registerName
Sel_registerName (const char *name) {return __sel_registerName(name, 1, 1); return __sel_registerName(name, 1, 1); }Copy the code
5, then continue the process to find the __sel_registerName function implementation, which is as follows:
static SEL __sel_registerName(const char *name, bool shouldLock, bool copy) { SEL result = 0; If (shouldLock) sellock. assertUnlocked(); else selLock.assertLocked(); // if (! name) return (SEL)0; // Matches whether the value result = search_builtins(name) already exists in the cache based on the name of the method selector passed in; If (result) return result; Conditional_mutex_locker_t lock(selLock, shouldLock); // Insert method auto it = namedSelectors. Get ().insert(name); If (it.second) {// No unique matching cache was found, *it. First = (const char *)sel_alloc(name, copy); } return (SEL)*it.first; }Copy the code
6. The search_builtins function does a method lookup, and then calls dyLD’s _DYLD_GET_objc_selector function to do the lookup. If the lookup fails, it returns nil. The _dyLD_GET_objC_selector function is explained in objC source code as being called only by OBJC to see if dyLD has a unique selector. If dyld has a unique value, that value is returned; If there is no unique value, nullPtr is returned. Note that this function must be called after _dyLD_OBJC_notify_register.
7, then focus on the sel_alloc function, see the name of the function probably can see the function: to open up memory for SEL. Why do you say so, because each class object in its cache is no cache method, that is, SEL and IMP corresponding to the cache, so the system did not open method cache, so the first time to go to the start memory, for storage. Let’s look at the implementation of sel_alloc: sel_alloc
static SEL sel_alloc(const char *name, bool copy) { selLock.assertLocked(); StrdupIfMutable return (SEL)(copy? strdupIfMutable(name) : name); }Copy the code
Sel_registerName = strdupIfMutable; sel_registerName = true; strdupIfMutable;
Static inline char * strdupIfMutable(const char * STR) {// Add size_t size = strlen(STR) + to the memory size 1; If (_dyLD_IS_memorY_immutable (STR, size)) {return (char *) STR; } else {return (char *)memdup(STR, size); }}Copy the code
The _dyLD_IS_memory_imMUTABLE function is defined in objC as a conditional branch, but it is not implemented in objC. Returns if the specified address range is in a dyld owned memory that is mapped read-only and will never be unloaded. This means that if there is any usable memory in the memory space pointed to by the given address, the changed address is returned directly, and the memory map is read-only and will never be freed. That is, as long as there is enough memory to continue to return this memory space address. Then let’s look at the implementation of memdup function:
Void *dup = malloc(len); static inline void * memdup(const void *mem, size_t len) {void *dup = malloc(len); Memcpy (dup, mem, len); memcpy(dup, mem, len); // return dup; }Copy the code
10. From the above observation, we can see that objC is assigning messages to msG_send and calling setter methods.
11. Then change the main.m code as follows:
12. Then, with the clang-rewrite-objc main.m -o main.cpp conversion, we can see that the value also goes msG_send and sel_registerName is called.
conclusion
The jump in the exploration is relatively fast, so the article looks messy, but the result of the exploration is probably clear, we get the difference of the attribute assignment value.