繁体   English   中英

UIImage imageNamed扩展

[英]UIImage imageNamed extension

我最近在我的应用中发现了一个很大的性能问题,这是由于在[UIImage imagenamed:]中找不到图像。

我想知道是否有一种“嵌入式”解决方案以某种方式记录这种“错误”? 我开始为UIImage类编写扩展,如下所示:

@implementation UIImage (Debug)
#ifdef DEBUG
+ (UIImage*) imageNamed:(NSString*) name{
    UIImage* img = [UIImage imageNamed:name];

    if(!img){
        NSLog(@"Error: referencing non-exiting image: %@", name);
    }

    return img;
}
#endif
@end

但这会导致无限循环,因为[UIImage imageNamed:name]当然会导致再次调用扩展方法...

有什么建议么?

谢谢托马斯

永远不要使用类别来覆盖现有方法 这将导致意外的结果(使用的实现取决于运行时加载二进制映像/模块的顺序)

相反,您可以使用objc运行时的可能性将一个选择器的实现与另一个选择器交换(有时称为方法swizzling )。 但是如果你真的不知道含义的话,我会劝阻你这么做 (如果要调用原始方法以避免调用循环,请调用swapped方法,当方法在父类而不是子类中实现时管理用例,以及更多的微妙之处)


但是,如果您只想调试并在未找到UIImage时收到警告,请使用符号断点 (断点不限于放在给定的代码行上 !)

断点的功能超出了您的想象(我鼓励您观看WWDC'11视频会议,了解“在Xcode中掌握调试”),尤其是可以将断点放置在代码的特定行上,而不是代码的特定行 (在您的情况下为方法-imageNamed: ,并向断点添加一个条件,以便仅在特定条件下才将其命中(返回图像nil?)。 您甚至可以要求断点记录一些信息 (或播放声音或其他内容)和/或继续执行,而不是停止执行代码。

您想要做的事情称为swizzling :您交换了两个方法,因此现在调用了您自己的方法,并且可以在您的方法名下访问原始方法。 一开始似乎有些混乱,但是这是它的工作原理:

#import <objc/runtime.h>    

@implementation UIImage(Debug)

// Executed once on startup, before anything at UIImage is called.
+ (void)load
{
    Class c = (id)self;

    // Use class_getInstanceMethod for "normal" methods
    Method m1 = class_getClassMethod(c, @selector(imageNamed:));
    Method m2 = class_getClassMethod(c, @selector(swizzle_imageNamed:));

    // Swap the two methods.
    method_exchangeImplementations(m1, m2);
}

+ (id)swizzle_imageNamed:(NSString *)name
{
    // Do your stuff here. By the time this is called, this method
    // is actually called "imageNamed:" and the original method
    // is now "swizzle_imageNamed:".

    doStuff();
    // Call original method
    id foo = [self swizzle_imageNamed:name];
    doMoreStuff();
    return something;
}

@end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM