大屏 iPhone 的适配

自从苹果出了大屏 iPhone 后,iOS 开发也要做适配了,想必 Android 程序员正在偷着乐呢 :lol: , 这里大概总结下这几天了解到的大屏适配的注意事项。

启用高分辨率模式

从 Xcode6 GM 版本开始,模拟器新增了 iPhone6 和 iPhone6 Plus 两种,如果旧的工程直接跑到这两个模拟器中时,默认是”兼容模式”,即系统会简单的把内容等比例放大,显示效果有些模糊但尚可接受。此时 App 内部获取到的设备分辨率和 iPhone5 是一样的:320*568 point。

启用高分辨率模式有2个方法(目前我能找到的):

1.添加大屏的 LaunchImage:
在 Images.xcassets 里,新建或更改 LaunchImage 组,添加对应高分辨率的图片。对此,这里有一篇更详细的图文介绍:How to Add a Launch Image for the iPhone 6。如果想要快速测试一下新的效果,这里有3张示例图片下载。

2.添加 Launch Screen File
Launch Screen 是 Xcode6 和 iOS8 新加的功能,它用一个 xib 文件来作为启动画面。App 在旧版 iOS 启动时,该属性会被自动忽略,不会造成异常。
首先,点击 New File ->iOS User Interface ->Launch Screen,然后在工程设置项里启用它:

LaunchFile

上面两处设置,只要启用任意一个即可让 App 进入高分辨率模式;但如果两处都没有设置,则 App 会回退到兼容模式。鉴于现在不少 App 还需要兼容 iOS5,而第一种方法在 iOS5 上据说可能有bug,所以这里推荐用第二种方法。

(更多…)

WWDC2014

熬夜看完了直播,新闻类的东西就去新闻网站看去吧,这里来吐槽开发相关的东西。

总的来说,WWDC = World Wide Developers Crying。
iMessage 重新造了半个微信,iDrive 实现了 Dropbox,iCloud Mail 把 QQ 中转站弄来了、CloudKit 把一些小的云服务干掉了、出了个 Metal 把 OpenGL 换掉了、矢量地图语音导航给各种 Map 带来压力,等等。。最后,还出了一门新语言 Swift 换掉了 Objective-C!!

新语言 Swift 的书可以在这里下载。从网站上的文档来看,苹果把所有 ObjC 和 C 的 API 都用 Swift 重新实现了一遍,并且文档里是 Swift 优先。这点上来看,下面我们该洗洗天赋点了 :?: .

iOS 8.0 API Diffs里面可以看到下面一些变化:

1.苹果把大量基础类中的方法改成了 property。
2.把大量的 id 返回值改成了 instancetype 或者实际的对象类型以适配 swift。
3.增加了大量的新 Framework,包括这次重点介绍的 CloudKit、HealthKit、HomeKit、Metal、Webkit等。
4.新增的 NetworkExtension 允许 App 自定义 DNS、VPN,有着完整和详细的 VPN 控制。
5.新增的 NotificationsCenter 允许 App 自定义 Widget了(Android啊)。

因为最近自己私下里搞 Midi 合成的库,所以其他的 API 没仔细看,音频相关的 API 倒是仔细翻了一下。这次 iOS 支持完整的 MIDI 了,可以加载 sf2/dls 格式的音色库、有了 MidiSynth 支持、有了完整的 Midi CC 控制、支持 SysEx 信息。有了专门播放 Midi 的类:AVMIDIPlayer。音频处理方面,添加了混响、滤波、重采样、变调、3D音效(比如说HRTF)等等。很棒。想想我折腾我自己的库干毛啊,苹果都帮我实现了。。性能和效果上估计会比我的实现要好。。(摔)(摔)(摔) :cry: 那这样,我就抄抄 API 设计好了。。然后移植到 Android 去喵的。。

好困,睡觉了喵。。没吃药果然一点都不萌萌哒。。。

~~~~~~~~~~~~~~~~~~

update:后来在 iOS8 真机上试了一下,苹果原生的 midi synth 效果很渣。。就算给个好的音色库依然很渣。。之前期望太高。。

无意义的第二篇吐槽

距离无意义的第一篇吐槽已经过去3年了呢~ ;-)

一年前,我说过想做一个钢琴的 App。看到其他 App 实现的技术那么复杂,本来是想放弃的,但后来还是没忍住,决心深入进去研究一下。后来断断续续在工作之余研究这些东西。嘛~现在终于做出了个音效比较让我满意的 demo 了。现在能支持加载 sf2 音色库、读取 mid 文件、支持部分 midi 指令、有比较好的混响效果和压缩器,可以实时调节音高和滤波效果。音效上听上去比 FingerPiano 要好了~~  :mrgreen:  这次是用纯C写的核心库,以后也可以移植到 Android 了~ 等核心库完善了,就可以下一步的界面设计和上架了。 这算是咱半年来做的比较有成就的一件事吧~~

一个月前,公司搬家了。原来走路十多分钟就能到公司的,现在要挤半个小时公交了。 :?: 公司新楼附近的环境比想象的要好很多啊~对面的园区很像大学,绿化超级棒,吃完午饭去散半个小时步,感觉好惬意。特斯拉的分部在那里,Musk 过来的那几天就变得好热闹。虽然我还对汽车不感兴趣,但凑热闹倒是挺有意思。再往北去就是360大楼和798了。360大楼上面隔几天就贴出一个超大超2B的宣传画,有次还放了个超大的二维码在上面,难道是专门给我这样蛋疼的人去扫的?

五一三天又在家宅着过去了。。好久不看新番了,漫展也好久没去了。总想腾出时间学一下画画,大学的时候为此还买了块板子,现在也落灰了。。天天码代码真的要变成码农了啊 :arrow: 不管怎样,希望以后的生活会更好吧~

实现 CFArray

平时都在用 NSArray,但最近搞一个纯C的库,不想有太多依赖,所以想把 NSArray 的功能提取出来。NSArray 和 CFArray 是 Toll-Free bridged的,而且 CFArray 是开源的。所以这里研究了一下 CFArray 的实现,并且给出一个纯C的、无其他依赖的替代实现。

苹果的实现

在翻CF的源码前,我在网上找到一篇很有意思的老文章:http://ridiculousfish.com/blog/posts/array.html (2005年)。这篇文章里面,对 CFArray 和 STL Vector 做了一次性能对比,结果如下:
vector_resultscfarray_results

这篇文章写于2005年,那时的 CFArray 实现的非常有意思:在 CFArray 容量超过300000左右时,消耗的时间完全变了。我很好奇的测试了一下现在系统的实现,已经跟那时的结果完全不一样了。于是我翻了一下CF的历史源码,看到了 CFArray 这些年的变化。

1.最开始,CFArray 底层是用 deque(双端队列)实现的,在头部尾部进行插入删除性能很高,但是在 deque 中间插入删除时,就需要 memmove 来挪动内存了,性能就会降下来。苹果的方法是,当 CFArray 长度超过某个数值(具体来说是262040)时,将底层的 deque 换成 balanced tree

具体来说,苹果写了一个名为 CFStorage 的类,用 balanced tree 实现了大数量的数值的存储和编辑,并且在插入和删除时有很好的性能。CFArray 在长度达到阈值(262040)时,就会在底层替换为CFStorage来完成操作。

2. 但是在2011年,CF-635.15中,苹果把这个特性去掉了。具体的对比可以看下面两个文件。
http://opensource.apple.com/source/CF/CF-550/CFArray.c
http://opensource.apple.com/source/CF/CF-635.15/CFArray.c 在这之后, CFArray 就只是用简单的deque实现了,长度越大,位于中间的插入删除耗时就越长。至于为什么这么改?我也不知道。。也许是怕切换数据结构造成的时间抖动?也许是这个 feature 根本没有多少人用到?

3.最新的 CFArray 中,代码应该又调整了。性能比单纯的双端队列高,我猜测应该换成了一个环形缓冲区。但是苹果还没有开源最新的代码。

 我的测试和实现

在我的系统(10.9.1)里面,我参考最新的 CFArray 源码实现了一个纯 C 的 deque。随后与系统CFArray做性能对比,发现在随机插入的时候,系统的CFArray仍然有更高的性能。当我把deque换成circular后再进行对比,性能就完全一致了。所以,我猜测现在系统的 CFArray 底层又换成了 circular,只是最新的代码还没有开源出来。

我的实现代码放到了 https://github.com/ibireme/yy_music_base/blob/master/yy_music_base/ym_array.c,里面有个纯C的、简单的引用计数对象的实现,有个 CFMutableArray 和 CFMutableDictionary 的模仿实现。所有 API 都和 CoreFoundation 类似。 还没有没仔细 test,但应该没什么大问题。

下面是我自己的实现和CFArray的一个性能对比:除去随机数的影响,插入性能应该是一致的。
yy_array_time_cost

 

 结论

好了,现在可以回头看看苹果给出的时间复杂度的描述了:

用开头那篇博客的话来说:Don’t second guess Apple, because Apple has already second guessed YOU.

 

PS: [NSMutableArray arrayWithCapacity:xxx]中的capacity没有任何作用。。仅仅是一个hint而已。。