1. Review

In the previous blog, a series of exploration and analysis of the OC underlying source code,Last blogSome interview questions have also been answered and analyzed, and this blog continues the interview questions analysis!

2. IOS Interview Question Analysis

2.1 The nature of the method? What is sel? What is IMP? What is the relationship between the two?

  • Essence of the method: send message flow
  1. Quick message lookup (objc_msgSend),cache_tCache lookup messages.
  2. Slow message lookup (lookUpImpOrForward) recurse itself and the parent class, and if you can’t find it by yourself, you can’t find it in the cache of the parent class, and you will do a slow search of the parent class until you find nil.
  3. Cannot find the message for dynamic method parsing (resolveInstanceMethod/resolveClassMethod).resolveClassMethodIf a method is not found during the process, it will be calledresolveInstanceMethod.
  4. Fast message forwarding (forwardingTargetForSelector) is equivalent to finding an alternate recipient of the message.
  5. Slow message forwarding (methodSignatureForSelector & forwardInvocation), after still not solving the problemmethodSignatureForSelectorAgain, a slow message lookup (this time without message forwarding) is performed.
  6. In the end there are still no solved problems that will enterdoesNotRecognizeSelectorThrow an exception.
  • selIs the method number, inread_images It is compiled into memory.
  • impIt’s the function implementation pointer, findimpIt’s finding the function.

Sel-imp can be understood as the book’s table of contents, sel the name of the book’s table of contents, and IMP as the page number of the book. To look for specific functions is to look for specific chapters in the book.

  • 1: We first know what we want to see — > tittle (sel)

  • 2: based on the directory page number — >(IMP)

  • 3: Turn to the specific content

  • impwithSELThe relationship between

SEL: method number IMP: function pointer address. SEL is the name of the book catalog. IMP: page number of the book catalog

  1. First understand what we are looking for in the book (sel The name in the directory)
  2. Find the corresponding page number by name (imp)
  3. Use page numbers to locate specific content

2.2 Is it possible to add instance variables to the compiled class? Can you add instance variables to classes created at run time

You cannot add an instance variable to the compiled class

Reason: Our compiled instance variables are stored in ro. Once compiled, the memory structure is completely determined and cannot be modified.

It can be added as long as it is not registered in memory

You can add properties, methods, and so on by associating objects

We mainly use objc_setAssociatedObject, objc_getAssociatedObject, and objc_removeAssociatedObjects methods

When our object is freed –> dealloc 1: c++ function is freed: object_cxxDestruct 2: remove associated properties: _object_remove_assocations 3: automatically set weak references to nil: Weak_clear_no_lock (&table. Weak_table, (id)this) 4: Reference count processing: tab.refcnts. Erase (this) 4: Destroy object: free(obj)

2.3 The differences and Principles between [self Class] and [Super Class]

So let me start by looking at the code below

@implementation LGTeacher
- (instancetype)init{
    self = [super init];
    if (self) {
        NSLog(@ % @ - % @ ""[self class], [super class]);
    }
    return self;
}
Copy the code

The code runs as follows:

202107 -- 30 10:49:10.213169+0800 ObjcBuild[65615:2453340] LGTeacher--LGTeacher
Copy the code

[self class] printing results are understandable, but [super class] printing is confused

What a surprise. So let’s see clang, objc_msgSendSuper

Then debug it and compile the trace to see

Don’t look unimportant, a look more meng! What the hell 👻?? Don’t you send objc_msgSendSuper? Objc_msgSendSuper2! Now the skull is buzzing! Puzzled.

- (Class)class {
    return object_getClass(self);
}

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
Copy the code
  • classisNSObjectThe method ofclassThe hidden parameter of isid self.SEL _cmd. so[self class]Is to send a messageobjc_msgSend, the message recipient isself And method numberclass. So backLGTeacher.
  • forsuperIt doesn’t have this parameter. It’s not a parameter name, it’s aCompiler keyword. inclangIs called after compilation inobjc_msgSendSuperMethods.
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... * / )
Copy the code

Objc_msgSendSuper has two arguments, objc_super and SEL

  • objc_super
/// Specifies the superclass of an instance. 
struct objc_super {
    __unsafe_unretained _Nonnull id receiver;
#if! defined(__cplusplus) && ! __OBJC2__
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
};
#endif
Copy the code

One of the parameters, receiver, is the message receiver, and super_class is the first class to be looked up, but it actually calls objc_msgSendSuper2, which is verified above.

  • objc_msgSendSuper2
// objc_msgSendSuper2() takes the current search class, not its superclass.
OBJC_EXPORT id _Nullable
objc_msgSendSuper2(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
Copy the code

You can also see from the source code comments that super_class should be the current class.

  • objc_msgSendSuperwithobjc_msgSendSuper2The implementation is as follows:
    ENTRY _objc_msgSendSuper
    UNWIND _objc_msgSendSuper, NoFrame
    P0 storage receiver, P16 storage class
    ldp p0, p16, [x0]       // p0 = real receiver, p16 = class
    // Skip to the implementation of L_objc_msgSendSuper2_body
    b L_objc_msgSendSuper2_body

    END_ENTRY _objc_msgSendSuper

    // no _objc_msgLookupSuper

    ENTRY _objc_msgSendSuper2
    UNWIND _objc_msgSendSuper2, NoFrame

#if __has_feature(ptrauth_calls)
    ldp x0, x17, [x0]       // x0 = real receiver, x17 = class
    / / read
    add x17, x17, #SUPERCLASS   // x17 = &class->superclass
    ldr x16, [x17]      // x16 = class->superclass
    AuthISASuper x16, x17, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS
LMsgSendSuperResume:
#else
    // LDP reads two registers and resolves objc_super into receiver and class
    ldp p0, p16, [x0]       // p0 = real receiver, p16 = class
    // Find superclass by class
    ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
#endif
L_objc_msgSendSuper2_body:
    // Look for the cache
    CacheLookup NORMAL, _objc_msgSendSuper2, __objc_msgSend_uncached

    END_ENTRY _objc_msgSendSuper2
Copy the code

_objc_msgSendSuper jumps to _objc_msgSendSuper2, the difference is that _objc_msgSendSuper is called directly, Objc_msgSendSuper2 obtains superClass from CLS. That is to say, the superClass of objc_super passed by objc_msgSendSuper is the superClass, and the superClass of objc_super passed by objc_msgSendSuper2 is itself, and the superClass of objc_super is obtained in assembly code.

In [super class], the receiver determines the receiver of the message. In this case, the receiver is self (LGTeacher)

So [super class] also prints LGTeacher.

  • inllvmThe implementation source code is as follows:

More to come

🌹 just like it 👍🌹

🌹 feel have harvest, can come a wave, collect + concern, comment + forward, lest you can’t find me next 😁🌹

🌹 welcome everyone to leave a message to exchange, criticize and correct, learn from each other 😁, improve self 🌹