objective-c - 按名称调用 Property setter 的最佳方式是什么?

标签 objective-c

我正在构建一个可以连接到一系列底层对象属性的通用 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. 1.620685 毫秒
  2. 30.357355 毫秒
  3. 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/

相关文章:

ios - 应用程序在 tableview 的 reloadData 方法上崩溃

iphone - "pointInside:"是如何工作的?

ios - UIProgressView不显示进度

iphone - Obj-c,在没有核心数据的情况下,执行许多 SQLite 插入/更新查询的最快方法是什么?

iphone - 将坐标从 iPhone 屏幕尺寸转换为 iPad 屏幕尺寸

ios - 使用全局常量时体系结构的重复符号

c++ - 从 C++ 类调用 Objective C 实例方法?

objective-c - 三元条件运算符中的赋值产生 “Expression is not assignable”错误

ios - Table View Press,如何到 "let go"的按钮?

objective-c - 根据字符串的长度更新 NSTextField 的宽度