今天簡單的記錄一下怎么用塊來實現(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_setAssociatedObject,objc_getAssociatedObject方法
? Objective-C有兩個擴展機制:Associative和Category。Category用來擴展類方法,Associative用于擴展屬性。Associative機制的原理是把兩個對象關聯(lián)起來,讓一個對象成為另外一個對象的一部分。它可以在不修改類的定義的前提下為其對象增加存儲空間,這在我們無法訪問類的源碼時(例如給UILable添加一個selected的BOOL屬性)是非常有用的。Associative基于關鍵字的,因此我們可以使用不同的關鍵字為任何對象添加任意多的Associative。Associative可以保證被關聯(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)
慢慢來,一步一個巴掌印~~~