給UIButton添加塊(Block)

今天簡單的記錄一下怎么用塊來實現(xiàn)Button的點擊事件

首先,我想要的做的效果是直接通過類方法來初始化Button,然后同時把點擊事件的操作放在塊中,最后返回創(chuàng)建好的Button。

  • 第一步,創(chuàng)建一個UIButton的擴展(category)
  • 第二步,在h文件中添加初始化Button的類方法聲明
#import <UIKit/UIKit.h>

typedef void (^ActionBlock)(UIButton *button);

@interface UIButton (Block)

@property (nonatomic,copy) ActionBlock actionBlock;

/**
 通過block對Button的點擊事件進行封裝
 
 @param frame frame大小
 @param title 內(nèi)容
 @param titleColor 內(nèi)容顏色
 @param bgImgName 背景圖片
 @param completion 點擊事件
 @return Button
 */
+ (UIButton *)createButtonWithFrame:(CGRect)frame
                              title:(NSString *)title
                         titleColor:(UIColor *)titleColor
                        bgImageName:(NSString *)bgImgName
                        actionBlock:(void(^)(UIButton *sender))completion;


/**
 通過block對Button的點擊事件進行封裝

 @return 返回初始化后的button
 */
+ (UIButton *)button;

@end

  • 第三步,在m文件中實現(xiàn)方法
#import "UIButton+Block.h"
#import <objc/runtime.h>

static NSString *keyWithMethod = @"keyWithMethod"; //關聯(lián)對象的key
static NSString *keyWithBlock = @"keyWithBlock";

@implementation UIButton (Block)

+ (UIButton *)createButtonWithFrame:(CGRect)frame
                              title:(NSString *)title
                         titleColor:(UIColor *)titleColor
                        bgImageName:(NSString *)bgImgName
                        actionBlock:(void (^)(UIButton *sender))completion {
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame = frame;
    [button setTitle:title forState:UIControlStateNormal];
    [button setTitleColor:titleColor forState:UIControlStateNormal];
    [button setBackgroundImage:[UIImage imageNamed:bgImgName] forState:UIControlStateNormal];
    [button addTarget:button action:@selector(buttonTapAction:) forControlEvents:UIControlEventTouchUpInside];
    
    /*
     *用runtime中的函數(shù)通過key關聯(lián)對象
     *
     *objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
     *id object                 表示關聯(lián)者,是一個對象,變量名也是object
     *const void *key           獲取被關聯(lián)者的索引
     *id value                  被關聯(lián)者,這里是一個block
     *objc_AssociationPolicy    policy 關聯(lián)時采用的協(xié)議,有assign,retain,copy等協(xié)議,一般使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
     */
    objc_setAssociatedObject(button, &keyWithMethod, completion, OBJC_ASSOCIATION_COPY_NONATOMIC);
    
    return button;
}

+ (UIButton *)button {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:button action:@selector(buttonTapAction:) forControlEvents:UIControlEventTouchUpInside];
    return button;
}

- (void)setActionBlock:(ActionBlock)actionBlock{
    objc_setAssociatedObject(self, &keyWithBlock, actionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC );
}

- (ActionBlock)actionBlock{
    return objc_getAssociatedObject(self ,&keyWithBlock);
}

- (void)buttonTapAction:(UIButton *)button {
    //通過key獲取被關聯(lián)對象
    //objc_getAssociatedObject(id object, const void *key)
    void (^tapBlock)(UIButton *) = objc_getAssociatedObject(button, &keyWithMethod);
    
    if (tapBlock) {
        tapBlock(button);
    }
 
    ActionBlock block2 = (ActionBlock)objc_getAssociatedObject(button, &keyWithBlock);
    if(block2){
        block2(button);
    }
}

@end
  • 第四步,簡單的使用
UIButton *button = [UIButton createButtonWithFrame:CGRectMake(20, 100, 200, 200) title:@"帶塊的button" titleColor:[UIColor redColor] bgImageName:@"" actionBlock:^(UIButton *button) {
        NSString *str = [button titleForState:UIControlStateNormal];
        NSLog(@"%@",str);
}];
[self.view addSubview:button];

UIButton *btn = [UIButton button];
btn.frame = CGRectMake(20, 100, 200, 200);
[btn setTitle:@"1234" forState:UIControlStateNormal];
btn.actionBlock = ^(UIButton *button) {
    NSString *str = [button titleForState:UIControlStateNormal];
    NSLog(@"%@",str);
};
[self.view addSubview:btn];

注意:由于擴展不能直接添加屬性,所以要用運行時來自己添加屬性的get、set方法。

最后,簡單的了解一下objc_setAssociatedObjectobjc_getAssociatedObject方法

? Objective-C有兩個擴展機制:AssociativeCategory。Category用來擴展類方法,Associative用于擴展屬性。Associative機制的原理是把兩個對象關聯(lián)起來,讓一個對象成為另外一個對象的一部分。它可以在不修改類的定義的前提下為其對象增加存儲空間,這在我們無法訪問類的源碼時(例如給UILable添加一個selected的BOOL屬性)是非常有用的。Associative基于關鍵字的,因此我們可以使用不同的關鍵字為任何對象添加任意多的AssociativeAssociative可以保證被關聯(lián)的對象在對象的整個生命周期都是可用的。Associative基于runtime,是運行時里的東西,所以頭文件需要引用#im port<objc/runtime.h>文件。

Associative提供了3個方法

- objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
- objc_getAssociatedObject(id object, const void *key)
- objc_removeAssociatedObjects(id object)

第一個用于給關聯(lián)對象賦值:

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)注意的是返回值類型為Object類型,注意一些不是Object類型的例如:BOOL是結構類型。當碰到這種情況可以考慮通過中間類型來轉換,如設置BOOL類型屬性的時候可以轉換為NSNumber類型,獲取的時候再轉換成BOOL類型即可。
四個參數(shù)分別是:源對象、關鍵字、關聯(lián)對象和關聯(lián)策略。
關鍵字是一個void類型的指針,例如static NSString *keyWithMethod = @"keyWithMethod"; //關聯(lián)對象的key每一個關聯(lián)的關鍵字必須是唯一的。

關聯(lián)策略是枚舉類型,如下:

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                            *   The association is made atomically. */
    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                            *   The association is made atomically. */
};

第二個用于獲取關聯(lián)的對象:

objc_getAssociatedObject(id object, const void *key)用于獲取關聯(lián)對象的值。這里需要注意的是返回值類型為Object類型,注意一些不是Object類型的例如:BOOL是結構類型。

第三個用于斷開關聯(lián)的對象:

objc_removeAssociatedObjects(id object) 是斷開關聯(lián),需要注意的是它會斷開所有關聯(lián),所以不推薦這種方式。需要斷開關聯(lián)的時候使用objc_setAssociatedObject函數(shù),傳入nil值即可。

斷開關聯(lián)是使用objc_setAssociatedObject函數(shù),傳入nil值即可。
使用函數(shù)objc_removeAssociatedObjects可以斷開所有關聯(lián)

慢慢來,一步一個巴掌印~~~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容