This is the 12th day of my participation in the August More Text Challenge. For details, see:August is more challenging

Write in the front: the exploration of the underlying principles of iOS is my usual development and learning in the continuous accumulation of a step forward road. I hope it will be helpful for readers to record my journey of discovery.Copy the code

The directory is as follows:

  1. Exploring the underlying principles of iOS alloc
  2. Exploration of the underlying principles of iOS structure in vivo alignment
  3. The nature of the object explored by iOS underlying principles & the underlying implementation of ISA
  4. The underlying principles of the ISA-class (part 1)
  5. The underlying principles of the ISA class (middle)
  6. The underlying principles of isA-Class (part 2)
  7. Exploring the nature of Runtime Runtime & Methods in iOS Underlying principles
  8. Objc_msgSend explores the underlying principles of iOS
  9. Runtime Runtime slow lookup process
  10. Dynamic method resolution for exploring the underlying principles of iOS
  11. IOS underlying principles to explore the message forwarding process
  12. IOS Application loading principle
  13. Application loading principle (2)
  14. IOS underlying principle exploration class load
  15. IOS Underlying principles to explore the classification of loading
  16. Associated object for iOS underlying principle exploration
  17. Exploration of iOS underlying principles of sorcerer KVC
  18. Exploring the underlying principles of iOS — KVO Principles | more challenging in August
  19. Exploration of the underlying principles of iOS rewrite KVO | August more text challenges
  20. Exploring the underlying principles of iOS multithreading | more challenging in August
  21. Exploring the underlying principles of iOS: GCD functions and queues
  22. GCD Principles (part 1)
  23. IOS Low-level – What do you know about deadlocks?
  24. IOS low-level – Destroy a singleton

Summary column for the above

  • Summary of the phase of iOS underlying principle exploration

Tidy up the details

  • Summary of iOS development details

preface

The recent exploration of the COMMUNIST Party of China (GCD) is also coming to an end. Today, let’s learn about the Dispatch Source. Instead, let’s take a look at the Dispatch Source today and use it to implement a custom Timer that’s more accurate than the NSTimer. Well, let’s get started!

Dispatch Source

The Dispatch Source is a wrapper around the BSD system kernel’s customary kQueue, which is a technique for application programmers to perform processing when various events occur in the XNU kernel. It has a very small CPU load and tries not to use resources. Kqueue is arguably one of the best ways for an application to process the various events that occur in a XUN kernel.

When an event occurs, the Dispatch Source performs the handling of the event in the specified Dispatch Queue.

Type of Dispatch Source

typedef conststruct dispatch_source_type_s *dispatch_source_type_t; #define DISPATCH_SOURCE_TYPE_DATA_OR user-defined events OR #define DISPATCH_SOURCE_TYPE_DATA_REPLACE custom event, The variable Replace #define DISPATCH_SOURCE_TYPE_MACH_SEND MACH port sends #define DISPATCH_SOURCE_TYPE_MACH_RECV MACH port receives #define DISPATCH_SOURCE_TYPE_PROC Process monitoring, such as process exit, create one or more child threads, process received UNIX signal #define DISPATCH_SOURCE_TYPE_READ IO operation, For example, read response to file operations and socket operations #define DISPATCH_SOURCE_TYPE_SIGNAL Response when A UNIX signal is received #define DISPATCH_SOURCE_TYPE_TIMER Timer #define DISPATCH_SOURCE_TYPE_VNODE Listens for file status when a file is deleted, moved, or renamed #define DISPATCH_SOURCE_TYPE_WRITE IO operations, such as write response to file operations and socket operationsCopy the code

Use of Dispatch Source

Create a Dispatch Source

  • Create a new dispatch source to monitor low-level system objects and automatically malatic a handler block to the dispatch queue in response to events.

  • The dispatch source is not reentrant. Whether any event source received at dispatch is suspended or the event handler block is currently executing after the dispatch source recovers or after the event handler block has returned.

  • The scheduling source is created in the inactive state. After the source is created and any desired properties are set (for example, handler, context, etc.), dispatch_activate() must be called in order to start event passing. Calling dispatch_set_target_queue() once the source is activated is not allowed (see dispatch_activate() and dispatch_set_target_queue()).

  • For reasons of backward compatibility, dispatch_resume() otherwise, suspended sources and calls have the same effect as dispatch_activate(). For new code, it’s best to use dispatch_activate(). Specifies the type of dispatch source. It must be one of them that defines the dispatch_source_type_t constant.

  • Handle to the underlying system to monitor. The interpretation of this argument depends on the constants provided in the type parameters.

  • Specifies the flag mask for the desired event. This argument is determined by the constant provided in the type parameter.

  • The dispatch queue to which the event handler block will be submitted. If the queue is DISPATCH_TARGET_QUEUE_DEFAULT, the source will submit a handler block for the global queue of event default priority.

  • The newly created dispatch source. NULL if the passed parameter is invalid.

API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT
DISPATCH_NOTHROW
dispatch_source_t
dispatch_source_create(dispatch_source_type_t type,
	uintptr_t handle,
	uintptr_t mask,
	dispatch_queue_t _Nullable queue);
Copy the code

Setting event Handlers

  • Sets the event handler block for the given dispatch source.
  • The scheduling source to be modified. The result of passing NULL in this argument is undefined.
  • The block of event handlers to commit to the source destination queue.
API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NOTHROW
void
dispatch_source_set_event_handler(dispatch_source_t source,
	dispatch_block_t _Nullable handler);
Copy the code

Source event Settings data

  • Merge data into dispatch sources of type DISPATCH_SOURCE_TYPE_DATA_ADD, DISPATCH_SOURCE_TYPE_DATA_OR or DISPATCH_SOURCE_TYPE_DATA_REPLACE, and submits its event handler block to the target queue.

  • The result of passing NULL in this argument is undefined

  • The value to be merged with pending data using logical OR OR ADD is specified by the dispatch source type. A value of zero has no impact and does not cause the event handler block to be committed.

API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
dispatch_source_merge_data(dispatch_source_t source, uintptr_t value);
Copy the code

Obtain the source event data

  • Returns pending data for the dispatch source
  • This function is intended to be called from within the event handler block. The result of calling this function outside of the event handler callback is undefined. The result of passing NULL in this argument is undefined. The return value should be interpreted according to the type of dispatch and may be one of the following:
 *  DISPATCH_SOURCE_TYPE_DATA_ADD:        application defined data
 *  DISPATCH_SOURCE_TYPE_DATA_OR:         application defined data
 *  DISPATCH_SOURCE_TYPE_DATA_REPLACE:    application defined data
 *  DISPATCH_SOURCE_TYPE_MACH_SEND:       dispatch_source_mach_send_flags_t
 *  DISPATCH_SOURCE_TYPE_MACH_RECV:       dispatch_source_mach_recv_flags_t
 *  DISPATCH_SOURCE_TYPE_MEMORYPRESSURE   dispatch_source_memorypressure_flags_t
 *  DISPATCH_SOURCE_TYPE_PROC:            dispatch_source_proc_flags_t
 *  DISPATCH_SOURCE_TYPE_READ:            estimated bytes available to read
 *  DISPATCH_SOURCE_TYPE_SIGNAL:          number of signals delivered since
 *                                            the last handler invocation
 *  DISPATCH_SOURCE_TYPE_TIMER:           number of times the timer has fired
 *                                            since the last handler invocation
 *  DISPATCH_SOURCE_TYPE_VNODE:        dispatch_source_vnode_flags_t
 *  DISPATCH_SOURCE_TYPE_WRITE:           estimated buffer space available
Copy the code
API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_WARN_RESULT DISPATCH_PURE
DISPATCH_NOTHROW
uintptr_t
dispatch_source_get_data(dispatch_source_t source);
Copy the code

Continue to

  • The block call to the dispatch object is restored.
  • Dispatch objects can be suspended using dispatch_suspend(), which increments the internal pause count. Dispatch_resume() is the opposite operation and consumes the pause count. When the last hang count is consumed, the block associated with the object is called again.
  • For backward compatibility reasons, dispatch_resume() in both inactive and inactive states otherwise, the suspended dispatch source object has the same effect as the call dispatch_activate(). For new code, it’s best to use dispatch_activate().
  • If the specified object has a suspend count of zero and is not an inactive source, this function causes the assertion and process termination.
  • Object to restore. The result of passing NULL in this argument is undefined.
API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
dispatch_resume(dispatch_object_t object);
Copy the code

hang

  • Suspends the call to the block on the dispatch object.

  • A pending object will not invoke any of the blocks associated with it. The suspension of an object will occur after the object completes after any associated run blocks.

  • Calls to dispatch_suspend() must be balanced with calls to dispatch_resume().

  • A suspended object. The result of passing NULL in this argument is undefined.

API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
dispatch_suspend(dispatch_object_t object);
Copy the code

cancel

  • Undispatch the source asynchronously, preventing any further calls to the event handler block.
  • Cancellation will prevent any further calls to the event handler block specified dispatch source, but don’t interrupt event handler ongoing blocks, cancel the handler is submitted to the source of the target queue source of the event handler is complete, that now safe to handle to closed source (such as file descriptors or Mach port).
  • The dispatch source to cancel. The result of passing NULL in this argument is undefined.
API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
dispatch_source_cancel(dispatch_source_t source);
Copy the code

Custom Timer

The use of a Dispatch Source is roughly the same as above, and we’ll implement a timer ourselves (that fires once per second).

Define a block that defines what task we will execute when the one second clock runs out.

typedef void(^task)(void);
Copy the code

Define two methods:

/// Add the task to be executed once per second
- (void)executeTask:(task)task;

/// Start or pause the timer
- (void)starOrPause;
Copy the code

Customize a dispatch_source_t:

    // Customize the serial queue
    dispatch_queue_t queue = dispatch_queue_create("com.monkey.timer", DISPATCH_QUEUE_SERIAL);
    // Timer mode
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0.0, queue);
    // Triggers every second
    dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), NSEC_PER_SEC * 1.0);
Copy the code

To realize the method of opening or suspending:

if(! self.isRefreshing) {// Do not count - start the timer
        
    dispatch_resume(self.timer);
    self.isRefreshing = YES;
    NSLog(@"Start");
}else {
    // The timer is ticking - just hang
        
    dispatch_suspend(self.timer);
    self.isRefreshing = NO;
    NSLog(@"Hang");
}
Copy the code

To implement the add task:

dispatch_source_set_event_handler(self.timer, task);
Copy the code

So, the timer is written.