美文网首页
使用 Runtime 禁止 UIAlertController

使用 Runtime 禁止 UIAlertController

作者: ft6206 | 来源:发表于2019-07-05 18:04 被阅读0次

    项目里需要增加强制更新功能,此时使用的是系统的UIAlertController,结果点击跳转到App Store之后,弹框就消失了,这是因为系统默认会自己dismiss,所以需要自己加个变量可以控制是否dismiss。

    
    @dynamicft_rejectDismiss;
    
    - (void)setFt_rejectDismiss:(BOOL)ft_rejectDismiss {
    
        objc_setAssociatedObject(self, @selector(ft_rejectDismiss), @(ft_rejectDismiss), OBJC_ASSOCIATION_ASSIGN);
    
    }
    
    - (BOOL)ft_rejectDismiss {
    
        return [(NSNumber *)objc_getAssociatedObject(self, _cmd) boolValue];
    
    }
    
    + (void)load {
    
        static dispatch_once_t onceToken;
    
        dispatch_once(&onceToken, ^{
    
            Classclass = [selfclass];
    
            SEL originalSelector = NSSelectorFromString(@"_dismissAnimated:triggeringAction:triggeredByPopoverDimmingView:dismissCompletion:");
    
            SELswizzledSelector =@selector(ft_dismissAnimated:
    
                                             triggeringAction:
    
                                             triggeredByPopoverDimmingView:
    
                                             dismissCompletion:);
    
            MethodoriginalMethod =class_getInstanceMethod(class, originalSelector);
    
            MethodswizzledMethod =class_getInstanceMethod(class, swizzledSelector);
    
            // 动态添加方法,如果类中不存在这个方法的实现,则添加成功
    
            // 这里 UIAlertController 类中存在 originalMethod,所以添加是失败的
    
            BOOLdidAddMethod =class_addMethod(class,
    
                                                originalSelector,
    
                                                method_getImplementation(swizzledMethod),
    
                                                method_getTypeEncoding(swizzledMethod));
    
            if(didAddMethod) {
    
                // 如果添加成功,则用 originalMethod 替换添加的空方法 originalMethod
    
                class_replaceMethod(class,
    
                                    swizzledSelector,
    
                                    method_getImplementation(originalMethod),
    
                                    method_getTypeEncoding(originalMethod));
    
            }else{
    
                // 交换两个方法的实现
    
                method_exchangeImplementations(originalMethod, swizzledMethod);
    
            }
    
        });
    
    }
    
    - (void)ft_dismissAnimated:(BOOL)animation
    
              triggeringAction:(UIAlertAction*)action
    
    triggeredByPopoverDimmingView:(id)view
    
             dismissCompletion:(id)handler {
    
        // 如果点击“取消”按钮或者允许弹框 dismiss,就调用原来的方法(originalMethod)
    
        // 因为已经交换了两个方法的实现,所以其实是调用 swizzledMethod
    
        // 所以这里并不会出现循环调用
    
        // 否则就忽略原来的方法(originalMethod),直接下一步,掉用后面的方法
    
        if (action.style == UIAlertActionStyleCancel || self.ft_rejectDismiss == NO) {
    
            [self ft_dismissAnimated:animation
    
                    triggeringAction:action
    
       triggeredByPopoverDimmingView:view
    
                   dismissCompletion:handler];
    
        }else{
    
            SEL invokeHandler = NSSelectorFromString(@"_invokeHandlersForAction:");
    
            // 这里如果使用 performSelector 来调 invokeHandler 这个方法
    
            // [self performSelector:invokeHandler withObject:action];
    
            // 会报 "PerformSelector may cause a leak because its selector is unknown" 的警告
    
            // 为消除警告,用下面的方法
    
            IMPimp = [selfmethodForSelector:invokeHandler];
    
            void(*func)(id,SEL,UIAlertAction*) = (void*)imp;
    
            func(self, invokeHandler, action);
    
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:使用 Runtime 禁止 UIAlertController

          本文链接:https://www.haomeiwen.com/subject/vyxyhctx.html