使用块的返回值动态创建字符串

时间:2014-03-17 15:07:44

标签: ios objective-c string objective-c-blocks

所以我试图动态构建一个字符串,我真的很喜欢构建这个字符串的所有代码都存在于作为参数传递给stringWithFormat方法的块中。以下代码示例应该演示我尝试实现的目标:

    NSString * deviceLanguage = [NSString stringWithFormat:@"Device Language: %@", ^NSString*(void){

        NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];

        NSString *locale = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];

        return [NSString stringWithFormat:@"%@_%@", language, locale];

    }];

预期的输出类似于......

Device Language: en_GB

但是,我从这个方法获得的输出实际上返回了NSGlobalBlock方法的description,例如

Device Language: <__NSGlobalBlock__:0x30a35c>

这是因为我没有在字符串中使用正确的占位符,或者没有声明该块返回NSString个对象吗?

3 个答案:

答案 0 :(得分:6)

那是因为你将块本身作为参数传递给stringWithFormat:, 而不是调用块的结果:

NSString * deviceLanguage = [NSString stringWithFormat:@"Device Language: %@", ^NSString*(void){

    NSLocale *locale = [NSLocale currentLocale];
    NSString *language = [locale displayNameForKey:NSLocaleIdentifier
                         value:[locale localeIdentifier]];
    return [NSString stringWithFormat:@"%@_%@", language, locale];

}()];

请注意,您可以使用"compound statement expression"获得类似的结果 而不是一个块:

NSString * deviceLanguage = [NSString stringWithFormat:@"Device Language: %@", ({

    NSLocale *locale = [NSLocale currentLocale];
    NSString *language = [locale displayNameForKey:NSLocaleIdentifier
                         value:[locale localeIdentifier]];
    [NSString stringWithFormat:@"%@_%@", language, locale];

})];

答案 1 :(得分:1)

这是一个很好的问题!

问题出在stringWithFormat:。当它处理它的格式字符串时,当它到达%@时,它会找到对象参数,在其上调用-description并将对象的描述添加到其中输出。这种情况下的描述是<__NSGlobalBlock__:0x30a35c>

你可以通过以下方式解决这个问题:

NSString*(^userLanguage)(void) = ^(void) {
    NSLocale *locale = [NSLocale currentLocale];

    NSString *language = [locale displayNameForKey:NSLocaleIdentifier
                                             value:[locale localeIdentifier]];

    return [NSString stringWithFormat:@"%@_%@", language, locale];

};
NSString *language = userLanguage();
NSString * deviceLanguage = [NSString stringWithFormat:@"Device Language: %@", language];

但当然你现在不需要这个块,所以你可以这样做:

NSLocale *locale = [NSLocale currentLocale];
NSString *language = [locale displayNameForKey:NSLocaleIdentifier
                                         value:[locale localeIdentifier]];
NSString *userLanguage = [NSString stringWithFormat:@"%@_%@", language, locale];;
NSString * deviceLanguage = [NSString stringWithFormat:@"Device Language: %@", userLanguage];

答案 2 :(得分:1)

因为您正在将块对象传递给stringWithFormat:所以您正在打印描述。如在@MartinR答案。 如果您按照这样重新编码,就可以更轻松地管理您的块。

// first you declare a block like this, to retain it or pass it multiple times
typedef NSString* (^MyBlock)(void);

       MyBlock block = ^{
        NSLocale *locale = [NSLocale currentLocale];
        NSString *language = [locale displayNameForKey:NSLocaleIdentifier
                                                 value:[locale localeIdentifier]];
                                   // print the local id
        return [NSString stringWithFormat:@"%@_%@", language, locale.localeIdentifier];
    }; 

// Now pass it to stringWithFormat:
NSString *deviceLanguage = [NSString stringWithFormat:@"device language: %@", block()];