//iOS 给原生类(如:UIButton类)拓展一个Block成员属性
//iOS,Block,Category,runtime
/*
用网上的方法可以实现用category加一般的属性,但是加Block属性后有问题(估计是内存管理的问题)
备注:Block里面只打印或者简单的画UI是OK的,一旦用到Viewcontroller、Viewcontroller属性或者Block外的变量就会crash
以下代码分别是
①、UIbutton的category申明文件(.h文件)部分代码
②、UIbutton的category实现文件(.m文件)部分代码
③、ViewController中使用UIbutton的拓展方法和拓展属性Block
*/
///////////////////////////////////////////////////////////////////////////////
//----------------①----------------
#import
typedef void(^buttonHandler)(UIButton *sender);
@interface UIButton (Utility)
@property (nonatomic, copy) buttonHandler eventHandler;
#pragma mark - block button(handler+cacheMode+isResized) 图片不占内存+拉伸
/**
* block button(handler+cacheMode+isResized) 图片不占内存+拉伸
*
* @param frame coordinate and rectangle
* @param superview supperview
* @param title button tittle
* @param titleSelected titleSelected
* @param imageName imageName
* @param imageNameSelected imageNameSelected
* @param cacheMode 图片是否加载到内存
* @param isResized 图片是否拉伸
* @param handler handler
*
* @return button obj
*/
- (id)initWithFrame:(CGRect)frame
supperview:(UIView *)superview
title:(NSString *)title
titleSelected:(NSString *)titleSelected
image:(NSString *)imageName
imageNameSelected:(NSString *)imageNameSelected
ImageCacheMode:(ImageCacheMode)cacheMode
isResized:(ImageResized)isResized
actionHandler:(buttonHandler)handler;
@end
///////////////////////////////////////////////////////////////////////////////
//----------------②----------------
实现文件.m文件(部分代码)部分
#import "UIButton+Utility.h"
#import "Utility.h"
#import <objc/runtime.h>
static const void *UtilityKey = &UtilityKey;
@implementation UIButton (Utility)
#pragma mark - extension member
@dynamic eventHandler;
- (buttonHandler)eventHandler {
return objc_getAssociatedObject(self, UtilityKey);
}
- (void)setEventHandler:(buttonHandler)eventHandler {
objc_setAssociatedObject(self, UtilityKey, eventHandler, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)buttonPressed:(UIButton *)sender {
NSLog(@"buttonPressed:\nbtn===000:%@\nbtn===111:%@", sender, self);
if (self.eventHandler) {
self.eventHandler(sender);
}
}
#pragma mark - block button(handler+cacheMode+isResized) 图片不占内存+拉伸
/**
* block button(handler+cacheMode+isResized) 图片不占内存+拉伸
*
* @param frame coordinate and rectangle
* @param superview supperview
* @param title button tittle
* @param titleSelected titleSelected
* @param imageName imageName
* @param imageNameSelected imageNameSelected
* @param cacheMode 图片是否加载到内存
* @param isResized 图片是否拉伸
* @param handler handler
*
* @return button obj
*/
- (id)initWithFrame:(CGRect)frame
supperview:(UIView *)superview
title:(NSString *)title
titleSelected:(NSString *)titleSelected
image:(NSString *)imageName
imageNameSelected:(NSString *)imageNameSelected
ImageCacheMode:(ImageCacheMode)cacheMode
isResized:(ImageResized)isResized
actionHandler:(buttonHandler)handler {
self = [super initWithFrame:frame];
if (self) {
//set title
if (title) {
[self setTitle:title forState:UIControlStateNormal];
}
if (titleSelected) {
[self setTitle:titleSelected forState:UIControlStateSelected];
[self setTitle:titleSelected forState:UIControlStateHighlighted];
}
//set image
if (imageName) {
[self setBackgroundImage:getImageWithCacheAndResized(imageName, cacheMode, isResized) forState:UIControlStateNormal];
}
if (imageNameSelected) {
[self setBackgroundImage:getImageWithCacheAndResized(imageNameSelected, cacheMode, isResized) forState:UIControlStateSelected];
[self setBackgroundImage:getImageWithCacheAndResized(imageNameSelected, cacheMode, isResized) forState:UIControlStateHighlighted];
}
//set block
if (handler) {
self.eventHandler = handler;
//add action
[self addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
[superview addSubview:self];
[self release];
}
returnself;
}
@end
///////////////////////////////////////////////////////////////////////////////
//----------------③----------------
//ViewController中使用UIbutton的拓展方法和拓展属性Block
@interface ViewController ()
@end
@implementation ViewController
- (void)loadView {
[super loadView];
__block ViewController *vc = self;
NSString *sss = @"Block attribute";
[[UIButton alloc] initWithFrame:self.view.frame supperview:self.view title:nil titleSelected:nil image:@"common_dialog_new_bg" imageNameSelected:nil ImageCacheMode:ImageCacheModeNoCache isResized:ImageIsResized actionHandler:^(UIButton *sender) {
NSLog(@"blcokButton"); //只写这一行代码不会crash
NSLog(@"blcokButton:, %@", sss); //只写这行代码会crash
//用以下代码也会crash
SubViewController *subVC = [[SubViewController alloc] init];
[vc presentViewController:subVC animated:YES completion:nil];
[subVC release];
}];
}
@end
objc_setAssociatedObject(self, UtilityKey, eventHandler, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
这个方法中OBJC_ASSOCIATION_RETAIN_NONATOMIC用
OBJC_ASSOCIATION_COPY_NONATOMIC代替就没有内存管理的问题了