2015年了呢…

又是新的一年了呢。。偶尔也写写年终总结之类的东西,然后顺便稍微展望一下未来吧。

算起来,来到帝都工作已经快三年了呢;相对于刚毕业前后那段紧张绝望迷茫的日子来说,刚过去的这一年已经算得上不错了。这一年里换了一个新工作,从 Java 转回了 iOS,上班从酒仙桥挪到了中关村,工资涨了点儿,活儿轻松了点儿。和小伙伴租的房子,一年一搬。新的房子有个面朝阳台的书房,午后的阳光很棒;书房有一个很大的书架,能放下我在这边买的所有的书。看上去,这一年过得还不错。

但是到底是怎样的呢?我也不知道。能说上话的人越来越少,从前的朋友和同学也都各奔东西,不再联系。朋友们有的去留学了,有的留学又回来了,有的去创业了,有的仍留在出生的城市工作。大家都有自己的圈子,即使能有空聚一聚,或者在网上聊一聊,也都没什么话题了。我自己也不太擅长与人交流吧,所以总是习惯了一个人。用村上的话来说:”哪里会有人喜欢孤独,不过是不喜欢失望罢了”。

2015年来了,我要做些什么呢?如果可以的话,腾出更多个人时间来做些有意思的事儿。再仔细学一下 dsp 相关的东西,希望能做出类似 GarageBand 那样的 App 吧,我想要在 iPad 上编辑和录制 midi。在屋里腾出块空间来放下我的电钢,试试看能不能捡起一些过去的技能。换一块儿好点的数位板,认真学一下数码绘,希望能创造点东西,而不是总在复制。然后,一定要多读书!想得太多读书少这肯定是不行的。我知道现在如果立下一堆计划怕是用处不大(笑),但是不管怎么样,希望未来能更好一些吧。

最后还是想说一下我的第一份工作。08年我第一次注册人人网,加上了很多大学好友,玩得不亦乐乎。11年底,我拿到人人的 Offer,到人人网实习,做一些移动方面的东西。12年毕业后,便正式加入了人人网,只是转做起了 Java 后台,先后负责开发开放平台、应用中心、支付等一些项目。虽然当时由移动开发转做 Java 有点不情愿,但现在看来这让我增长了很多技能,眼界也开阔了很多。在这期间,部门的头头(给我面试机会、招我进去,算是有知遇之恩吧)走了,一同去的几个同学也先后走了,部门同事也前前后后走了很多,最后我也走了。。我在人人网玩了六年多,工作了两年多,到现在每天新鲜事儿都刷不出来几条了,多少有点感伤,稍微祝福一下人人吧。。

大屏 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

(更多…)