【问题标题】:CFLocaleCopyCurrent stale valueCFLocaleCopy当前陈旧值
【发布时间】:2020-03-01 22:54:43
【问题描述】:

在我的工作场所,我们的应用程序通过使用类似于下面的代码来确定用户会话的区域设置(尽管在启动时它到达这里之前要经过各种代码层,所以问题是/运行下面的代码可能不明显)

#include <CoreFoundation/CoreFoundation.h>  
#include <iostream>  
#include <string>  
#include <vector>  
#include <memory>  

  // Reference release  
    struct reference_close  
    {  
        void operator()(const void *ref) const  
        {  
            CFRelease(static_cast<CFTypeRef>(ref));  
        }  
    }; // end of reference_close structure  

    typedef std::unique_ptr<const void, reference_close>  reference_uptr;  

    std::string get_user_locale()  
    {  
        reference_uptr  ref_ptr(CFLocaleCopyCurrent());  
        CFLocaleRef    locale_ref(static_cast<CFLocaleRef>(ref_ptr.get()));  
        if (locale_ref == nullptr)  
        {  
            return std::string();  
        }  
        const size_t      default_size(128);  
        std::vector<char>  buff(default_size);  
        CFStringRef        str_ref(CFLocaleGetIdentifier(locale_ref));  

      if (str_ref != nullptr)  
        {  
            CFIndex  len(CFStringGetLength(str_ref) + 1);  
            if (len > boost::numeric_cast<CFIndex>(default_size))  
            {  
                buff.resize(len);  
            }  

            buff[0] = 0;  
            if (!CFStringGetCString(str_ref, &buff[0], len, kCFStringEncodingISOLatin1))  
            {  
                return std::string();  
            }  
        }  

        return std::string(&buff[0]);  
    } // end of get_user_locale()  

int main()  
{  
    std::cout << "get_user_locale() : "<<get_user_locale() << std::endl;  

    return 0;  
}  

该应用程序具有定义明确的捆绑结构,其中包含必要的资源和本地化资源目录,例如Contents/Resources/ja.lproj

最近,我们面临一个问题,我们执行以下操作

1) 更改首选项中的系统语言和国家/地区,例如从 en_US 更改为 ja_JP

2) 重启机器

3) 启动应用程序并查看错误输出,例如 en_JP

4) 重新启动应用程序以获取正确答案为 ja_JP

我已阅读 CFLocaleCopyCurrent 的文档,其中指出

您从此语言环境中获得的设置不会随着用户的设置而改变 首选项已更改,以便您的操作保持一致。 通常,您对返回的对象执行一些操作,然后 释放它。由于返回的对象可能会被缓存,所以不需要 无限期地坚持下去。

我还查看了lifetime of CFLocale 上的另一个文档,其中指出

你从 CFLocaleCopyCurrent 返回的对象不会改变 用户更改其首选项设置。此外,对象 本身可能会被运行时系统缓存,所以连续调用 CFLocaleCopyCurrent 可能返回相同的对象,即使用户有 更改首选项设置。如果您想确保您的语言环境 设置与用户偏好一致,必须同步 首选项并使用 CFLocaleCopyCurrent 获取新的语言环境对象。

鉴于此信息,我尝试将CFPreferencesSynchronize 和/或CFPreferencesSynchronize 合并到应用程序代码中(就在我调用CFLocaleCopyCurrent 之前)以获得最新的语言环境。但没有运气。

我是否需要做任何额外的事情来确保从系统首选项中获取语言环境对象的最新/更新值?

【问题讨论】:

  • 为什么不使用[NSLocale autoupdatingCurrentLocale]?无论如何,这段代码看起来写得很糟糕。
  • @trojanfoe 对于CFLocale 类有没有autoupdatingCurrentLocale 的任何C++ 替代品?我发现很难在我的 C++ 代码中混合 Objective C 代码。
  • 您只需要在.mm 文件中实现C++,它就会被编译为Objective-C++。我将用一些(未经测试的)示例代码添加答案。
  • CFLocaleCopyCurrent 的文档说“当前语言环境的语言可能与用户默认设置的 AppleLanguages 数组中第一个索引处的语言不对应。”。 en_JP 是正确的。
  • @Willeke 嗯,令人沮丧的是,它第一次返回了错误的语言 (en_JP),然后更正了一个 (ja_JP)。

标签: c++ macos foundation core-foundation


【解决方案1】:

使用[NSLocale autoupdatingCurrentLocale],它会随着用户更改其区域设置而改变,但由于NSLocale 是一个Objective-C 类,您需要将粘合代码实现为Objective-C++。

这里是一些未经测试的示例代码,给你一个想法:

创建一个名为 AppleLocale.mm 的文件(当然,除非您的项目仅适用于 Apple 平台,因此不需要 Apple 名称前缀)。

#include <Foundation/Foundation.h>

std::string get_user_locale()
{
    NSLocale* locale = [NSLocale autoupdatingCurrentLocale];
    return std::string([[locale localeIdentifier] UTF8String]);
}

注意:当然,您还需要在某些标头中添加函数原型。

【讨论】:

  • Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSLocale autoupdatingCurrentLocale]: unrecognized selector sent to class
  • 我现在正在尝试确定上述运行时错误的原因。
  • @Recker 我不明白那次崩溃。有关非常相似的用法,请参阅 this Apple guide
  • 嗯,这段代码崩溃了。我试图理解为什么这样简单的用例会因堆栈而失败。
  • 嗯,几乎可以肯定这超出了您的问题范围。
猜你喜欢
  • 1970-01-01
  • 2020-09-27
  • 2014-11-22
  • 2015-06-15
  • 2020-07-02
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 2021-10-02
相关资源
最近更新 更多