我正在构建一个可以连接到一系列底层对象属性的通用 UI,因此我想按名称调用 getter 和 setter。我尝试过使用 NSInvocation,也看到其他人使用 setValue:forKey
。但我想用最快的方法。
如果我持有对 NSInvocation 实例的引用,我可以非常快速地调用 invoke,但我有一个问题 - 如何使用它调用属性 setter ?像这样在 setter/getter 上效果很好:
SEL propSelector = NSSelectorFromString(propertyName);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[target class]instanceMethodSignatureForSelector:propSelector]];
[inv setSelector:propSelector];
[inv setTarget:target];
[inv invoke];
float value;
[inv getReturnValue:&value];
但我一直没能找到一种方法来为选择器赋值。使用 setArgument:atIndex:
似乎不起作用。
因此,我转而使用 setValue:forKey:
方法,但我担心随着时间的推移性能会迅速下降。
有什么想法吗?
最佳答案
我不完全理解您要实现的目标,但我已经快速测试了 valueForKey:
与您的调用方法的性能。在我的测试中,下面的代码 valueForKey:
几乎比 NSInvocation 方法快 5 倍。
- 1.620685 毫秒
- 30.357355 毫秒
- 7.593611 毫秒
代码:
#import <Foundation/Foundation.h>
#include <mach/mach_time.h>
@interface Foo : NSObject
{
NSNumber *value;
}
@property (nonatomic, retain) NSNumber *value;
@end
@implementation Foo
@synthesize value;
- (void) dealloc
{
[value release];
[super dealloc];
}
@end
#pragma mark MAIN
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// prepare loops
NSUInteger i;
NSUInteger max = 10000;
Foo *target = [[[Foo alloc] init] autorelease];
target.value = [NSNumber numberWithFloat:12.345f];
NSString *valueKey = @"value";
// prepare mach timebase
mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
double ticksToNanoseconds = (double)timebase.numer / timebase.denom;
// old-fashioned
uint64_t startTime = mach_absolute_time();
for (i = 0; i < max; i++) {
NSNumber *numValue = [target valueForKey:valueKey];
}
uint64_t elapsedTime = mach_absolute_time() - startTime;
double elapsedTimeInNanoseconds = elapsedTime * ticksToNanoseconds;
NSLog(@"1: %f millisec", elapsedTimeInNanoseconds / 1000000);
// invocation
startTime = mach_absolute_time();
for (i = 0; i < max; i++) {
SEL propSelector = NSSelectorFromString(valueKey);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[target class] instanceMethodSignatureForSelector:propSelector]];
[inv setSelector:propSelector];
[inv setTarget:target];
[inv invoke];
NSNumber *numValue;
[inv getReturnValue:&numValue];
}
elapsedTime = mach_absolute_time() - startTime;
elapsedTimeInNanoseconds = elapsedTime * ticksToNanoseconds;
NSLog(@"2: %f millisec", elapsedTimeInNanoseconds / 1000000);
// reused invocation
SEL propSelector = NSSelectorFromString(valueKey);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[target class] instanceMethodSignatureForSelector:propSelector]];
startTime = mach_absolute_time();
for (i = 0; i < max; i++) {
[inv setSelector:propSelector];
[inv setTarget:target];
[inv invoke];
NSNumber *numValue;
[inv getReturnValue:&numValue];
}
elapsedTime = mach_absolute_time() - startTime;
elapsedTimeInNanoseconds = elapsedTime * ticksToNanoseconds;
NSLog(@"3: %f millisec", elapsedTimeInNanoseconds / 1000000);
// clean and return
[pool drain];
return 0;
}
关于objective-c - 按名称调用 Property setter 的最佳方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4549815/