iOS開發基礎136-防暴力點選

Mr.陳發表於2024-07-23

要在Objective-C中建立一個高度可複用的工具類,以防止按鈕的暴力點選,並且使用切面程式設計(AOP)的方式,我們可以考慮使用Aspects這個庫來實現方法的攔截。以下是具體的實現步驟:

第一步:引入Aspects庫

首先,需要將Aspects整合到專案中。Aspects是一個輕量級的AOP框架,允許你在執行時攔截類的例項方法和類方法。你可以透過CocoaPods來新增此庫:

pod 'Aspects'

第二步:建立UIButton的Category

接下來,建立一個UIButton的Category,用於新增防暴力點選的邏輯。

UIButton+PreventSpam.h:

#import <UIKit/UIKit.h>

@interface UIButton (PreventSpam)

// 設定間隔時間,進行防暴力點選設定
- (void)setPreventSpamInterval:(NSTimeInterval)interval;

@end

UIButton+PreventSpam.m:

#import "UIButton+PreventSpam.h"
#import <objc/runtime.h>
#import <Aspects/Aspects.h>

static const char *UIButton_preventSpamIntervalKey = "UIButton_preventSpamIntervalKey";

@implementation UIButton (PreventSpam)

- (void)setPreventSpamInterval:(NSTimeInterval)interval {
    objc_setAssociatedObject(self, UIButton_preventSpamIntervalKey, @(interval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    // 使用Aspects進行方法攔截
    [self aspect_hookSelector:@selector(sendAction:to:forEvent:) withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo> aspectInfo, SEL action, id target, UIEvent *event) {
        UIButton *button = aspectInfo.instance;
        if (button.isIgnoring) {
            return;
        }
        button.isIgnoring = YES;

        // 執行原始的 sendAction:to:forEvent: 方法
        // 這裡直接呼叫原始方法是不合適的,因為這是一個攔截後的block,我們要重新invoke original invocation
        [[aspectInfo originalInvocation] invoke];
        
        // 延遲間隔時間後,重置為可以點選
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            button.isIgnoring = NO;
        });
    } error:NULL];
}

// 判斷當前是否應該忽略點選,透過關聯物件新增屬性
- (void)setIsIgnoring:(BOOL)isIgnoring {
    objc_setAssociatedObject(self, @selector(isIgnoring), @(isIgnoring), OBJC_ASSOCIATION_ASSIGN);
}

- (BOOL)isIgnoring {
    return [objc_getAssociatedObject(self, @selector(isIgnoring)) boolValue];
}

@end

使用

在適當的位置設定按鈕的點選間隔:

#import "UIButton+PreventSpam.h"

[myButton setPreventSpamInterval:1.0]; // 點選間隔設定為1秒

注意

  1. 本示例使用了Aspects庫進行方法的攔截,這是一種執行時AOP的技巧。這裡利用了Objective-C的動態特性。AOP可以幫助增加程式碼的可維護性和可複用性,但它也會增加程式碼的複雜性,使用時需要權衡。

  2. 使用關聯物件(objc_setAssociatedObjectobjc_getAssociatedObject)來給UIButton動態新增屬性,用於儲存是否應該忽略點選和間隔時間,這是Objective-C擴充套件現有類功能的常用技巧。

  3. 在實際專案中,可能需要考慮多種情況和細節,如處理快速切換介面時按鈕點選事件的響應等。

相關文章