1. How much memory an OC object occupies

  • The system allocates 16 bytes to the NSObject object (obtained by the malloc_size function)

  • But NSObject uses only 8 bytes of space internally (available in 64-bit environments via class_getInstanceSize)

2. Where does the isa pointer to the object point to?

  • The ISA of an instance object points to a class object
  • The ISA of a class object points to a meta-class object
  • The ISA of a meta-class object points to a meta-class object of the base class

3. Where is the OC class information stored?

  • Object methods, properties, member variables, and protocol information are stored in class objects
  • Class method, stored in a meta-class object
  • The specific value of a member variable is stored in the instance object

4. How does iOS implement KVO for an object? (What is the nature of KVO?)

  • Use the RuntimeAPI to dynamically generate a subclass and have the Instance object’s ISA point to the new subclass

  • When modifying the properties of an instance object, Foundation’s _NSSetXXXValueAndNotify function willChangeValueForKey is called.

  • Internal will trigger the listener (Oberser) surveillance methods (observeValueForKeyPath: ofObject: change: context:)

5. How do I manually trigger KVO?

Manually call willChangeValueForKey and didChangeValueForKey:

- (void)viewDidLoad { [super viewDidLoad]; Person *person = [[Person alloc]init];; [p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];  [p willChangeValueForKey:@"name"]; [p didChangeValueForKey:@"name"]; } -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{NSLog(@" observed object :%@, observed attribute :%@, value change :%@ \n, carrying information :%@", object, keyPath, change, context); }Copy the code

6. Does directly modifying a member variable trigger KVO?

  • KVO will not trigger

7. Does modifying attributes via KVC trigger KVO?

  • Will trigger the KVO
  • When KVC is assigned, the listener is triggered internally (Oberser) (observeValueForKeyPath:ofObject:change:context:) Send notifications

8. What is the assignment and value process of KVC? How does it work?

  • KVC stands for key-value Coding, commonly known as “key-value Coding”, which allows access to an attribute through a Key

  • Call setValue: forKey: \ setKey _setKey – > found on assignment, call accessInstanceVarlableDirctly whether to allow to modify the value value was not found, returns YES, call _key, _isKey, Key, isKey is assigned

9. What is the use of Category?

  • Add object methods or class methods to a class without modifying the existing class code
  • Or associate a new attribute with a class
  • Decompose large class files

Application situation:

  • Add Instance method
  • Add class methods
  • Add the agreement
  • Add attributes
  • Associated member variable

10. Implementation principle of Category

  • After Category compilation, the underlying structure is struct category_t, which stores classified object methods, class methods, attributes, and protocol information

  • At runtime, the Runtime merges the Category data into the class information (class object, metaclass object).

11. What is the difference between a Category and a Class Extension?

  • When Class Extension is compiled, its data is already included in the Class information
  • Category data is merged into the class information at runtime

12. Is there a load method in Category? When is the load method called? Can the load method inherit?

  • With the load method
  • The load method is called when the Runtime loads a class or class
  • The load method can be inherited, but usually the system does not automatically call the load method

13. How and when is the initialize method called

  • The initialize method of the class is called when the class receives a message for the first time
  • Is the messaging mechanism through runtimeobjc_msgSend(obj,@selector())callable
  • Class initialize is called first, if there is no class, the subclass is called, if the subclass is not implemented, the parent class is called

What is the difference between load and initialize methods? What order are they called in the category? And how they call each other when inheritance occurs?

  • Load is called when the class is loaded into memory, preferentiallySuperclass -> subclass -> category
  • Initialize is called the first time the class receives a message, preferentiallyCategory -> Subclass -> Parent class
  • It depends on the level and compile order
  • The load method is called before the main function

15. Can I add member variables to a Category? If so, how do YOU add member variables to a Category?

  • You cannot add member variables to a Category directly, but you can make it look like a Category has member variables indirectly
  • Category occurs at runtime, after compilation, the memory layout of the class has been determined, and member variables cannot be added (the underlying data structure of the Category also has no structure for member variables).
  • You can dynamically correlate properties through runtime

16. How does Block work? What is the essence?

  • A block is essentially an OC object
  • A block encapsulates the function call and the calling environment

17. What does __block do? What is the use of attention?

  • If you need to change the value of an external local variable inside a block, you need to use the __block modifier (global and static variables can be modified without __block).
  • After __block modification, the data structure of the local variable is changed, and the underlying object becomes a structure object, which declares a member of the __block modifier variable, and stores the address of the __block modifier variable in the heap memory. If you want to change the value of the variable, you can use the isa pointer to find the structure and change the value of the variable.
  • You can change the value of a variable inside a block

18. Why is copy the attribute modifier of block? What are the implications of using blocks?

  • Once a block is not copied, it is not on the heap
  • Usage Note: Circular reference problem (externally resolved using __weak)

19. Block To modify NSMutableArray, do I need to add __block?

  • This is not necessary if you are operating on an NSMutableArray object, because the block copies the memory address of the NSMutableArray object
  • If the NSMutableArray object is to be reassigned, __block is added

20. Why can’t local variables be modified inside a Block

  • If an external variable is used inside a Block, the same variable will be created inside the Block, and the value of the external variable will be referenced. (just copy the value of the external variable inside the block), the internal variable has nothing to do with the external
  • On the other hand, a block is essentially a function pointer, and the external variable is also a local variable. It is possible that when a block uses this variable, the external variable has already been released, causing an error
  • When __block is added, the memory of external variables is copied to the heap, which is managed by the block.

21. Talk about OC’s messaging mechanism

  • Method calls in OC are actually converted into calls to objc_msgSend, which sends a message to the receiver (selector method name).
  • Objc_msgSend has three main phases underneath
    • Message sending (look up in current class, parent class)
    • Dynamic method parsing
    • forward

22. Message sending process

  • When one of our receivers receives a message, it finds its class object through the ISA pointer, then looks for the corresponding method implementation in the list of class object methods, and if not, finds the class object of its parent through the superClass pointer. If it finds it, it returns it, if it doesn’t find it, it goes up and down, eventually it gets to NSObject, and if it still doesn’t find it, it does dynamic method parsing
  • The class method call is the same as above, except that the ISA pointer finds the metaclass object;

23. Dynamic method resolution mechanism

When we send a message and do not find a method implementation, we enter the second step, dynamic method resolution: the code implementation is as follows

ResolveInstanceMethod :(SEL) SEL {if (SEL == @selector(run)) {Method Method = class_getInstanceMethod(self, @selector(test)); class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method)); return YES; } return [super resolveInstanceMethod:sel]; } // class method call +(BOOL) resolveClassMethod:(SEL) SEL....Copy the code

24. Process of message forwarding mechanism

If the dynamic method binding is not found, the message forwarding phase occurs

/ / fast forward - specified message processing object - (id) forwardingTargetForSelector aSelector: (SEL) {if (aSelector = = @ the selector (run)) {return [Student  new]; } return [super forwardingTargetForSelector:aSelector]; } / / standard message forwarding - signing messages - (NSMethodSignature *) methodSignatureForSelector aSelector: (SEL) {if (aSelector = = @ the selector (run)) { return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } return [super methodSignatureForSelector:aSelector]; } - (void)forwardInvocation:(NSInvocation *)anInvocation{// internal logic to handle}Copy the code

25. What is Runtime? Have you used it in your daily projects?

  • Objective-c Runtime is a runtime library that provides support for the dynamic features of Objective-C. All OC code we write is converted to Runtime code at runtime, classes are converted to C constructs, methods are converted to C functions. The message is converted to the corresponding function call in C language. By understanding the Runtime and source code, you can have a deeper understanding of the features and principles of the OC

  • OC is a very dynamic programming language, allowing many operations to be deferred until the program is running

  • The dynamism of OC is supported and implemented by Runtime, which is a SET of C LANGUAGE APIS that encapsulates many functions related to dynamism

  • The OC code written at ordinary times is converted into the Runtime API to call

26. Runtime application

  • Add attributes to categories using AssociatedObject
  • Iterate over all member variables of the class (changing placeholder text color of TextField, dictionary conversion model, auto archive unfile)
  • Switching method implementation (switching system method)
  • Use the message forwarding mechanism to resolve exceptions where methods cannot be found

27. Unrecognized selector sent to instance error

This error is based on the MESSAGE mechanism of OC:

  • Method implementation not found in method list
  • Try dynamic method resolution, no binding violation
  • The message is forwarded and not processed
  • Finally, an error is reported

28. If sending a message to a nil object does not crash, what is the error of sending a message to deallocated instance?

  • The object has been freed (reference count = 0), so calling the method will Crash, because the object is a pointer to a zombie object (reference count = 0, the memory that the pointer points to is not available). It is safe to reset the object to nil after release, making it a null pointer

29. What happens when you send a message to an NILL object?

  • OC sends a message to nil, it doesn’t do anything, it doesn’t crash.

OC uses objc_msgSend to send messages. Compared with C and C++, null pointer operations can cause crash problems. Objc_msgSend determines whether to send messages by checking self. And then the selector will be empty, so it’ll just return, no problem. Depending on the method return value, sending a message to nil might return nil (object), 0 (some underlying data), or 0X0 (ID), etc. For [NSNull null] objects, however, it will crash because the NSNull class has only one NULL method

30. Code print result:

@interface Person : NSObject @end @implementation Person @end @interface Student : Person @end @implementation Student - (instancetype)init{ if (self= [super init]) { NSLog(@"%@", [self class]); NSLog(@"%@", [super class]); NSLog(@"%@", [self superclass]); NSLog(@"%@", [super superclass]); }} [self superClass] and [super superClass] both return a message to the current class. Spuer Student / Student/ Person / PersonCopy the code

31. Code execution results?

BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [[Person class] isKindOfClass:[Person class]];
BOOL res4 = [[Person class] isMemberOfClass:[Person class]];
NSLog(@"%d-%d-%d-%d",res1, res2, res3, res4);
Copy the code
  • IsKindOfClass indicates whether the object is of the type of the current class or subclass
  • IsMemberOfClass indicates whether it is the type of the current class
  • IsMemberOfClass is divided into – object method and + class method 2

    - (bool)isMemberOfClass; Class objects are compared

    + (bool)isMemberOfClass; The comparison is metaclasses

Print result: 1,0, 0, 0

32. Talk about RunLoop. Is it useful in the project?

  • Runloop runs a loop that keeps the program running. The main thread is enabled by default
  • Used to handle various events on the thread, timer, etc
  • It can improve application performance, save CPU resources, do something when there is something to do, and let the thread sleep when there is nothing to do
  • Application areas: timer, event response, gesture recognition, interface refresh, autoreleasePool, etc

33. Implementation logic inside Runloop?

  • RunLoop is actually just such a function, with a do-while loop inside. When you call CFRunLoopRun(), the thread stays in the loop forever; This function does not return until it times out or is stopped manually.

34. How do runloops relate to threads?

  • Each thread has a unique RunLoop object corresponding to it

  • Runloops are stored in a global Dictionary, with threads as keys and runloops as values

  • The thread is created without a RunLoop object; the RunLoop is created the first time it gets it

  • The RunLoop is destroyed at the end of the thread

  • The RunLoop for the main thread is automatically acquired (created), and RunLoop is not enabled for the child thread by default

35. Relation between Timer and Runloop?

  • The timer is implemented based on a runloop. The runloop listens to the customizer during the running loop and executes it. Therefore, the timer needs to be added to the runloop. Note that the runloop of the child thread is not enabled by default. If the timer is executed on the child thread, you need to manually enable the runloop

36. Add NSTimer that responds every 3 seconds in the program. When dragging the TableView, the timer may not respond.

  • Add the Timer object to the runloop and change the runloop’s running mode
 NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:nil];
 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
Copy the code

37. What is the mode function of runloop?

  • Runloop can only run in one mode, The default is kCFRunLoopDefaultMode. If the view slides back to UITrackingRunLoopMode, you need to set it manually if you want to run it in multiple modes kCFRunLoopCommonModes;
  • KCFRunLoopDefaultMode: The default Mode of the App in which the main thread normally runs

  • UITrackingRunLoopMode: interface tracing Mode, used by ScrollView to track touch sliding, ensuring that the interface sliding is not affected by other modes

  • UIInitializationRunLoopMode: in the first to enter the first Mode when just start the App, start no longer use, after the completion will switch to the kCFRunLoopDefaultMode

  • GSEventReceiveRunLoopMode: accept system internal Mode of events, usually in less than

  • Kcfrunloopcommonmode: this is a placeholder Mode, used to mark kCFRunLoopDefaultMode and UITrackingRunLoopMode, not a real Mode

38. What should I pay attention to when using Method Swizzling?

  • Mode infinite loop
  • Some checks need to be done during version iteration in case the library functions change

39. Does it matter if a system method is swapped more than once? And in what order? The principle of

Will be executed, the last swap will be called first. So the first time you swap viewwillAppAppear and test1 and the method that points to it changes the address and the second time you swap viewwillAppAppear and test2 and you're essentially swapping test2 and test1 because ViewwillAppAppear has become test1. Test2 -- test1-- viewwillAppAppear creates a closed loop :viewwillAppAppear is called only onceCopy the code

40. The main runloop listener is stuck

  • User-level perceived lag comes from the main thread that processes all the UI, including large computations, heavy IO operations, or heavy drawing work on the main thread.

How do you monitor the main thread? The first thing you need to know is that the main thread is driven by NSRunLoop just like any other thread. Take a look at the general logic of CFRunLoopRun , it is not difficult to find that the NSRunLoop call method is mainly between kCFRunLoopBeforeSources and kCFRunLoopBeforeWaiting, and after kCFRunLoopAfterWaiting, that is, if we find that the time between the two is too long, Then you can tell that the main thread is stuck. Just start another thread and calculate in real time whether the time between the two states has reached a certain threshold to catch these performance killers.

Start a new thread with dispatch_semaphore_t in GCD, set a limit and number of occurrences, Then get the scenarios on the main thread between kCFRunLoopBeforeSources to kCFRunLoopBeforeWaiting and kCFRunLoopAfterWaiting that exceed the limit and occurrence times and dump the stack. Finally sent to the server for collection, through the stack can find the corresponding problem of that method.

- (void)start { if (observer) return; // // create signal semaphore = dispatch_semaphore_create(0); CFRunLoopObserverContext Context = {0,(__bridge void*)self,NULL,NULL}; observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &runLoopObserverCallBack, &context); CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes); Dispatch_async (dispatch_get_global_queue(0, 0)) ^{while (YES) {// Long st = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 50*NSEC_PER_MSEC)); // Returns zero on success, or non-zero if the timeout occurred. if (st ! = 0) { if (! observer) { timeoutCount = 0; semaphore = 0; activity = 0; return; } // kCFRunLoopBeforeSources is about to be processed source kCFRunLoopAfterWaiting just woke up from sleep // The RunLoop will loop all the way from thread start to thread end, Observers detect that the event source (CFRunLoopSourceRef) is executing handler functions, first generating notifications. Corefunction adds runloopObservers to threads to listen for events and control execution and dormancy of threads in NSRunLoop. Make the current NSRUNLoop-controlled thread work when there is something to do, there is nothing to do to make the current NSRUNloop-controlled thread sleep. if (activity == kCFRunLoopBeforeSources || activity == kCFRunLoopAfterWaiting) { if (++timeoutCount < 3) continue; NSLog(@" kind of stuck "); } } timeoutCount = 0; }}); }Copy the code

41. What does _objc_msgForward do? What happens when you call it directly?

  • _objc_msgForward is an IMP type for message forwarding: when a message is sent to an object and it is not implemented, _objc_msgForward will attempt to forward the message

  • Calling _objc_msgForward directly is dangerous. It’s a two-edged knife that can Crash the program if used badly, but can do a lot of really cool things if used well

  • JSPatch implements its core functionality by calling _objc_msgForward directly

42. How do I print all instance variables in a class

  • The OC class is actually an objc_class structure containing a list of instance variables: (objc_ivar_list). This list can be obtained by the Runtime function:

OBJC_EXPORT Ivar _Nonnull * _Nullable class_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount)

🌰

Student *stu = [[Student alloc]init];
stu.stu_name = @"alex";
stu.stu_age = 10;

unsigned int count = 0;
Ivar *list = class_copyIvarList([stu class], &count);
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
for (int i = 0; i< count; i++){
    id iVarName = [NSString stringWithUTF8String:ivar_getName(list[i])];
    dict[iVarName] = [stu valueForKey:iVarName];
}

NSLog(@"%@",dict);
Copy the code

43. How do I add a class dynamically using RumTime

  • Runtime is powerful. You can create a new class or object on the fly
MyClass = objc_allocateClassPair([NSObject Class], "MyClass", 0); // add the instance variable class_addIvar(MyClass, "_age", sizeof(NSString *), 0, "@"); Objc_registerClassPair (MyClass); Myobj = [[MyClass alloc] init]; [myobj setValue:@30 forKey:@"age"]; / / print NSLog (@ "age = % @", [myobj valueForKey: @ "age"));Copy the code
The statement
The answer to the interview questions in this article is based on the collection of various gods, the answer is not necessarily the most comprehensive, the most appropriate, if there is a question, welcome to actively discuss.
Reference article:

www.jianshu.com/p/ca1ff3749…

Github.com/ReginaVicky…