1

我想创建一个 UIImage 类的类别,它将有自己的处理

(UIImage*) imageNamed:(NSString*) name

方法将为我保存名称作为创建图像的属性。为此,我为此方法创建了一个 swizzle,并为它的 setter 和 getter 创建了对我新添加的属性的关联引用。最后实现看起来像这样:

@interface UIImage (MTReady)

@property(assign) NSString* imageName;

-(NSString*) getImageName;

@end

NSString * const imageNameKey = @"imageNameKey";

@implementation UIImage (MTReady)
@dynamic imageName;

-(NSString *)getImageName {
    NSString* name = objc_getAssociatedObject(self, &imageNameKey);
    return name;
}

-(void) setImageName:(NSString *)name {
    objc_setAssociatedObject(self, &imageNameKey, name, OBJC_ASSOCIATION_ASSIGN);
}

+(void)load {
    if(self == [UIImage class]) {
        Method originalImageNamed, swizzledImageNamed;

        originalImageNamed = class_getClassMethod(self, @selector(imageNamed:));
        swizzledImageNamed = class_getClassMethod(self, @selector(swizzledImageNamed:));
        method_exchangeImplementations(originalImageNamed, swizzledImageNamed);
    }
}

+(UIImage *)swizzledImageNamed:(NSString*) name {
    UIImage* image = [self swizzledImageNamed:name];

    if(image)
        [image setImageName:name];
    return image;
}

@end

这个解决方案似乎不起作用,因为每当我在使用方法imageNamed创建的 UIImage 上调用getImageName时,我总是得到nil。我目前不知道为什么会发生这种情况。我的实施中有什么遗漏吗?

4

1 回答 1

0

问题是

  objc_setAssociatedObject(self, &imageNameKey, name, OBJC_ASSOCIATION_ASSIGN);

应该

 objc_setAssociatedObject(self, &imageNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);

或者

 objc_setAssociatedObject(self, &imageNameKey, name, OBJC_ASSOCIATION_COPY);

不要使用OBJC_ASSOCIATION_RETAINor OBJC_ASSOCIATION_RETAIN_NONATOMIC,因为字符串可能是可变的。与您将字符串属性声明为副本而不是强属性的原因完全相同。

当我测试下面的代码时,关联的设置和检索正确。

@implementation UIImage (Name)

static char const imageNameKey;

-(NSString *)getImageName {
  NSString* name = objc_getAssociatedObject(self, &imageNameKey);
  return name;
}

-(void) setImageName:(NSString *)name {
  objc_setAssociatedObject(self, &imageNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

+(void)load {
  if(self == [UIImage class]) {
    Method originalImageNamed, swizzledImageNamed;

    originalImageNamed = class_getClassMethod(self, @selector(imageNamed:));
    swizzledImageNamed = class_getClassMethod(self, @selector(swizzledImageNamed:));
    method_exchangeImplementations(originalImageNamed, swizzledImageNamed);
 }
}

+(UIImage *)swizzledImageNamed:(NSString*) name {
  UIImage* image = [self swizzledImageNamed:name];

  if(image)
    [image setImageName:name];
  return image;
}

@end
于 2014-08-11T19:07:30.483 回答