之前在Android NDK下纠结过wchar的问题,发现在官方文档里写着2.3以上系统支持部分wchar相关函数,如wcslen等,不支持swprintf,mbstowcs等,很是遗憾,只能自己找了相关函数的源码作了替代实现。现在居然发现在iOS上用swprintf效果也是不尽人意。
省略若干google baidu以及排查调试的过程,直接讲结果,就是在用swprintf的时候任何参数串内容带有中文字符(应该是所有非ansi那些),就会导致返回错误-1,查看errno错误号是EILSEQ,原因就是wchar串里有无法解析的编码字符,这个问题的解决方法是:
在调用swprintf前,进行locale设置:setlocale(LC_CTYPE,”UTF-8″),顺带一说,源代码文件的文本编码是UTF-8,setlocale的文档传送:http://www.cplusplus.com/reference/clibrary/clocale/setlocale/,做过这步操作后在simulator上ok了,拼串中的中文不再导致swprintf出错了。本以为问题就这么终结了,结果发现修改后的代码在设备上运行时还是会出现问题,和没改一样。检查了一下是setlocale返回NULL,调用失败,查errno结果是ENOENT,文件未找到?发现https://devforums.apple.com/message/171660#171660,apple开发论坛上有人提到这个,就是设备上的setlocale只有””, “C” & “POSIX”.这几个可用参数,但提了个解决方法,就是自己生成setlocale指定编码所需的数据文件,用mklocale这个工具,我呢,直接到/usr/share/locale下把UTF-8这个夹子给端到自己程序的资源目录里,维持目录结构不变,然后把程序自身资源路径设置给setlocale搜索路径的环境变量,这下就ok了,设备也可以成功执行swprintf了。
NSString* resources = [ [ NSBundle mainBundle ] resourcePath ]; int success = setenv("PATH_LOCALE", [resources cStringUsingEncoding:1], 1); setlocale(LC_CTYPE,"UTF-8"); 调用一次就可以了。
博主友情提示:
如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。
这样还是行不通啊 。。真机上跑起来 还是乱码啊 。。
先确认代码调整没问题,然后确认”直接到/usr/share/locale下把UTF-8这个夹子给端到自己程序的资源目录里,维持目录结构不变”这步的操作生成的执行文件包内却是有这部分资源么?
大哥,我也碰到本文的问题,请问/usr/share/locale下的UTF-8文件夹,是iPhone上的文件夹吗?但我的iPhone上找不到此文件夹啊,急盼回复,谢谢!
不是iPhone上的,是Mac PC上的,正是因为iPhone上没有这个locale文件才导致swprintf不能正常工作的,你要做的就是把Mac OSX里的这个编码资源以你程序资源的方式带到iPhone上。
谢谢,我copy了Mac上的usr/share/locale/UTF-8目录(目录下就一个LC_TYPE文件)到我iPhone的app的根目录下,build之后myapp.app包内也有UTF-8目录了( 路径如myapp.app/UTF-8/LC_TYPE ),但在设备中执行时,setlocale(LC_CTYPE,”UTF-8″)返回NULL, errno为22,是不是意味着资源还是有问题?
能不能告诉我你的xcode中UTF-8这个文件夹路径和部署到iphone后的路径?
errno=22 (EINVL),意思是非法参数
int success = setenv(“PATH_LOCALE”, [resources cStringUsingEncoding:1], 1);
这句你那执行有没有出问题?
按你描述的复制的locale文件情况来看应该没什么问题。
我明天再帮你查一下我那的那些文件的位置、大小之类的吧,现在手头么有Mac…
好的,谢谢。我的 int success = setenv(“PATH_LOCALE”, [resources cStringUsingEncoding:1], 1); 这句返回为0,应该是执行正确了吧,resources的值就是app的根目录。
查了一下资料,setenv返回0表示执行正确。另, 我的Mac默认装的是英文,但装了中文语言包,可以显示和输入英文。
Mac系统本身就是有多语言支持的,你的默认英文应该没啥大碍,况且现在研究的是UTF-8编码。
我查了一下我这的LC_CTYPE文件大小是80752字节,路径都一样。
不过你这个EINVL比较奇怪,如果是setlocale第二个参数不对的话,应该报的是我文章里写的那个ENOENT文件未找到的错误,这个EINVL应该值得是第一个参数不对,你那LC_CTYPE的定义值是2么?
我的LC_CTYPE大小是80752,LC_CTYPE的定义值也是2啊。
另,我的测试设备系统是iOS 4.2,越狱了,应用安装目录是 /var/stash/Applications/myapp.app,你的应用是安装在什么目录下?
我直接用 setlocale(LC_CTYPE, “C”) 就没问题啊
我是用Xcode直接连接设备调试安装的,默认位置…
不知道这个问题和开发环境有没有关系,我用的是Xcode 4.0 + iOS SDK 4.3,
还有你是怎么安装的?
我是直接将app copy到/var/stash/Applications目录下,重启一下桌面就能看到应用的图标,我用的是越狱版,装了ssh,可以直接访问iPhone的文件系统。
你的联真机调试,调试代码是在iPhone的环境下运行还是在Mac机的环境下运行呢?这个真还有点不确定啊。
你这方法我还真没试过,我用的是正常方式安装的,不管是debug还是发布ipa,都是经过正常安装过程的,没有直接copy到设备上试过,问题可能是出在这里,建议你试试把你的程序打包成ipa,然后用itunes或者其它什么比如91助手之类的安装一下试试看。
好的,谢谢,我试一下ipa格式看看