用另一种功能代替这个功能,要求是不改变旧的项目(也就是不改变原来方法的实现)。
可以在类的分类中,再写一个新的方法(是符合新的需求的),然后交换两个方法的实现。这样,在不改变项目的代码,而只是增加了新的代码 的情况下,就完成了项目的改进。
交换两个方法的实现一般写在类的load方法里面,因为load方法会在程序运行前加载一次,而initialize方法会在类或者子类在 第一次使用的时候调用,当有分类的时候会调用多次。
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 需求:给imageNamed方法提供功能,每次加载图片就判断下图片是否加载成功。
// 步骤一:先搞个分类,定义一个能加载图片并且能打印的方法+ (instancetype)imageWithName:(NSString *)name;
// 步骤二:交换imageNamed和imageWithName的实现,就能调用imageWithName,间接调用imageWithName的实现。
UIImage *image = [UIImage imageNamed:@"123"];
}
@end
@implementation UIImage (Image)
// 加载分类到内存的时候调用
+ (void)load
{
// 交换方法
// 获取imageWithName方法地址
Method imageWithName = class_getClassMethod(self, @selector(imageWithName:));
// 获取imageWithName方法地址
Method imageName = class_getClassMethod(self, @selector(imageNamed:));
// 交换方法地址,相当于交换实现方式
method_exchangeImplementations(imageWithName, imageName);
}
// 不能在分类中重写系统方法imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用super.
// 既能加载图片又能打印
+ (instancetype)imageWithName:(NSString *)name
{
// 这里调用imageWithName,相当于调用imageName
UIImage *image = [self imageWithName:name];
if (image == nil) {
NSLog(@"加载空的图片");
}
return image;
}
@end
类\对象的关联对象
关联对象不是为类\对象添加属性或者成员变量(因为在设置关联后也无法通过ivarList或者propertyList取得) ,而是为类添加一个相关的对象,通常用于存储类信息,例如存储类的属性列表数组,为将来字典转模型的方便。
使用方式一:给分类添加属性
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 给系统NSObject类动态添加属性name
NSObject *objc = [[NSObject alloc] init];
objc.name = @"小码哥";
NSLog(@"%@",objc.name);
}
@end
// 定义关联的key
static const char *key = "name";
@implementation NSObject (Property)
- (NSString *)name
{
// 根据关联的key,获取关联的值。
return objc_getAssociatedObject(self, key);
}
- (void)setName:(NSString *)name
{
// 第一个参数:给哪个对象添加关联
// 第二个参数:关联的key,通过这个key获取
// 第三个参数:关联的value
// 第四个参数:关联的策略
objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
使用方式二:给对象添加关联对象。
比如alertView,一般传值,使用的是alertView的tag属性。我们想把更多的参数传给alertView代理:
/**
* 删除点击
* @param recId 购物车ID
*/
- (void)shopCartCell:(BSShopCartCell *)shopCartCell didDeleteClickedAtRecId:(NSString *)recId
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"确认要删除这个宝贝" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
// 传递多参数
objc_setAssociatedObject(alert, "suppliers_id", @"1", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(alert, "warehouse_id", @"2", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
alert.tag = [recId intValue];
[alert show];
}
/**
* 确定删除操作
*/
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
NSString *warehouse_id = objc_getAssociatedObject(alertView, "warehouse_id");
NSString *suppliers_id = objc_getAssociatedObject(alertView, "suppliers_id");
NSString *recId = [NSString stringWithFormat:@"%ld",(long)alertView.ta