More:

Interview questions for iOS (part 1)

Interview questions for iOS (Part 2)

Want to enter big factory, interview question essential! (iOS Interview collection!)

IOS Interview Materials

1. What is the relationship between Runloop and thread?

  • A thread corresponds to a Runloop.
  • The default for the main thread is Runloop.
  • The Runloop for the child thread is created as a lazy load.
  • The Runloop is stored in a global mutable dictionary where the thread is key and Runloop is value.

2. Running mode of RunLoop

  • RunLoop runs in one of five modes. To switch modes, you have to pause the current mode and override the starting one
-uitRackInGrunLoopMode, which tracks user interaction events (used for ScrollView tracking touch slides, Ensure the interface slip is not affected by other Mode) - kCFRunLoopCommonModes, pseudo Mode, is not a real running Mode - UIInitializationRunLoopMode: When just start the App the first to enter the first Mode, start will no longer use - GSEventReceiveRunLoopMode: after the completion of acceptance within the system, is usually not usedCopy the code

3. Internal logic of runloop?

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

  • Internal logic:

    1. Notifies the Observer that the RunLoop has entered

    2. Notifies the Observer that the Timer is about to be processed

    3. Notifying the Observer that non-port-based input sources will be processed (Source0 will be processed)

    4. Processing those non-port-based input sources that are ready (processing Source0)

    5. If the port-based input source is ready and waiting for processing, process the event immediately. Go to Step 9 (processing Source1)

    6. Notifies the Observer that the thread is about to sleep

    7. Put the thread to sleep until one of the following events occurs

      • The event reaches a port-based input source (i.e. Source0).
      • Timer to time execution
      • External manual wake up
      • The time set for RunLoop times out
    8. Notifies the Observer that the thread has just woken up (the event has not yet been handled)

    9. Handle the events to be handled

      • If it is a Timer event, process the Timer and restart the loop, jumping to Step 2
      • If the input source is triggered, process the event (deliver the Event on documents)
      • If the RunLoop has been manually awakened but has not timed out, restart the loop and skip to Step 2

4. When is autoreleasePool released?

  • The App starts, apple registered in the main thread RunLoop two Observer, the callback is _wrapRunLoopWithAutoreleasePoolHandler ().
  • The first event monitored by the Observer is an Entry(about to enter the Loop), which calls _objc_autoreleasePoolPush() within its callback to create an automatic release pool. Its order is -2147483647, which has the highest priority, ensuring that the creation of the release pool takes place before any other callbacks.
  • The second Observer monitors two events: BeforeWaiting(ready to go to sleep) calls _objc_autoreleasePoolPop() and _objc_autoreleasePoolPush() releases old pools and creates new ones; BeforeWaiting(ready to go to sleep) calls _objc_autoreleasePoolPush() releases old pools and creates new pools; Call _objc_autoreleasePoolPop() when Exit(about to Exit the Loop) torelease the automatic release pool. The order of this Observer is 2147483647, which has the lowest priority, ensuring that its pool release occurs after all other callbacks.
  • Code that is executed on the main thread is usually written in event callbacks, Timer callbacks, etc. These callbacks are surrounded by the AutoreleasePool created by RunLoop, so there are no memory leaks and the developer does not have to show that the Pool was created.

5. Use of GCD in Runloop?

  • GCD returns from the child thread to the main thread, and only in this case will a RunLoop be fired. The Source 1 event for the RunLoop is triggered.

6. How to use Runloop in AFNetworking?

  • AFURLConnectionOperation the AFURLConnectionOperation class is built on NSURLConnection and is expected to receive a Delegate callback in a background thread. AFNetworking created a separate thread for this purpose and started a RunLoop in that thread:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

+ (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [_networkRequestThread start];
    });
    return _networkRequestThread;
}
Copy the code
  • RunLoop must have at least one Timer/Observer/Source internally before starting, so AFNetworking created a new NSMachPort and added it before [RunLoop Run]. Normally, the caller needs to hold this NSMachPort (mach_Port) and send messages to the loop from the external thread through this port; But the port is added here only to keep the RunLoop from exiting, not to actually send the message.
- (void)start { [self.lock lock]; if ([self isCancelled]) { [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread]  withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; } else if ([self isReady]) { self.state = AFOperationExecutingState; [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; } [self.lock unlock]; }Copy the code
  • When need the background threads execute tasks, AFNetworking by calling [NSObject performSelector: onThread:..] Throw this task into the RunLoop of the background thread.

7. How does PerformSelector work?

  • When calling NSObject performSelecter: afterDelay: after its internal will actually create a Timer and add to the current thread RunLoop. So if the current thread does not have a RunLoop, then this method will fail.
  • When the performSelector: onThread: when, in fact, it will create a Timer is added to the corresponding thread, in the same way, if the corresponding thread no RunLoop this method will fail.

8. PerformSelector: afterDelay: this method in the child thread work?

  • No, the child thread has no Runloop by default, and therefore no Timer. This can be done using GCD’s dispatch_after

9. Event response process?

  • Apple registered a Source1 (based on the Mach port) to the receiving system, the callback function as __IOHIDEventSystemClientQueueCallback ().
  • When a hardware event (touch/lock/shake, etc.) occurs, an IOHIDEvent event is generated by the IOKit. Framework and received by SpringBoard. The details of this process can be found here. SpringBoard only receives events such as button (lock screen/mute, etc.), touch, acceleration, proximity sensor, etc., and then forwards them to the desired App process using Mach Port. Then apple registered the Source1 will trigger the callback, and call the _UIApplicationHandleEventQueue () distribution within the application.
  • _UIApplicationHandleEventQueue () will wrap IOHIDEvent process, and as a UIEvent processing or distribution, including identifying UIGesture/processing screen rotation/send UIWindow, etc. Usually click event such as a UIButton, touchesBegin/Move/End/Cancel events are completed in the callback.

10. The process of gesture recognition?

  • When _UIApplicationHandleEventQueue () to identify a gesture, the first call will Cancel the current touchesBegin/Move/End series callback to interrupt. The system then marks the corresponding UIGestureRecognizer as pending.
  • Apple registered a Observer monitoring BeforeWaiting (Loop entering hibernation) events, the callback function Observer is _UIGestureRecognizerUpdateObserver (), Internally it gets all the GestureRecognizer that was just marked for processing and executes the GestureRecognizer’s callback.
  • This callback handles any changes (create/destroy/state change) to the UIGestureRecognizer.

Which is more accurate, CADispalyTimer or Timer

More accurate CADisplayLink

  • IOS devices have a fixed screen refresh rate, and CADisplayLink is normally called at the end of each refresh, which is fairly accurate.
  • NSTimer is less accurate. For example, if the runloop is blocked when the NSTimer’s firing time is up, the firing time will be delayed until the next runloop cycle. A tolerance attribute has been added to NSTimer, allowing users to set a tolerance range for triggering time.
  • CADisplayLink is used in specific situations, suitable for continuous redrawing of UI, such as custom animation engine or video playback rendering. NSTimer is much more widely used, and can be used for a variety of tasks that require single or circular timing. The advantage of using CADisplayLink for UI-related animations or displays, as opposed to using NSTimer, is that you don’t have to worry too much about the screen refresh frequency because it is synchronized with the screen refresh.

More: An iOS Interview Guide