目标 c - Obj-C:if 语句和 NSString 比较函数,以提高效率和可读性


什么是

有效编码的最佳方法,因为它将被递归调用,并且创建大量对象是不好的。 +*-/, sin,cos,sqrt,pi and x,y,a,b应该放在三个独立的if statements中,不像现在一切都是分开的。同样为了可读性,制作包含 4 个isEqualToString的 if 语句也不是很好。

    NSString *operation = topOfStack;
    if ([operation isEqualToString:@"+"]) {
    } else if ([@"*" isEqualToString:operation]) {
    } else if ([operation isEqualToString:@"-"]) {
    } else if ([operation isEqualToString:@"/"]) {

    } else if ([operation isEqualToString:@"sin"]) {
    } else if ([operation isEqualToString:@"cos"]) {
    } else if ([operation isEqualToString:@"sqrt"]) {
    } else if ([operation isEqualToString:@"pi"]) {

    } else if ([operation isEqualToString:@"x"]) {
    } else if ([operation isEqualToString:@"y"]) {
    } else if ([operation isEqualToString:@"a"]) {
    } else if ([operation isEqualToString:@"b"]) {
    }
我不

相信有最好的方法可以做到这一点,但这里有另一种选择来补充已经给出的答案。

创建一个 NSDictionary,将您的操作名称(sin、sqrt、-)映射到选择器,如下所示:

NSDictionary *operations = @{
    @"sin": [NSValue valueWithPointer:@selector(operationSin:)],
    /* other operations here */
};

然后,您的 switch 语句将变为查找。

NSString *operation = topOfStack;
if(operations[operation]) {
    SEL op = [operations[operation] pointerValue];
    [self performSelector:op withObject:value];  /* Or some approximation thereof */
}
else {
    /* Default action for unknown operation */
}

或者,您可以在已识别的操作上创建一个枚举,使用 NSDictionary 将操作名称映射到 NSNumber 装箱您的枚举值。

typedef NS_ENUM(NSUInteger, OperationType) {
    OperationTypeSin = 0L,
    OperationTypeSqrt,
    /* and so on */
    OperationTypeUnknown
};
/* And later...  */
NSDictionary *operations = @{
    @"sin": @(OperationTypeSin),
    /* you get the idea */
};
/* Finally ... */
NSString *operation = topOfStack;
OperationType opType = [operations[operation] unsignedIntegerValue];
switch(opType) {
    case OperationTypeSin:
        /* Much cleaner, and type-safe too */
}

准备工作:
首先将 NSString 操作转换为 int 哈希代码,将该哈希代码存储在 #define或常量。

法典:

1) 将 NSString 操作转换为 int 哈希码 (tokenId)。
2) 然后在该令牌 ID 上执行一个开关语句。

int token = operationToToken(operation);
switch (token) {
case: OP_MINUS: break;
case: OP_SIN: break;
case: OP_COS: break;
}

首先,可以回退到 C 字符串,然后利用 sincossqrtpiabxy(几乎)都以不同的字符开头的事实:

const char *s = [operation UTF8String];
switch (s[0]) {
case '+':
    // addition
    break;
case '-':
    // subtraction
    break;
case 's':
    // sine or sqrt
    switch (s[1]) {
    case 'q':
        // sqrt
        break;
    case 'i':
        // sine
        break;
    }
    break;
case 'c':
    // cosine
    break;
// et cetera...
default:
    // not found
}

如果你使用的是Objective-C,那么你可以用一些名称巧妙的选择器来做到这一点。

首先,创建一个对象来封装Operation

然后,创建一个-initWithOperation:(NSString *)op方法。在此方法中,将任何符号操作(*+等)转换为唯一的字符串标识符(仅限字母)。

然后,您可以调用NSSelectorFromString(stringOp)尽管如果您希望方法具有参数,则必须自己附加:字符。

获得选择器

后,可以使用-performSelector:+performSelector:执行选择器,或手动调用选择器。

如果您使用与操作相同的名称命名每个选择器,则不需要任何ifswitch语句,但您必须处理发送无效选择器的情况。

例如:

@interface Operation : NSObject
- (id)initWithOperation:(NSString *)op;
- (void)performOperationWithValue:(float)value;
+ (float)sin:(float)value;
// ... Other operations
@property (nonatomic, copy) NSString *theOperation;
@end
@implementation Operation
- (id)initWithOperation(NSString *)op {
    self = [super init];
    if (self) {
        // Convert symbols to unique strings
        theOperation = [[NSString alloc] initWithString:op];
    }
    return self;
}
- (void)performOperationWithValue:(float)value {
    NSString *withOneParam = [self.theOperation stringByAppendingString:@":"];
    SEL sel = NSSelectorFromString(withOneParam);
    [Operation performSelector:withOneParam withObject:[NSNumber numberWithFloat:value]];
}
// Class methods are the actual operation implementation...

在上面的示例中,我假设您已将@"sin"传递给Operation对象。这只能在Objective-C中实现,因为您可以利用命名选择器。

您可以为每个符号分配一个数字,并可以实现开关情况。

最新更新