IOS pop-up priority scheduler: fgpopupscheduler

Time:2021-10-19

GitHub address: fgpopupscheduler
Support cocopods, easy to use and efficient basic components.

preface

According to the test feedback a few days ago, when a new user just opened the app, due to too many pop-up windows and a translucent guide layer, pop-up windows often cover each other and even block the normal process. To solve such problems, we not only need to clarify the dependencies between pop-up windows, but also need to deal with the conditions of pop-up windows themselves. And every time a new pop-up window is added, you need to check the logic of the previous pop-up window. Each step will consume development resources.

Therefore, our purpose is to solve how to split the dependencies between pop-up windows and display pop-up windows in turn at the right time.

requirement analysis

The first is the demand of the pop-up window itself

  • Pop up display
  • Pop up hidden
  • The pop-up window displays the conditions to be met

Then it’s about pop ups and pop ups

  • Pop up priority
  • Will pop ups be affected by the displayed pop ups

A feature of pop-up display is that only one pop-up window will be displayed at the same time, and can be displayed one by one. If you use queue management, you naturally need to deal with the behavior of insertion, deletion, emptying, traversal and so on.

This process seems to be solved, but in fact, when all pop-up windows are managed by one scheduler, we must consider when it is more reasonable to show / hide these pop-up windows.

Of course, fgpopupscheduler can help deal with these trivial things, and more than that.

Implementation analysis

Considering the diversity of pop-up window itself, it may not even be view. Therefore, the protocol is used to put the logical abstract processing of pop-up window into<FGPopupView>As long as the protocol is observed, it can be managed by the scheduler.

@protocol FGPopupView <NSObject>

@optional
/*
 Fgpopupschedulerstrategyqueue will listen to the display logic according to - showpopupview:, if it contains animation, please implement - showpopupviewwithanimation: method
 */
- (void)showPopupView;

/*
 Fgpopupschedulerstrategyqueue will listen to the hidden logic according to - disasspopupview:, if it contains animation, please implement the - showpopupviewwithanimation: method
 */
- (void)dismissPopupView;

/*
 Fgpopupschedulerstrategyqueue listens to the display logic according to - showpopupviewwithanimation:
 */
- (void)showPopupViewWithAnimation:(FGPopupViewAnimationBlock)block;

/*
 Fgpopupschedulerstrategyqueue will listen for hidden logic according to - disasspopupview:, if it contains animation, please implement - disasspopupviewwithanimation: method
 */
- (void)dismissPopupViewWithAnimation:(FGPopupViewAnimationBlock)block;

/**
 Fgpopupschedulerstrategyqueue will judge whether it can become the first priority popupview of the response when the queue order is its turn according to - canregisterfirstpopupview. The default is yes
 */
- (BOOL)canRegisterFirstPopupViewResponder;

@end

As for the order and priority of pop-up display, the actual operation will also involve the operation of Midway insertion or removal. The data structure is more similar to linked list, so the STL standard library of C + + is adopted here: list.

The specific strategies are as follows

typedef NS_ENUM(NSUInteger, FGPopupSchedulerStrategy) {
    Fgpopupschedulerstrategyfifo = 1 < < 0, // first in first out
    Fgpopupschedulerstrategylifo = 1 < < 1, // last in first out
    Fgpopupschedulerstrategypriority = 1 < < 2 // priority scheduling
};

In fact, users can also combineFGPopupSchedulerStrategyPriority | FGPopupSchedulerStrategyFIFOIt is used together to handle how to determine the sorting of the pop-up window of the same priority when selecting the priority policy.

adopthitTestTo solve the requirements of pop-up display conditions. If the pop-up fails according to the current hithitTest, the next pop-up window will be obtained in the current list for testing according to the selected scheduler policy.

- (PopupElement *)hitTestFirstPopupResponder{
    list<PopupElement*>::iterator itor = _list.begin();
    PopupElement *element;
    do {
        PopupElement *temp = *itor;
        id<FGPopupView> data = temp.data;
        __block BOOL canRegisterFirstPopupViewResponder = YES;
        if ([data respondsToSelector:@selector(canRegisterFirstPopupViewResponder)]) {
            dispatch_sync_main_safe(^(){
                canRegisterFirstPopupViewResponder = [data canRegisterFirstPopupViewResponder];
            });
        }
        if (canRegisterFirstPopupViewResponder) {
            element = temp;
            break;
        }
        itor++;
    } while (itor!=_list.end());
    return element;
}

Due to adoptionFGPopupSchedulerTo uniformly manage all pop-up windows, so the components need to handle the trigger on the pop-up window themselves. The author considered three trigger cases

  • When adding pop-up objects
  • Monitor the idle time of the main thread through runloop
  • User active trigger
    Through the above three cases, almost all usage scenarios can be covered.

In addition, the scheduler is addedsuspendedIn order to control whether the current scheduler can trigger, the active queue is hung up / restored.hitTestThen show the logic of.

In addition, the component supports thread safety. Considering that the timing of operation may be in any thread,Component passpthread_mutex_tTo ensure thread safety。 It is worth noting that the display process of pop-up window will be switched to the main thread, so there is no need for additional processing.
pthread_mutex_tAlthough it can be guaranteed that resources will not be occupied at the same time, it must be ensured that both locking and unlocking are in the same thread. Therefore, the component finally uses semaphores to replace mutexes for thread protection.

So far, the business of the whole component is relatively clear. Fgpopupscheduler adopts status mode,
Components need to allow these three processing methods to change freely, so the policy mode is adopted for processing. The following is the UML class diagram:

IOS pop-up priority scheduler: fgpopupscheduler