CloudKit First Take

CloudKit First Take


james sa

Speed 3D Inc.



The problem

The problem I want to solve is in our app (3DPIPO), we have right now 500MB+ 3D model assets. One 3D model takes from 5MB to 10MB based on the texture and resolution of the model.

Each Model is around 5~10MB.

In first version

Cache is good

^ We put everything in cache to make review happy. After that we managed a fallback model to store these assets.

^ As models become more and more, it becomes infeasible to use IAP to download the assets which will take up a lot of phone space and use only once. 3DPIPO will easily boost to 200MB after downloading multiple packs.

^ Therefore, I begin to revamp the underling service and looking for solution. The first paradigm is to maintain a catalog file containing all downloadable models along with their URI. By leveraging NSURLSession's default caching mechanism, this can be done easily.

^ With one catch, I have to build up my own assets management server which needs minimal security level and others.

^ When solving a problem, one should try a lot of solutions and look for the highest solutions or choose the right abstration of the problem.

The Podcast

Everyone needs some motiviation.

After hearing Ray Wanderlich's podcast, I tried CloudKit this morning using defaut sample. As version 2.0 (2014-0-13)

The Setup

I can set up with only a few catch like creating application specific Record Type like ReferenceItems and ReferenceSubitems. Looks like other Record Type are created automatically but not these two.

ReferenceItems has attribute name as String
ReferenceSubitem has attribute parent as Reference, and name as String

The Catch

For Photos and Users record types, you have to create a bogy attribute to make the queriable in PUBLIC DATA.

The result

In the end my iCloud dashboard looks like

Items (2 attributes, location as Location, and name as String)
Photos (2 attributes, photo as Asset, bogy as Queriable)
User (1 attributes, boggy as Queriable)

Now you can head to User Records and Default Zone in PUBLIC DATA

The rest of the problem is data versioning.

Tips for Defining Your App's Record Types

^ When defining your app’s record types, it helps to understand how you use those record types in your app. Here are some tips to help you make better choices during the design process:

  • Organize your records around a central record type.

^ A good organization strategy is to define one primary record type and additional record types to support the primary type. Using this type of organization lets you focus your queries on your primary record type and then fetch any supporting objects as needed. If you define too many primary record types, your app’s interface may require more complexity to select or search for relevant records. For example, a calendar app might define a single calendar record (the primary record type) that contains multiple event records (a secondary record type) corresponding to events on that calendar.

  • Use references to create strong relationships between records.

^ Although you can store the ID of a record or asset in a field using an NSString object, doing so is not recommended. Instead, use a CKReferenceobject to establish a formal relationship between the two objects. References also let you establish an ownership model between objects that can make deleting those records easier.

  • Include version information in your records.

^ A version number can help you decide at runtime what information might be available in a given record.

  • Handle missing keys gracefully in your code.

^ For each record you create, you are not required to provide values for all keys contained in the record type. For any keys you do not specify, the corresponding value is nil. Your app should be able to handle keys with nil values in an appropriate way. Being able to handle missing keys becomes important when new versions of your app access records created by an older version.

  • Avoid complex graphs of records.

^ Creating a complex set of relationships between records creates the potential for problems later when you need to update or delete records. If the owner relationships among your records are complex, it might be difficult to delete records later without leaving other records in an inconsistent state.

  • Use assets for discrete data files.

^ When you want to associate images or other discrete files with a record, use a CKAsset object to do so. The total size of a record’s data is limited to 1 MB though assets do not count against that limit.


iOS8 only

No Serverside scripting


it's just a beginning


Designing for CloudKit

The problem now is the Data Transfer quota. The 25MB/day for assets worries me.

Ray Wenderlich's Beginning CloudKit


Sample Code

Cloud Captions

WWDC Party based on CloudKit

One More Thing

We are recruting :)


> “等你醒來以後來找我”-Rita Vrataski (Edge of Tomorrow)

當 Rita 發現 Cage 有了可以死後輪迴的能力後,在被外星人攻擊前,她把所有的希望都放在他身上。

Doug Liman 再一次導出好片,如果你喜歡 Mr. & Mr. Smith(2005), Jumper (2008),你一定會喜歡這部片的節奏。

不同於湯姆克魯斯前一部科幻片 Oblivion(遺落戰境),只能演資優生,這次阿湯哥可以發揮的演技多了,從一個廣告小屁孩,為了逃避上戰場,跑去做募兵廣告,結果被老闆抓包,直接丟上戰場。從逃避責任,到面對,到 [ooxx],個性變化十足。

Emily Blunt 演的 Rita,加上強植裝甲,好有異性裡面雪歌妮·薇佛的味道,用意志力來求勝。跟阿湯哥微妙的感情戲在這個特殊的故事框架裡,也表現的很好。真的是認真的女人最美麗。

3D 的效果也做的剛剛好,把戰場上面的緊張感表達的很好,但是又不會眼花繚亂。


PS. 如果真的要做點準備,看一下 Full Metal Jacket (1987) 金甲部隊 裡面士官長的獨白!

Go Docker!

[fit]Go Docker

The most popular Go project and how you can do the same.

jamie sa 撒景賢
Product Manager
Speed 3D Inc.

^ ex founder of Waveface
mostly Cocoa in past 3 years

[fit]Docker is

^ anyone heard of it, anyone try in before

A project started by Solomon Hykes

^ First some background. dotCloud is in a very busy space, the PaaS landscape is rapidly converging on a few ecosystems of note. There is Heroku, the

Almost got sold that time.

an open source project to pack, ship and run any application as a lightweight container

Open Source

Highly active since very begining

Lightweight Container

Linux Containers LXC

  • Kernel namespaces (ipc, uts, mount, pid, network and user)
  • Chroots (using pivot_root)
  • Kernel capabilities
  • Control groups (cgroups)

^ The goal of LXC is to create an environment as close as possible as a standard Linux installation but without the need for a separate kernel.

PID namespaces in the 2.6.24 kernel

struct upid {
    int nr;                         /* moved from struct pid */
    struct pid_namespace *ns;      /* the namespace this value is visible in */
    struct hlist_node pid_chain;  /* moved from struct pid */

struct pid {
    atomic_t count;
    struct hlist_head tasks[PIDTYPE_MAX];
    struct rcu_head rcu;
    int level;                /* the number of upids */
    struct upid numbers[0];

November 19, 2007

^ Thinking in chroot or jail


Go Bindings for LXC

in lxc.c

pid_t go_lxc_init_pid(struct lxc_container *c) {
    return c->init_pid(c);

Creating an lxc container in Go

func main() {
    c, err := lxc.NewContainer(name, lxcpath)
    if err != nil {
        log.Fatalf("ERROR: %s\n", err.Error())
    defer lxc.PutContainer(c)

    log.Printf("Creating container...\n")

    if os.Geteuid() != 0 {
        if err := c.CreateAsUser(distro, release, arch); err != nil {
            log.Printf("ERROR: %s\n", err.Error())
    } else {
        if err := c.Create(template, "-a", arch, "-r", release); err != nil {
            log.Printf("ERROR: %s\n", err.Error())

Before I try

Most of the appeal for me is not the features that Go has, but rather the features that have been intentionally left out.

^ read effetive go if you haven't.

After that certain date.

Why Go?

  1. Static compilation
  2. Netural
  3. It has what we need
  4. Full development environment
  5. Multi-arch build

Jérôme Petazzoni, Docker and Go: why did we decide to write Docker in Go?

^ easy to install, deploy
^ not C++, Python, Ruby, Java
^ asynchronous primitives,
^ doc, get ,fmt, test run
^ _linux, _darwin

Jan 19, 2013, Initial commit

func (docker *Docker) Create(name string, command string, 
    args []string, layers []string, config *Config) (*Container, error) {

    if docker.Exists(name) {
        return nil, fmt.Errorf("Container %v already exists", name)
    root := path.Join(docker.repository, name)
    container, err := createContainer(name, root, command, args, layers, config)
    if err != nil {
        return nil, err
    return container, nil

by Andrea Luzzardi

^ A googler now


What kind of web serivce do you use?

  • AWS
  • [.*]Azure
  • Linode

^ The prefix changes from time to time

One More thing

Critical Mass

April 19, 2014, Saturday 4PM


How do you know that you're on the right track?

今天早上我有一個很有趣的經驗,因為要開會還有時間,決定要走去開會的地點。途中我開著 Google Maps 導航,走上了一個我知道的人行步橋,到了橋中間,Google Maps 瘋狂的叫我要右轉,一直說我走錯路了。


但是 Google Maps 非常的緊張,很怕我迷路,一直要我回到它認為正確的路上。


This is your life, this is your journey. You shouldn't listen to others.

Developer's Reproduciblity

1 Project

For a small two year old project with 4+ people from back to front, used by 10K users everyday with

  1. CMS and
  2. Sophiscate membership managment,
  3. And some banking exchange
Language                     files          blank        comment           code
Python                          34           2232            485          18758
HTML                           160            771            246          10384
Javascript                      26            859           1161           8553
CSS                             15            996           1395           6436
SASS                             7            320             71           1313
YAML                             6             17             17            902
SQL                             33            116              0            577
Bourne Shell                     1              6              4             21
Ruby                             1              6             13              5
SUM:                           283           5323           3392          46949

2 experinced

When there was 2 people, 1 from G, 1 from Y, things was easy. One used MacPort and One uses Homebrew, everything was fine. A simple document is fine.

3 is a warning

Then the third came, yet another senior, things still fine. But I started moving to virtualenv and Fabric as I have my hygenie standard on enviroment. Managing a constant changing database is a pain in the ass.


Here comes the fresh blood/brains. They spent hours to keep up the environment. Things went south immediately. My time was consumed by the newbies.

For 2 hours

Finally, I decide to try Virtual Box. For 2 hours, I could setup a complete new environment.

For 6 hours

I setup a completely reproducible enviroment using Vagrant. Don't aske me why I took so long. I recorded it in my calendar is that how long it takes.

For 4 hours

I migrate my development environment to Ansible. Simply because I saw it in Vagrant 's document and love the name and the pholosophy behind.

In 8 hours

I tried docker and give up. XD becuase I want not ready for it.

In review

It's all about scale. For 20 hours, I've came to the level of reproducible I need and I am pleasant about it. The best thing is that the juniors can get up and coding (sort of) within 20 minutes.

In short, If there's only one, bare metal is enough. Stay focused on your pet project.

For 2+, vagrant should be there. Otherwise Frederick Brooks will be laughing at you.

But docker is the blue meth, purist thing I've ever seen so far. Definitely the holy grail.

Auto Layout Examples

[SteamClock's auto layout example」(



魯迅 (1881-1936, 作家、思想家)



2013 年 9 月,一個友人問我,升級 iOS 7 之後,原本越獄安裝的輸入法就不能用了,要怎麼辦。



  1. 從 2008 年開始,教育部已經規定漢語拼音爲全國通行的拼音方式。這解答了我為什麼新店要拼成 Xindian,明明就跟小時候學的不一樣。

  2. 外國人學習中文時,用的都是漢語拼音。見圖一。

  3. 打“ldh” 就會在候選字裡面出現“劉德華”、“李登輝”。

  4. 任何英文鍵盤都可以使用。




圖四、最短距離還是被 Colemak + Pinyin 拿走。

其二,在 iPhone 上面的注音實在是太難按了,不管是動態鍵盤,還是一般。


在研究了一下午後,我決定要來學習漢語拼音的打字法。首先把 iPhone 跟 Mac 都加上拼音。

Day 0 實驗開始


發現自動人名輸入還有成語自動完成。“qnbz”-> 勤能補拙

Day 2

Still straggling。發現在 OS X 裡面, Option + Shift + L 就可以查表,太方便了。

Day 7

打起來像是喝醉酒,一句話總是有幾個字打不出來。但是發現在 iPhone 上面打字變快了。尤其是在通訊錄裡面的人名,都可以用字首打法,省下很多時間。

Day 19

開始順了,可以輕易的打字 :)

Day 21

寫了一個小 app 套上萌典,從常用字來練習。


Day 80

新加坡朋友來台灣玩,我們在 Facebook 上面討論行程,發現用拼音來溝通地名好方便。

Day 98


經過這三個月的實驗,對我來說,漢語拼音真的很符合我的需求,因為大部份時間都是在 iPhone 上面打中文。中英文混用時也非常的方便。





OSX 學習小技巧

2014-2-27 補充
在輸入法的選單裡,如果打開 Correct Fuzzy Pinyin,就會在拼錯的時侯,建議你正確的拼法,對於初學者來說,真的是非常的方便。 Getting Started Guide

Helios 提供了 iOS apps 一個很好的後台框架,當然是用好用的 Ruby,如果你還不會,試試 Ruby 吧。Notification, Password 當然有,但特別的是它做了一個我很有興趣的嘗試,Client & Server 之間資料同步的 Do not Repeat Yourself (DRY)的功能。

在開發 iOS app 時,一個常遇到的問題就是,Core Data 的資料變動後,要同步回遠端的伺服器。比較好的解法是,先在 background thread 寫入 Core Data, 有空時再把資料同步到伺服器。AFNetworking & AFIncrementalStore 就是把這兩件事做得很好的 Library。

Helios 有趣的地方來了,它會讀取你的 Core Data 的 Schema, 然後在 Postgres 裡面,建立相對應的 Schema 還有基本的 API 呼叫,只要 30 分鐘,你就有免費的後台了,Restful 的 GET/POST/PUT/DELETE 全部都有了。


  • Ruby 2.0 stable 2.0.0-p247, HEAD
  • PostgreSQL stable 9.2.4
  • Homebrew

下面操作的來源是 ,但是我更新了一些環境上的設定

在 OS X 上面安裝

  1. 檢查 Ruby

    ruby -v
    ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.3.0]
  2. 安裝 Helios

    gem install helios


    brew install libxml2 libxslt
    gem install helios

    Credit Zekus

  3. 建立一個 Helios app

    helios new myapp
  4. 建立 Postgres 資料庫

    createdb -h localhost myapp


    createdb: could not connect to database template1: could not connect to server: Connection refused
    Is the server running on host "localhost" (::1) and accepting
    TCP/IP connections on port 5432?

    就手動起始 Postgres

    pg_ctl -D /usr/local/var/postgres -l logfile start
    createdb -h localhost myapp
  5. 啓動 web server

    $ cd myapp
    $ helios server
  6. 打開 http://localhost:5000/admin/,你應該可以看到 Helios 太空色調的 UI 了。

接下來,就是把 Core Data model 跟 Helios 整合起來,這邊我就沒遇到什麼問題了,照個 Helios 使用說明 還有 iOS Core Data buildpack 做就行了,有卡關的,歡迎投書,我再把它補上。

我用的 Podfile

platform :ios, "7.0"
pod "AFNetworking"
pod "AFIncrementalStore"


Live Demo

PS. 給那些每天在 Core Data, Client-Server 同步在奮戰的朋友們。順便找個機會用用傳說中好用的不得了的 logdown. 我一個小時就寫好這篇了。