假设你展示了一个 ObjC 类:
@interface MCADictionaryHolder : NSObject
@property (nonatomic) NSDictionary<NSString *, id> * _Nonnull objects;
- (void)randomise:(NSInteger)upperBound;
- (id _Nullable)itemForKey:(NSString * _Nonnull)key;
@end
@implementation MCADictionaryHolder
- (instancetype)init
{
self = [super init];
if (self) {
self.objects = [[NSDictionary alloc] init];
}
return self;
}
-(void)randomise:(NSInteger)upperBound {
NSMutableDictionary * d = [[NSMutableDictionary alloc] initWithCapacity:upperBound];
for (NSInteger i = 0; i < upperBound; i++) {
NSString *inStr = [@(i) stringValue];
[d setObject:inStr forKey:inStr];
}
self.objects = [[NSDictionary alloc] initWithDictionary:d];
}
-(id)itemForKey:(NSString *)key {
id value = [self.objects objectForKey:key];
return value;
}
@end
假设您启动了类似于如下所示的性能测试:
class NSDictionaryToDictionaryBridgingTests: LogicTestCase {
func test_default() {
let bound = 2000
let keys = (0 ..< bound).map { "\($0)" }
var mutableDict: [String: Any] = [:]
for key in keys {
mutableDict[key] = key
}
let dict = mutableDict
let holder = MCADictionaryHolder()
holder.randomise(bound)
benchmark("Access NSDictionary via Swift API") {
for key in keys {
let value = holder.objects[key]
_ = value
}
}
benchmark("Access NSDictionary via NSDictionary API") {
let nsDict = holder.objects as NSDictionary
for key in keys {
let value = nsDict.object(forKey: key)
_ = value
}
}
benchmark("Access NSDictionary via dedicated method") {
for key in keys {
let value = holder.item(forKey: key)
_ = value
}
}
benchmark("Access to Swift Dictionary via Swift API") {
for key in keys {
let value = dict[key]
_ = value
}
}
}
}
然后性能测试将显示类似于下图的结果:
Access NSDictionary via Swift API:
.......... 1103.655ms ± 9.358ms (mean ± SD)
Access NSDictionary via NSDictionary API:
.......... 0.263ms ± 0.001ms (mean ± SD)
Access NSDictionary via dedicated method:
.......... 0.335ms ± 0.002ms (mean ± SD)
Access to Swift Dictionary via Swift API:
.......... 0.174ms ± 0.001ms (mean ± SD)
从结果可以看出:
- 通过 Swift API 访问 Swift Dictionary 可以获得最快的结果。
- 在 Swift 端通过 NSDictionary API 访问 NSDictionary 有点慢,但可以接受。
因此,无需创建专用方法来对NSDictionary 执行操作,只需将[AnyHashable: Any] 转换为NSDictionary 并执行所需的操作即可。
更新
在某些情况下,通过便捷的方法或属性访问 ObjC 是值得的,以最小化 ObjC Swift 之间的跨界成本。
假设你有一个 ObjC 扩展,如下所示:
@interface NSAppearance (MCA)
-(BOOL)mca_isDark;
@end
-(BOOL)mca_isDark {
if ([self.name isEqualToString:NSAppearanceNameDarkAqua]) {
return true;
}
if ([self.name isEqualToString:NSAppearanceNameVibrantDark]) {
return true;
}
if ([self.name isEqualToString:NSAppearanceNameAccessibilityHighContrastDarkAqua]) {
return true;
}
if ([self.name isEqualToString:NSAppearanceNameAccessibilityHighContrastVibrantDark]) {
return true;
}
return false;
}
@end
假设您启动了类似于如下所示的性能测试:
class NSStringComparisonTests: LogicTestCase {
func isDarkUsingSwiftAPI(_ a: NSAppearance) -> Bool {
switch a.name {
case .darkAqua, .vibrantDark, .accessibilityHighContrastDarkAqua, .accessibilityHighContrastVibrantDark:
return true
default:
return false
}
}
func isDarkUsingObjCAPI(_ a: NSAppearance) -> Bool {
let nsName = a.name.rawValue as NSString
if nsName.isEqual(to: NSAppearance.Name.darkAqua) {
return true
}
if nsName.isEqual(to: NSAppearance.Name.vibrantDark) {
return true
}
if nsName.isEqual(to: NSAppearance.Name.accessibilityHighContrastDarkAqua) {
return true
}
if nsName.isEqual(to: NSAppearance.Name.accessibilityHighContrastVibrantDark) {
return true
}
return false
}
func test_default() {
let appearance = NSAppearance.current!
let numIterations = 1000000
benchmark("Compare using Swift API", numberOfIterations: numIterations) {
let value = isDarkUsingSwiftAPI(appearance)
_ = value
}
benchmark("Compare using ObjC API", numberOfIterations: numIterations) {
let value = isDarkUsingObjCAPI(appearance)
_ = value
}
benchmark("Compare using ObjC convenience property", numberOfIterations: numIterations) {
let value = appearance.mca_isDark()
_ = value
}
}
}
然后性能测试将显示类似于下图的结果:
Compare using Swift API:
.......... 813.347ms ± 7.560ms (mean ± SD)
Compare using ObjC API:
.......... 534.337ms ± 1.065ms (mean ± SD)
Compare using ObjC convenience property:
.......... 142.729ms ± 0.197ms (mean ± SD)
从结果可以看出,通过便捷方式从 ObjC 世界中获取信息是最快的解决方案。