Swift 编程思路的变化

今天看到这篇文章,才发现之前那次尝试着用 Swift 写代码时犯了一个多大的错误。

上次是在做优优育儿时,有一个新功能非常简单,就是一个单纯的列表页,所以尝试着用 Swift 进行了实现。而我当时正是像文章中写的那样,只是把之前 Objective-C 的写法按照 Swift 的语法进行了变化,然后相信了 Xcode 的代码更正提示,结果虽然可以正常运行,但代码里全是 exclamation mark。

阅读了这个系列的文章,发现 Swift 的确是个现代化的语言。虽然凭借传统语言的知识可以很容易地入手,但它所带来的不仅仅是语法的改变,更多的是编程思路的变化。

下面我将分别展示三段代码,功能是从 JSON 串中得到一个 Article 对象的数组。第一段是用 Objective-C 编写的代码,这也是我写这种功能的标准形式。第二段是按照传统思路编写的 Swift 代码,是应该避免的。第三段是用正确的思路编写的 Swift 代码。

应用上线后 IAP 商品不会立即生效

应用和 IAP 项目均在 App Store 审核通过后,发现从 App Store 内下载的版本,无法正常获取到 IAP 商品信息,通过 product ID 获取 product 时,未能返回相应的 product。

测试环境(Sandbox)下一切正常,可根据 product ID 获取到 product,完成支付。

推测应该是由于 IAP 审核通过后并没有同步及时的上线,所以导致无法正常获取到 product,等待一段时间即可。(我等待了约 7 个小时就正常了,也有人等待了一两天)

所以在程序中要注意,如果获取不到 product 做相应的处理,防止程序崩溃。

管理宽广而严格的广电总局

广电总局状告苹果 App Store

因为广电总局电影卫星频道节目制作中心具有电影《血搏敌枭》的独家网络传播权,而优酷侵权播放了这部电影,所以广电总局状告了苹果公司。

是不是很奇怪?优酷的错为什么状告苹果?

因为优酷的应用是通过苹果 App Store 下载的,所以,苹果,自然要怪你喽。

广电总局要求审核国内游戏

苹果最终还是拿它没有任何办法,在最后一刻公布了这个决定。

游戏个人开发者可以放弃了。但愿不要插手其他类型的应用。我们并不是怕审核,怕的是没有具体审核规则,怕的是自由裁量,怕的是复杂的审核流程、漫长的审核周期、徒增的审核成本,怕的是会应运而生的各种代理。

Battery drainer gpsd

降级到 Kitkat 依然掉电凶猛,刷 MIUI 也是一样。查看电池记录,发现一个叫 gpsd 的进程耗费了大量的电量,但即使把 GPS 关掉也无济于事。在网上搜索,发现有很多 S4 用户都遭遇这个问题,有人说到空旷的地方用 GPS 定位一下就好了,但实测无效。用 Better battery life 查看,系统始终不会进入 Deep Sleep 状态,所以一直在唤醒。

找了很多方法,最后终于找到了一个管用的--把 3G 网络禁用,只允许 2G 网络。不知道是什么原因,但事实证明的确只跟这个有关。

IMEI missing after downgrade Samsung S4

最近手机耗电严重 (Samsung S4 I9502),充满后放一边不用,半天就电量告急了。恢复所有设置也不奏效,想降级到 Android Kitkat 试试。

从网上下载了 4.4.2 的官方五件套,然后按照网上的方法用 Odin 工具刷入。过程很顺利,重启后变成了 Kitkat 的风格,进入首次设置页面。但马上发现,右上角的信号位置,变成了 ⦸ 这样的符号。查看系统设置,或者拨号键盘输入 *#06#,发现 IMEI 丢失。

上网搜索,发现 Samsung 的机器有个叫 efs 的东西,其中保存了包括 IMEI 在内的一些信息。如果降级前没有备份的话,可能会丢失!绝望了好一阵儿,发现把 SIM 卡放到另一个卡槽里可以用,只不过另一个卡槽只支持 2G 网络。可是这让我越想越觉得奇怪,于是又下载了 5.0.1 的固件刷进去,发现 IMEI 回来了,这说明 efs 并没有丢失。马上 ROOT 之后备份 efs,继续折腾。

再次降级,依然没有信号。ROOT 后查看文件,发现 /efs 目录有个叫 .nv_data.bak 的文件,用这个文件替换这个目录下的 nv_data.bin 文件,然后删掉 nv_data.bin.md5 文件,重新手机,IMEI 恢复。

另外,如果只是把原有的 nv_data.bin 文件删掉,也能恢复信号,但是查看 IMEI,发现是一个不正确的 IMEI(一大串 0,后面是 0049)。

Travel in 2016

趁着最近空闲,分两次去了重庆、成都、青岛、日照、上海游玩。

重庆

2016.3.30。山城。一个 3D 的城市。既有文化底蕴,又有现代繁华。夜晚的江景非常美。

成都

詞記 Release!

Dear friends,

我的最新作品,词记,已正式上线 App Store 啦!

应用简介 (Description)

你一定写过日记。或许是小学语文老师布置的家庭作业,或许是青春期时懵懵懂懂的情感记忆,或许是长大后日记本里给自己的加油打气,或许是旅行在外每天晚上写下的旅途随笔。

词记,让你用一个独特的方式写日记。把今天所有的点点滴滴,在思绪中整理、精心挑选,然后只用一个词来概括。

或许随着时间流逝,再看到这些词时,早已想不起这词背后的故事。但这些故事给自己留下的感觉,却依然明晰:惊喜、开心、阳光明媚、意外收获,亦或失落、无聊、阴雨绵绵、心情好糟。

是的,这就是我们的生活。

词记,用一个词记录今天!
一天一个词,烦恼去无边~

You have ever written diary. Maybe homework assigned by your teacher, maybe affection memories in your teens, maybe “fighting” in your notebook after graduation, maybe notes in every evening on your trip.

Ciji (詞記), a special way to keep a diary. All things happened today, in mind, pick only one word to describe!

Time flies, maybe you cannot remember the things happened behind these words, but the feelings are clear: surprise, happy, sunshine, windfall, or disappointed, boring, rainy, restless, etc.

Yeah, it is our life.

Ciji (詞記), use one word to record today.
A word a day, keep the sadness away~

应用下载 (Download)

喜欢请五星好评哦!

iTunes Connect Error ITMS-90475

提交 binary 到 iTunes Connect 时,遇到了之前未遇到过的错误:

ERROR ITMS-90475: “Invalid Bundle. iPad Multitasking support requires launch story board in bundle ‘org.stoneark.worddiary’.”

原因是,iPad 程序(或者 Universal 程序),从 iOS 9 / Xcode 7 开始,默认要求支持多任务分屏。但这要求必须使用 Launch Storyboard,而不能再用 Launch Image。而正如之前说过的,所以我并没有采用 Launch Storyboard,所以导致了这个问题。

目前可以暂时不支持多任务分屏,在工程属性的 General 里,把 Requires full screen 勾选上即可(会在 Info.plist 里增加字段 UIRequiresFullScreen)。

Application localization in iOS development

iOS 对国际化的支持是相对比较完善的。

应用的国际化支持

在 Project 属性中,有 Localizations 一项,在其中可以管理支持的语言列表,还可以选择是否开启 Base 语言。

为资源文件开启国际化

在资源文件(如 strings/xib/storyboard)的文件属性中,可以在 Localization 项中进行国际化语言的管理。如果尚未国际化,会有一个长长的 Localization 按钮,点击后开启这个文件的国际化。如果已国际化,会显示并可管理当前文件已支持的语言。

如果想取消对这个文件的国际化,在 Xcode 里做不到。唯一的办法是,去 Finder 里把各个语言的 .lproj 目录下的这个资源文件删掉,只留一份放到工程目录的最外层(而不从属与任何 .lproj 目录)。

字符串的国际化:

自己新建一个 String 文件到工程里,名为 Localizable.strings 即可。(这是默认的文件名,调用 NSLocalizedString 方法默认取这个文件,如果用了其他的文件名,则每次调用方法时,需要指定文件名)

例如,Localizable.strings 内容为:

Localizable.strings(Chinese (Simplified))
1
2
3
4
5
"Today" = "今天";
"Yesterday" = "昨天";
"%d days ago" = "%d天前";
/* {User First Name}'s Profile */
"%@'s Profile"="%@'s Profile";
Localizable.strings(English)
1
2
3
4
5
"Today" = "Today";
"Yesterday" = "Yesterday";
"%d days ago" = "%d days ago";
/* {User First Name}'s Profile */
"%@'s Profile"="%@的个人资料";

获取时:

1
2
3
4
5
NSString *str;
str = NSLocalizedString(@"Today", nil);
int temp = 3;
str = [NSString stringWithFormat:NSLocalizedString(@"%d days ago", nil), temp];
str = [NSString stringWithFormat:NSLocalizedString(@"%@'s Profile", @"{User First Name}'s Profile"), user.name];

上面是常用的情况。还有一种复杂的情况,是在有些语言里,某两个参数的位置可能会颠倒,这时需要使用转义符:

1
"%@ Error! %@ failed!" = "%2$@ 失败了!%1$@ 错误了!";

更为详细的可参照:
http://nshipster.com/nslocalizedstring/
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html
https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/InternationalizingYourCode/InternationalizingYourCode.html

xib/storyboard 的国际化

除了借助 localizable strings 文件进行界面国际化之外,对于 xib/storyboard 可以直接进行国际化。虽然看上去很方便、很直观,但其实并不是特别好用。

它的原理其实还是 localizable strings,只不过这个 strings 文件是 Xcode 自动创建的。创建的时机是在你对这个界面开启 localization 时,而且它并不会监控 xib/storyboard 的变化。如果你在 localization 之后又改变了这个 xib/storyboard,主要是增加了新的控件,那么这个新控件并不会自动出现在 strings 文件中。

那你就没办法了,Xcode 也没有提供同步的手段,你唯一能做的是查看 xib 的源代码,从中找到新建控件的 ID,然后自己写到那个 strings 文件里--噢,这一点都不方便。

Bundle Display Name 的国际化

显然,需要对不同语言设定不同的应用名称,也就是 Bundle Display Name,我们都知道它在 Info.plist 里。

但注意,不是把 Info.plist 进行 Localization,如果对 Info.plist 进行了 Localization,会编译报错 the file Info.plist does not exist.

正确的方式是在工程里新建一个名为 InfoPlist.strings 的文件,然后对这个 strings 文件进行国际化,在里面写入:

1
"CFBundleDisplayName" = "名称";

即可。

注意,需要把 InfoPlist.strings 文件加到工程属性里的 Copy Bundle Resources 里(默认应该就给加上了,如果有问题可以检查一下)。但不要把 Info.plist 文件加到 Copy Bundle Resources 里,否则出现编译警告。

Base 语言的问题

测试发现,将 iOS 设备设置为并没有支持的语言时,应用并没有正确地显示为 Base 中的字符串(英语),而是显示成了简体中文。

Stackoverflow 上有很多国内外开发者遇到了这个问题,但都未找到原因和解决方法。

http://stackoverflow.com/questions/20241256/ios-app-default-language-en-is-not-applied
http://stackoverflow.com/questions/20584984/ios-set-a-default-language-in-xcode-for-my-app
http://stackoverflow.com/questions/18114994/does-my-base-internationalization-storyboard-have-to-correspond-to-a-fallback-la

App Store 应用名称及简介的国际化

希望让应用在不同国家的 App Store 中显示不同语言的名称,在 iTunes Connect 里新建应用时先用一个主要语言新建,如简体中文,新建成功后在 App 信息里可以看到“可本地化的信息”,可以在右侧选择语言,并且填入相对应的信息。另外,在版本中对应用简介、关键字、截图等也都须进行国际化。

如果未做本地化,则按照选择的主要语言显示。

Bug about launchscreen storyboard

Launchscreen storyboard,看起来很美,用起来很臭虫。

之前一直没在实践中真正采用过它,这次一试,可真是让人摸不着头脑。

一旦有两个 ImageView,则它们的表现会非常奇怪。尤其是两个图像有重叠部分的时候。
即使一张图片在另一张下方,也会把上方图片的重叠部分遮盖住。

设计时:(灰色渐变背景在底层,词记图标在上层)

运行时:(重叠部分被底层遮盖了)

关于 Launchscreen storyboard,涉及到 UIImageView 出现了很多问题,至今也没有解决:
https://forums.developer.apple.com/thread/17146
https://forums.developer.apple.com/message/62721

暂时还是不用它了,用回 Launch image asset。