13's blog

重拾程式解題的樂趣 - Advent of Code

你有做過線上解題嗎?像是高中生軟體比賽會寫的 ACM Online Judge,或是有些軟體工作面試要求考演算法,而要刷的 LeetCode

我不喜歡寫這些,雖然富有挑戰性,說實在並不有趣。如果想要享受純粹的解題樂趣,我不會去寫 LeetCode

直到最近我發現一個只在每年 12 月才會有的解題活動:Advent of Code

它是一人專案,作者是 Eric Wastl (@ericwastl)。這個活動從 2015 年以來已經是第 5 年了。

什麼是 Advent of Code

Advent 是天主教專有名詞,你可以簡單理解成「耶誕節倒數」(維基百科)。所以 Advent of Code(以下簡稱 AoC) 的活動是在每年的 12/1 到 12/25。

在這 25 天中,每天都會公布兩題(通常)要寫程式才能解決的題目。時間是台灣的下午一點。

第一題通常不會太難,而你要解開第一題以後才會看到第二題的題目,是第一題的變化。很有可能顛覆你前面的思路跟設定。我喜歡這種變化題的設計方式,可以打破慣性思維

實際解了幾題,我發現就解題樂趣而言,AoC 比 LeetCode 好玩很多。

LeetCode 的解題過程大致上是:

  • 挑題目(有些要付錢)
  • 理解題目(同時心裡想著,不會吧,這題是 Easy?)
  • 在網頁介面上寫程式來:
    • 處理輸入的測試資料
    • 解題完回傳答案
  • 送出程式碼讓 LeetCode 後台執行
  • 要考慮到 edge cases
  • 要考慮到執行時間,解完以後還會跟別人比較

而 Advent of Code 的解題過程則是:

  • 有一個簡單的背景故事(例如聖誕老人被困在太陽系某處,你要幫助他 blah blah)
  • 每天準時公布題目
  • 一組資料
  • 一個答案輸入框
  • 解題方式隨意
  • 第一題解完會有第二題
  • 答錯的話要過一分鐘才能重試

以下說明 AoC 的幾個特色。

解題方式隨意

2019 Day 1-1 這題,其實我是在手機上複製貼上到 Numbers app 解的😆

因為它的題目非常簡單,大意是:

聖誕老人的太空船上的各種模組要消耗燃油。它列給你所有模組的重量,然後你用簡單的四則運算求出對應的燃料重量,再加總。

所以用試算表秒解。而且不是只有我有這種想法

變化題

當你把 1-1 解完以後,「故事」才會往下展開。看到 1-2 這題就有趣了:

原來你剛才忘記計算燃料本身的重量了。每次增加燃料的同時,你要再增加一定的燃料,如此反覆直到某個條件為止。

這就不能用原本的方式計算,所以我才打開電腦寫程式,順便重寫第一題。

邏輯變了,但資料沒有變。我只要調整計算方式。

比較少在處理資料,比較多在解題本身

在寫 LeetCode 時,有好一部分時間是在處理資料的輸入格式,這個部份特別無趣。

AoC 你可以隨意。因為資料只會有一組而且是公開的,不需要像 LeetCode 反覆嘗試來處理各種「規則有寫但看不到範例」的 edge cases。

每天的兩題共用同一份資料,所以即使第二題的邏輯不同,你初始處理資料的程式碼通常也可以沿用第一題。

這些條件與設計,就讓人更專注在解題而不是處理資料格式

題目難度

2019 前面四天每天有越來越難的趨勢。

活動玩法

既然是玩法很自由的解題遊戲,你要怎麼做都可以。你可以跟高手比賽解題速度,每天下午一點公布題目後就開始寫。如果前 100 名的話,會得到 (100 - N + 1) 點積分,可以累積積分來排名。但是排行榜上都是在幾分鐘內解完,我可能題目都還沒理解完呢😂

所以我的玩法是志在參加,有把題目都解出來就好。我是用 Swift + Playground。每解完一題就 commit 起來。

解完之後再去看討論。以後學了其他語言也可以回來解一次。

AoC 也支援私底下的排行榜,可以跟朋友同事切磋。

救命,解不下去

不確定題目意思可以跟我在 Twitter 討論。

凡是公開題目就會有公開解答。GitHub 有一些可以參考,Reddit 也有很多討論。甚至還有人靠 Siri 解題!?(1-1 還沒解完的不要看)

不過我覺得前幾天的第一題的難度真的沒有太高,可以多試幾次再去看討論。

費用

AoC 完全免費!甚至不用登入就可以看題目

只要用 GitHub、Twitter 等註冊帳號就可以開始填答。

若你覺得這個活動很有趣,可以考慮捐助,金額隨意。

歷史題目

我是從今年才開始玩的。但是 2015-2018 也各有 25 * 2 題可以回去解。

結語

對你來說,線上程式解題是好玩、痛苦,或是苦樂參半的經驗?

前陣子在 Twitter 上有看到一陣在討論 LeetCode 怎麼刷、怎麼買(中文版比英文還便宜)。看到討論時,我比較有興趣的卻是,這種線上測驗的專案是怎麼做起來的啊?

等到我看到 @ericwastl 創造的 AoC 發現,這個專案是他一個人從頭搭建的,題目也都是自己想的。他甚至說,為了避免法律爭議,即使寄給他題目的建議他也不會讀,免得不小心用上了這些點子。我覺得這位工程師以及 AoC 這個專案,甚至比解題本身甚至更有意思。

也許我們應該思考怎麼創造出題目,而不是只會解題而已?

總之,AoC 是一個很有趣的程式解題活動,有空的話一起來玩吧。

可以來我開好的 Leaderboard,輸入747723-067e3e4b加入,已經有一些推友在上面了。我會把 anonymous user 移除,所以請記得到設定把自己的名稱顯示出來。

或者是只跟自己比也完全沒問題。

AoC 刷起來!

相關連結

如何管理 Xcode 版本才不會害到自己跟團隊

身為一個 iOS 工程師,我們應該對自己的開發工具有完整的掌握。最常使用的就是 Xcode。

我注意到開發者很常踩到 Xcode 在安裝、版本選擇方面的坑,所以決定來分享一下自己是怎麼管理 Xcode 版本。

安裝與下載

不要透過 Mac App Store

開發者最常犯的錯誤大概就是用 Mac App Store 下載 Xcode 了。使用 MAS 看似方便,但是後面會有各種無法掌握的因素。比如說:

下載不了…

類似的抱怨在 Twitter 上隨便找都一堆。

低能安裝過程…

下載失敗浪費空間…

正要用的時候,自己手賤或是系統犯賤幫你更新…

我覺得這個超慘的耶🤦‍♂️

而且強迫症的你還糾結著那該死的紅點…

其他缺點

  • 同時只能保留一個版本
  • 一直跳出更新提示

你完全可以避免這些問題😎,以下提供兩種方式。

直接從 Apple Developer 網站下載 Xcode

其實 Apple 官網一直有下載 .xip 壓縮檔版本 Xcode 的連結,但是藏得有點深。

下載頁面的首頁是 https://developer.apple.com/downloads。而列出下載檔的位置是在 https://developer.apple.com/downloads/more。都需要登入開發者帳號。

要去按 More,是不是藏得有點深…

是說,這邊最早還可以下載到 Xcode 3.2 呢。

自己下載唯一的缺點就是,通常這個版本會比 Mac App Store 還要晚個半天才會放上去。

但我通常都會在 Twitter 觀察一下災情,才決定要不要抓新版,所以沒差。

透過 xcode-install 套件管理 Xcode

如果你覺得手動下載、手動解壓縮好蠢,那麼來用 command line 吧。

xcode-install 是一個很方便的 Ruby 套件。

安裝 Xcode 11.0 只需要兩行:

gem install xcode-install
xcversion install 11.0

就會登入(使用跟 Fastlane 一樣的 Keychain 機制)、下載,並且解壓縮。

甚至可以列出所有可下載與已安裝的版本:

xcversion update
xcversion list

Xcode 與 iOS 相容性測試

(2020/06/23 更新:本段落舉例版號改成 WWDC20 推出的新版本,以利閱讀)

每次 Apple 發表新版 Xcode 的 beta 版以後,尤其是 WWDC 的年度大版本,開發者應該將 beta 版抓下來做專案的相容性測試。

我們應該要測試相容的有哪些呢?以下為了方便說明我們把時光假定為 beta 版期間。

以 2020 年發表的 Xcode 12 與 iOS 14 來說,相較於前一代的 Xcode 11 與 iOS 13,會有以下四種組合:

  Xcode 11 Xcode 12 beta
iOS 13 或更早 A. 現況 🔁 C. 向下相容 ⬇️
iOS 14 B. 向上相容 ⬆️ D. 新東西 🆕

通常 A、C、D 這三種情境我們比較熟悉,也比較容易。

A. 現況 🔁

專案在目前 Xcode 正式版的相容性,也就是現況。

B. 向上相容 ⬆️

專案在舊版 Xcode 上 build 出來的,跑在新版的 iOS beta 裝置。比如 Xcode 11.5 正式版去連接 iOS 14 beta 裝置。

這一塊可以說是個大盲區。你想想看當新的 iOS 正式推出的時候,使用者可能就升級上去了,但你不見得已經準備好支援 iOS 14 的 app。就算準備好了,他們也不見得會更新 app。

這明明就是在新版系統正式推出以後,使用者最有可能遇到的情境。但是 Apple 從來就沒有為了向上相容的測試提供方法。把一台 iOS 14 的裝置接到 Xcode 10,會告訴你不支援,系統版本太新,沒辦法 run 在實機上。這樣子要怎麼確保向上相容呢?

幸好,要讓 Xcode 去支援它本來不支援的新版系統,只需一個關鍵—DeviceSupport。我們可以從新版 Xcode 裡面把對應的 DeviceSupport 資料夾,看是要用 symbolic link 還是複製一份的方式。我是比較推薦前者。

我寫了一個 gist 來做這件事情,裡面還有 watchOS 與 tvOS 的指令。你可能得依照自己的 Xcode 路徑來修改指令內容。

唉呀,其實我在 2017 年就寫過類似的文章了。

C. 向下相容 ⬇️

專案在新版 Xcode build 出來以後,跑在舊版的 iOS 裝置。比如 Xcode 12 beta 連接 iOS 13 裝置。

WWDC 新版 Xcode 出來時,Apple 會希望你下載最新的 beta 版,來做向下相容的測試。直接把舊系統的裝置連到新版的 Xcode,通常安裝 app 不會有問題,我們要留意的是跑起來以後,新的 SDK 怎麼樣相容舊版系統,有沒有一些壞掉的情況。

一般來說向下相容比較不會有問題,因為 Apple 必須確保系統升級不會讓原有的應用程式無法使用。

而且除非你要升級 Xcode,不然這件事也沒那麼急。

D. 新東西 🆕

專案對於新系統、新版 Xcode 的相容性。現有專案直接用新版 Xcode 打開看能否 build。比如 Xcode 12 beta 跑在 iOS 14 beta 裝置。

這邊主要看的是專案對於系統的相容性。越早版本的 beta 問題當然是越多。

但是除非你的產品非得要用到最新的 API,要不然 D 這個部份的相容性應該是最不急迫的。

就一個成熟的產品或是日常工作來說,我覺得處理的優先順序應該是 A 現況 🔁 > B 向上相容 ⬆️ > C 向下相容 ⬇️ > D 新東西 🆕

2019 年大家都興沖沖地跑去玩 SwiftUI 或是 Combine,然後才發現坑超多。其實那些都是屬於 D 的部分,優先度最低🤣

以後 Apple 再發表新東西,我們最好還是吸取教訓,先搞定 A、B、C,再來玩玩具。

團隊協作

指定 Xcode 版本

有多個版本 Xcode 的話,用 xcode-select 來指定要使用的 Xcode 的路徑。這應該是基本功夫。

sudo xcode-select -s /Applications/Xcode.app #路徑

在專案中鎖定 Xcode 版本

我建議在發布 app 時使用 Fastlane,就可以用 ensure_xcode_version 來確保版本。

確定 Xcode 是沒有被動過手腳

你可能聽過 XcodeGhost 事件。下載來路不明的 Xcode 是有可能抓到被駭過的版本。

使用 Fastlane 的 verify_xcode 可以幫忙確認 Xcode 的 code sign,以及用 GateKeeper 檢查。

想要自己跑指令的話,也可以參考這裡

不過要注意的是,這個動作要跑好幾分鐘,比較建議是在出正式 Release 的 lane 再跑。

另外,如果因為前述的向上相容,而改過 DeviceSupport 資料夾的話,驗證會失敗。

我們到底要保留哪幾版 Xcode?

這完全是要看你手邊專案的狀況。三個版本不算誇張:

  1. 前一個正式版,如果舊版 app 出了問題可能要回去看。比如說你舊版 app 的 Swift 版本是上一代
  2. 目前的正式版,用在最近上架更新的 app
  3. 最新的 beta 版,如果要使用一些新系統才有的 API

我以前也舉過一個例子

結論

iOS 開發者的電腦硬碟要買大一點,MacBook Pro 要 512 GB 以上。

不是啦,講認真的:

  • 不要用 Mac App Store 安裝 Xcode,從官網的 More 下載,或透過 xcode-install 管理
  • 弄清楚相容性測試的優先順序
  • 可以透過 Fastlane 幫助團隊管理 Xcode 版本

同場加映

空間清理工具

每次更新開發裝置的 iOS 版本以後,記得把電腦上舊的 cache 給清除。身為 Xcode 使用者,一次清出幾十 GB 也是很常有的事。

跨版本安裝模擬器

其他資料

iOS 也有深色模式—智慧型反相

2019/01/04 更新:

這篇文章本來是寫在 iOS 12 時代,可以忽略了。現在請愛用 iOS 13 的 Dark Mode。

2018/11/30 更新:

如果要將整個 app 反向的話,不能用 UIView.appearance().accessibilityIgnoresInvertColors = true ,否則會遇到問題。官方回說可以在各個 viewController.view 做設定。

Don't do this in rdar://45663655


2016 年,Apple 給 tvOS 10 增加了深色主題設定(UIUserInterfaceStyle*)、2018 年 macOS 在 Mojave 也新增了深色模式,甚至連 Safari/WebKit 都可以告訴網站去支援深色模式(prefers-color-scheme)。但是 iOS 一直沒有全系統的深色主題或設定。

由於 iOS 的 UI 預設都是白底黑字或亮色系,大部分 app 如果不特別設計深色主題的話也就會是淺色,所以把螢幕顏色反過來就是一個建立深色模式的思路💡。

但是傳統的螢幕反相,就是單純地把輸出到螢幕的顏色反過來、黑白互換,類似於傳統底片的效果。遇到圖片就會慘不忍睹😂。直接拿來當深色模式是不堪用的。

螢幕顏色反相的設定在輔助使用裡面存在已久,但是我唯一聽過的使用情境,就是還在用傳統底片的攝影師,用相機 app 搭配反相模式來看她沖洗好的負片。


不過 iOS 11 新增了智慧型反相輔助功能。智慧型反相把 iOS 主畫面與 app icon 保留原本的配色,只是稍微降低飽和度。同時,app 可以指定忽略哪些 UI 元件。例如用來顯示圖片的 UIImageView 就不需要反相。對於大部分使用者來說,可以當作一個不錯的深色模式替代品。

把智慧型反相當作深色模式來思考的話,除了圖片以外,底色是深色的畫面就可以忽略反相。如果 app 本來就是以暗色為主的介面,那就可以全部忽略。以我公司 CATCHPLAY 的 app 為例,我們的主題一向是深色為主,因此可以把所有的元件都忽略掉智慧型反相。

要支援智慧型反相滿簡單的,就是把不要反相的 UIView 元件的 accessibilityIgnoresInvertColors 設為 true 即可。

2018/11/30 更新:請不要這麼做🚫 如果整個 app 都不要反相,在 UIApplicationDelegatedidFinishLaunchingWithOptions 方法設定 UIView.appearance().accessibilityIgnoresInvertColors = true 即可。


正常的顏色:

Normal

智慧型反相的預設結果,效果跟經典反相一樣:

Enable Smart Invert

整個 app 的 UIView 都忽略經典反相,看起來大致相同。狀態列的顏色仍然是反過來的:

Ignore Invert

如果在意狀態列顏色的話,可以監聽系統通知 invertColorsStatusDidChangeNotification,並用 UIAccessibility.isInvertColorsEnabled 來判斷使用者是否啟用反相,然後再指定狀態列的 style。這個判斷名稱雖然沒有寫 smart,但是我實測它只會在智慧型反相時回傳 true,在經典反相時則回傳 false。


雖然說叫做智慧型反相,其實也沒有多智慧🤣,就是可以指定部分 UI 元件不要反相而已。也許你還會想,既然照片的顏色顛倒不堪用,為什麼智慧型反相時,系統沒有預設把 UIImageView 忽略掉呢?大概是因為 UIImageView 可以用來顯示照片,也可以用來顯示圖形按鈕。即使 UIImagerenderingMode 也不容易判斷,乾脆讓開發者自己決定。就像其他 accessibility 功能一樣,系統可以猜到大概,最後細節還是要留給開發者。

但這也導致絕大多數 app 的圖片在智慧型反相預設情況下很可怕,就連 iOS 11 初期版本的 WebView 與郵件也沒支援正確的照片顏色。開發者應該檢查一下自家的 app 在智慧型反相下的效果。

最後提供一個開發或測試的時候的小技巧,可以在系統設定➡️一般➡️輔助使用➡️最下面的輔助使用快速鍵勾選智慧型反相,這樣按三下裝置的實體按鈕,就可以快速切換。控制中心也可以放入輔助使用快速鍵項目。


補充資料:

*iOS 12 也新增了跟 tvOS 10 一樣的UIUserInterfaceStyle,但是沒有作用。

開啟智慧型反相時,在裝置上螢幕截圖還是會截出正常的圖片。如果要截圖的話要接上電腦用 Quick Time 來抓。

accessibilityIgnoresInvertColors 也可以在 Interface Builder 設定,在 User Defined Runtime Attributes 新增 keyPath 並設為 true 即可。細節可參考這篇文章

iOS 12 Adoption

Now that iOS 12 has been released for three weeks, let’s take a look at its adoption.

iOS 12 adoption by Mixpanel on 10/9

The table lists how many days does each version (since iOS 7) took to passed 25%, its previous version, 50%, and 75%. The Final% means its adoption date at the day its next version released.

Version Release 25% Cross 50% 75% Final % Source
iOS 12 2018/9/17 6️⃣ +10 4️⃣ +17 4️⃣ +19 ? ? 📈
iOS 11 2017/9/19 5️⃣ +7 5️⃣ +20 5️⃣ +26 4️⃣ +90 🥉 90.81% 📈
iOS 10 2016/9/13 4️⃣ +4 🥉 +16 🥉 +18 🥉 +89 🥈 91.27% 📈
iOS 9 2015/9/16 🥈 +3 🥈 +8 🥈 +11 🥈 +68 5️⃣ 86.36% 📈
iOS 8 2014/9/17 🥈 +3 6️⃣ +27 6️⃣ +32 5️⃣ +146 4️⃣ 90.50% 📈
iOS 7 2013/9/18 🥇 +1 🥇 +3 🥇 +3 🥇 +33 🥇 95.06% 📈

Data collected from Mixpanel Trends.


iOS 12

  • 2018/09/17: Official released
  • 2018/09/27: Passed 25% after 10 days. The slowest since iOS 7 🙃
  • 2018/10/04: Passed iOS 11 after 17 days. It’s the 4️⃣th since iOS 7
  • 2018/10/06: Passed 50% after 19 days. Also the 4️⃣th

There are numerous factors contributing to the trends and I don’t plan to discuss here. However, while iOS 12 is probably the most stable version in recent years, its adoption rate is not growing the fastest compared to iOS history. It’s still remarkable that an OS with this large user base has half user upgrade within three weeks.

身為 iOS 工程師不該錯過的 iPlayground

最近台灣的 iOS 開發界有一個大事,就是即將在 10/20-21 在台大舉辦的開發者研討會 iPlayground。身為宣傳組的一員,我多半是用官方帳號小編的名義在做介紹。但我今天想用個人的角度談談 iPlayground,它的意義、以及為何你應該來參加。

我學習開發 iOS 已經超過五年。由於不是資訊相關科系出身,完全不認識其他同行,也沒有業界的朋友,前三年幾乎是自己在摸索。任職的公司 CATCHPLAY 願意栽培,2016 年送我去舊金山參加 WWDC。孤身一人踏上美國國土闖盪很有意思,但是我從頭到尾沒有遇到任何台灣人,吸收相對有限,也沒那麼好玩(而且,舊金山 6 月很冷)。

一直到 2016 年底我寫了一個開源的 app 叫 Blahker(專擋蓋版廣告,你可能有用過)。被 CocoaHeads Taipei 的成員 Vincent 邀請去分享。在那之前我都只是在網路上觀望,也不知道自己程式的實力如何。但就是那一次,我遇見了許多有趣的人,獲得許多迴響,也發現自己其實有一些特色是可以跟社群中的大家分享的。

有些軟體工程師寧可面對電腦也不願意面對人群。但是加入軟體開發的社群(任何形式的),對於個人只會有好處。我對自我學習能力很有自信,不過增加了社群參與以後,學習速度還會倍增。有問題你可以找人問、有可能從別人的分享中找到靈感,絕大部分的 bonus 都不是你個人的職涯規劃可以料想得到的。

比如說… 2017、2018 這兩年我就跟大家一起去 WWDC,玩得很開心。Apple 推了什麼新功能新技術,可以聽到不同的評論角度,觀點會跟更多元。有時候還湊熱鬧跑 lab 挑戰蘋果的工程師、甚至一起看個 NBA。上個月還去了東京參加 iOSDC。平時鑽研一些技術或是工作遇到的問題,隨便 PO 在 Facebook、Twitter 上就會有人神來一筆的回答。我最近一個開源專案 如果不是 @yllan 跟我在 Twitter 上往返,我可能兩個月也寫不出來。還有前前一個開源專案 也是在跟 @zonble 討論事情時想到的點子… 這裡不是要廣告自己的東西就不多說了。

iPlayground 是一群熱血的 iOS 工程師個人自發創立的,背後不是任何公司主導。這群人因為出國參加過 WWDC、iOSDC 等大型研討會,看到技術社群的價值、又發現台灣根本沒有這樣的活動,所以自己跳出來做,有一些成員還是因為一起籌備活動才認識的。期待它在台灣變成一個串連水果系技術資源交流、工程師人脈與求職、企業人力資源等各方面需求的平台。我們背後都是來自不同的公司,也沒有收益的目標(相反地,就算賠點錢還是想把這樣的平台做起來)。


你可以看看我們總召 hokila真誠介紹

iPlayground by Hokila


iPlayground 的票價是兩千元,因為在台北舉辦,場地就佔了很高的成本。坦白說由於第一次辦、經驗有限,我們犯了不少錯誤,包括時程安排、宣傳、預算規劃都有改進空間。但是就目前最重要的部分議程(見官網)來看我個人相當滿意。在台灣 iOS 開發圈你可以想得到的許多重要人物都出現在我們的講者名單上,他們也跟團隊成員一樣不支薪,是基於熱情來跟大家分享。我敢說任何去過 iOS 專門技術研討會的 iOS 開發者,一眼就可以看出這些議程跟這場活動的價值。甚至覺得物超所值。

WWDC 的票價就 1599 鎂,還不計算交通食宿。就算去東京參加 iOSDC 也要機票啊。而且只有在台灣舉辦你才能用熟悉的語言與大家交流。

如果沒參加過 iOS 研討會,這其實只是稍微離開自己的舒適圈一點點而已,卻有莫大收穫。就算只參加半天,也是值得。

最後必須提醒,由於活動僅剩三週,眼下看似還有一百多張票可能轉瞬就消失。所以有一點心動還是趕快行動吧。

你還在猶豫是因為你想要!