使用 Objective-C 中单例的标准模式,ARC 仍然会在每次使用单例时自动生成保留和释放调用,即使我们知道该对象永远不会被释放。在性能敏感的代码中,这些 ARC 生成的调用会导致大量的额外开销。有没有办法告诉编译器不要为单例生成保留/释放代码?
就我而言,我正在编写一个性能敏感的日语文本解析器。作为解析的一部分,我经常需要访问汉字字符的 NSCharacterSet,我已在 NSCharacterSet 的类别中定义了该字符集。
+ (id)kanjiCharacterSet
{
static NSCharacterSet* kanjiCharacterSet = nil;
static dispatch_once_t onceToken;
dispatch_once( &onceToken, ^
{
NSRange range = { .location = 0x4e00, .length = 0x9faf - 0x4e00 };
kanjiCharacterSet = [NSCharacterSet characterSetWithRange:range];
} );
return kanjiCharacterSet;
}
访问此字符集最常见的地方之一是检查字符串中是否存在汉字字符。此代码位于 NSString 的类别中。
- (BOOL)containsKanji
{
return [self rangeOfCharacterFromSet:[NSCharacterSet kanjiCharacterSet]].location != NSNotFound;
}
当我通过探查器运行此操作时,[NSString containsKanji]
花费的全部时间中大约 40% 是在保留/释放代码中。至于[NSCharacterSet kanjiCharacterSet]
,除了我们实际生成字符集的第一个调用之外,每个调用大约有80%的时间花在保留/释放代码上。
如果我在objc_retain
、obj_release
和objc_autorelease
中设置断点,我可以看到一个retain和一个autorelease被添加到[NSCharacterSet kanjiCharacterSet]
的 return 语句,当收到 [NSCharacterSet kanjiCharacterSet]
返回的值时,在 [NSString containsKanji]
中添加一个保留,当我们从 [NSString containsKanji]
返回时,将添加一个版本。似乎所有这些调用对于单例来说都是不必要的。有没有办法告诉编译器不要生成这些调用?
我找到了一种解决方法,即向 [NSString containsKanji]
添加一个静态变量来存储字符集,但我很想找到一个更通用的解决方案。
最佳答案
在重复调用 kanjiCharacterSet 的方法中,缓存一个副本。显然,只有当性能至关重要时才应该做这种事情。
- (BOOL)containsKanji
{
static NSCharacterSet* cachedKanji = nil;
static dispatch_once_t onceToken;
dispatch_once (&onceToken, ^{
cachedKanji = [NSCharacterSet kanjiCharacterSet];
});
return [self rangeOfCharacterFromSet: cachedKanji].location != NSNotFound;
}
关于objective-c - 如何使用 ARC 优化 Objective-C 单例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21846871/