大屏 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而已。。

Objective-C 中的消息与消息转发

[receiver message];

objective-c的这种有趣的语法被苹果称为“发消息”。与其他面向对象语言(C++/Java)的“方法调用”不同,objc的消息机制是由运行时实现、非常灵活动态。这篇文章简单记录一下objc运行时对于消息发送和转发的实现。

(更多…)

Objective-C 中的类和对象

Objective-C的runtime是开源的,源码可以在苹果官网下载到:objc4

在objc4-532.2以后,苹果把NSObject的实现也挪进来了。想要了解NSObject底层实现终于不用去抠GNUstep了~

好了,下面正文:


1.id和Class的定义

runtime里面,声明了idClass的类型,简化一下如下:

在objc中,id代表了一个对象。根据上面的声明,凡是首地址是*isa的struct指针,都可以被认为是objc中的对象。运行时可以通过isa指针,查找到该对象是属于什么类(Class)。

(更多…)

iOS 第三方开源库的吐槽和备忘

注意:这篇文章已经过期

 

做iOS开发总会接触到一些第三方库,这里整理一下,做一些吐槽。

目前比较活跃的社区仍旧是Github,除此以外也有一些不错的库散落在Google Code、SourceForge等地方。由于Github社区太过主流,这里主要介绍一下Github里面流行的iOS库。

首先整理了一份Github上排名靠前的iOS库(大概600个repos)

除了逛一下每日/每月流行之外,也可以到这里来看一下整个iOS Repos的排名。

 

下面是一些比较流行的第三方库:

(更多…)

iOS 如何创建和使用静态库

iOS里可以用静态链接库和动态链接库,但由于Appstore的政策限制,上架应用只能用苹果提供的动态链接库,第三方的库只能做成静态库。这里介绍一下静态链接库的创建方法和常见的一些问题。

 

1. 最常见的方法就是Xcode自带的模板”Cocoa Touch Static Library”。这个很好理解,苹果自己有一个简单的教程,网上也有大把的说明。最终的结果就是一个.a文件和一堆.h头文件。用起来也相对简单:把头文件导入,关联.a静态库,就可以编译了。

下面是一些示例:新浪微博SDK微信SDK

 

2.通过一些方法,将静态库打包成.framework,虽然是静态库,但使用表现上比较接近系统的动态库。目前来看这种方法比第1种好一些,所以推荐用这种方法。手动创建一个静态.framework是非常繁琐的一件事情,详细的过程可以看这里或者这里(中文)。懒人们可以用这个已经做好的模板:iOS-Universal-Framework。制作好后,用起来也就非常简单了,把.framework拖到工程里面就好。

下面是一些示例:百度分享SDK人人网SDK

(更多…)

YYKit — iOS 工具代码库

注意:这篇文章已经过期。

代码在:Github, 文档在:YYKit.

做开发有时需要一些常见的功能,通常随手写一个工具类或是Category就扔到工程里了。次数多了总是想整理出一份常用的代码库。本着“如果有别人洗好的类裤那就直接拿来用”的原则,我还是首先到Github转了一转。sstoolkit无疑是和我的想法最接近的了,但是既然是别人的内裤(雾),穿着总是不太舒服,又闲fork太麻烦,所以到底还是自己搞了一套。

我希望尽量提供和iOS系统风格类似的API,所以代码尽量加到了Category里面并且没有prefix保护。这样,如果把YYKit.framework放到pch文件里面,代码中的方法配色就会变得和系统API一样~~ 坏处就是Category太多了,会占用内存、影响启动速度的(虽然是微乎其微)。 另外不加prefix的话,有可能和系统或者其他第三方库中的同名方法冲突,造成不确定性。。

目前放进去的功能大概有下面这些:

(更多…)

第 2 页,共 5 页12345