Countdown Tool Class: PYContDownManager


Countdown. gif
  1. On the left is the output desk and on the right is the tableView. After clicking modal, a controller stops the timer.

I. Main Functions

For tableViewCell, there is always the problem of multiple cell s randomly timing, so a tool class is written.
It encapsulates stop countdown and start countdown. Provides the countdown unit timing time, as well as the remaining time from the current time to start timely variables, easy to use, asynchronous thread calculation. General performance.

Header document.h

1. Creating Method

1. Two methods are used to create these parameters. The external parameters are specified and stored internally.

/**
 * Use this method (or the corresponding init method) to create objects
 *@ How long does Parma countdown downStartTime take to start countdown
 *@ Parma countdown Unit countdown unit time
 *@ Parma model Array requires a countdown model array
 *@ Property name of Parma model DateKey model to store expiration time
 *@ Parma Model CountDownKey Model stores the attribute name for the remaining time
 *@ Is the expiration time stored in Parma model DateType model the remaining time?
 */
-(instancetype)initWithCountDownStartTime: (long)countDownStartTime andCountDownUnit: (double)countDownUnit andModelArray: (NSArray *)modelArray andModelDateKey: (NSString *)modelDateKey andModelCountDownKey: (NSString *)modelCountDownKey andModelDateType: (PYContDownManagerModelDateType)modelDateType;
/**
 * Use this method (or the corresponding init method) to create objects
 * @parma countDownStartTime How long will the countdown begin?
 * @parma countDownUnit Countdown unit time
 * @parma modelArray An array of model s that require countdown
 * @parma modelDateKey model Property name for storage expiration time
 * @parma modelCountDownKey model Property names that store the remaining time
 * @parma modelDateType model Is the expiration time in storage the remaining time?
 */
+(instancetype)countDownManagerWithCountDownStartTime: (long)countDownStartTime andCountDownUnit: (double)countDownUnit andModelArray: (NSArray *)modelArray andModelDateKey: (NSString *)modelDateKey andModelCountDownKey: (NSString *)modelCountDownKey andModelDateType: (PYContDownManagerModelDateType)modelDateType;

2. Common methods:

  1. This method is used for UI interface refresh outside. Here you can traverse the model array, find a model less than 0, and do the relevant UI operations (default back to the main thread)
    /**
    * The UI can be refreshed here (it has returned to the main thread)
    *@ Param countdown Data Fredback WithBlock provides a model to the outside world (by this time the model has been assigned successfully).
    */
    -(void)countdownDataFredbackWithBlock: (void(^)(id model,long long CountDown))countdownDataFredbackWithBlock;
  • Cancel the timer: In most cases, clicking on the cell will jump to the corresponding secondary interface, so we need to turn off the timer.
    /**
    *Cancel timer
    */
    -(void)cancelTimer;
  • Timer restart: Similarly, when you call back to the current interface, the timer should be restarted (in fact, a timer has been recreated internally).
    /**
    *Turn on the timer
    */
    -(void)resumeTimer;
  • 3. Common attributes

    1. In many cases, the time when the server requests back is not the same as the local time, which will lead to the inaccuracy of the countdown, so we need to unify the current time of the local reference with the current time of the server, and pass the server time here to correct the accuracy of the countdown.
    If you have any questions about server and client time correction, please see here.

    /**
     * Client time, default to the current time of the mobile phone. If there are any deviations, you can adjust them here.
     */
    @property (nonatomic,strong) NSDate *clientTime;

    3. Logic of concrete realization.

    1. Logic

    1. A timer is created inside the class. Each time the timer executes, it traverses the model array and decides whether it should be counted down. If it needs to be counted down, it assigns the remaining time attribute of the model through kvc.
    2. Every other unit interval, the block of the callback method is executed

    2. Realization

    1. create object

      In fact, it is to record the attributes and finally use them. [self createTimer]Create a timer

      #pragma mark - Create objects
      +(instancetype)countDownManagerWithCountDownStartTime: (long)countDownStartTime
                                         andCountDownUnit: (double)countDownUnit
                                            andModelArray: (NSArray *)modelArray
                                          andModelDateKey: (NSString *)modelDateKey
                                     andModelCountDownKey: (NSString *)modelCountDownKey
                                         andModelDateType: (PYContDownManagerModelDateType)modelDateType
      {
       return [[self alloc]initWithCountDownStartTime:countDownStartTime
                                     andCountDownUnit:countDownUnit
                                        andModelArray:modelArray
                                      andModelDateKey:modelDateKey
                                 andModelCountDownKey:modelCountDownKey
                                     andModelDateType:modelDateType];
      }
      -(instancetype)initWithCountDownStartTime: (long)countDownStartTime
                             andCountDownUnit: (double)countDownUnit
                                andModelArray: (NSArray *)modelArray
                              andModelDateKey: (NSString *)modelDateKey
                         andModelCountDownKey: (NSString *)modelCountDownKey
                             andModelDateType: (PYContDownManagerModelDateType)modelDateType
      {
       self = [super init];
       if (self) {
           self.countDownStartTime = countDownStartTime;
           self.countDownUnit = countDownUnit;
           self.modelArray = modelArray;
           self.modelDateKey = modelDateKey;
           self.modelCountDownKey = modelCountDownKey;
           self.modelDateType = modelDateType;
           if (!self.timer){
               [self createTimer];
           }
       }
       return self;
      }
    2. Timer Creation

      Here it is used. GCD The timer and sub-threads perform data traversal processing, and call back the timing events in the main thread.

      //MARK: Creation of Timer
      -(void)createTimer {
      //0. Create queues
           dispatch_queue_t queue = self.queue;
           //1. Create timers in GCD
           /*
            First parameter: Create the source type DISPATCH_SOURCE_TYPE_TIMER: Timer
            Second parameter: 0
            Third parameter: 0
            The fourth parameter: queue
            */
           dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
            self.timer = timer;
           //2. Setting Timer
           /*
            First parameter: timer object
            The second parameter: DISPATCH_TIME_NOW indicates timing from now on
            Third parameter: the minimum unit of time in the interval GCD is nanoseconds
            Fourth parameter: accuracy (for allowable errors, 0 for absolute accuracy)
            */
           dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, self.countDownUnit * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
           //3. Tasks to be invoked
           dispatch_source_set_event_handler(timer, ^{
               NSLog(@"GCD-----%@",[NSThread currentThread]);
               dispatch_async(self.queue, ^{
                   [self lookingForATimelyModelArray:self.modelArray];
                   dispatch_async(dispatch_get_main_queue(), ^{
                       if (self.countdownDataFredbackWithBlock) {
                           self.countdownDataFredbackWithBlock();
                       }
                   });
               });
           });
           //4. Start execution
           dispatch_resume(timer);
      }
    3. Data Processing

      1.This method has been done in sub-threads, to the outside world. model The array is traversed. The remaining time is calculated.

      -(void)lookingForATimelyModelArray: (NSArray *)modelArray {
       [modelArray enumerateObjectsUsingBlock:^(id  _Nonnull model, NSUInteger idx, BOOL * _Nonnull stop) {
           //If it's still an array, it's convenient once.
           if ([[model class] isSubclassOfClass:NSClassFromString(@"NSArray")]) {
               self.column ++;
               [self lookingForATimelyModelArray:model];
           }
           //Judging the Types of Time Classes in model
           NSString *dateValue = [model valueForKey:self.modelDateKey];
           long long dateNumber = dateValue.longLongValue;       
           //If there is no time value
           if (!dateNumber) return;        
           //Determine whether time difference needs to be calculated
           if (self.modelDateType == PYContDownManagerModelDateType_OriginalTime){
               //Time difference calculation
              dateNumber = [self computationTimeDifferenceWithDateNumber:dateNumber];
           }
           //Determine whether timing is required
           if (dateNumber <= self.countdownStartTime) {
               if ([[model valueForKey:self.modelCountDownKey] isKindOfClass:NSClassFromString(@"NSString")]) {
                   [model setValue:@(dateNumber).description forKey:self.modelCountDownKey];
               }else if ([[model valueForKey:self.modelCountDownKey] isKindOfClass:NSClassFromString(@"NSNumber")]) {
                   [model setValue:@(dateNumber) forKey:self.modelCountDownKey];
               }
           }
       }];
      }
      //MARK: Calculation of Time Difference
      -(long long)computationTimeDifferenceWithDateNumber: (long long)dateNumber {   
       NSTimeInterval timeInterval = [self.clientTime timeIntervalSince1970];
       return (dateNumber - timeInterval);
      }

    4. Transfer Station Connecting with the Outside

    Outside incoming block code blocks are stored with attributes and invoked after each time interval

    // MARK: Interface for External Refresh UI
    - (void)countdownDataFredbackWithBlock: (void(^)())countdownDataFredbackWithBlock {
        self.countdownDataFredbackWithBlock = countdownDataFredbackWithBlock;
    }

    5. Cancel and Open Timer

    //MARK: Cancel Timer
    -(void)cancelTimer {
        dispatch_cancel(self.timer);
        self.timer = nil;
    }
    //MARK: Turn on the Timer
    -(void)resumeTimer {
        if (!self.timer) {
            [self createTimer];
        }
    }

    Source code please click here

    Keywords: Attribute less Mobile

    Added by eastcoastdubs on Sun, 07 Jul 2019 01:01:08 +0300