Mac 開發的神祕面紗:後孃養的嫡長子

原本,標題是「揭開 macOS 開發的神祕面紗」,可想一想,以我目前對 macOS 開發的理解,仍是去掉「揭開」二字吧 😂html

本文不是系統性的文章,更像是 隨筆。回想本身過去 1.6 年的 macOS 開發歷程,挑些有意思的來講。若是想看完就去挖 macOS 這座金礦(若是是的話),你會失望的;且做佚事來讀吧git

注:嚴格地說,應該叫做「macOS 開發」,由於去年起,蘋果將 Mac 操做系統改名爲 macOS;不過,蘋果電腦依舊以 Mac 命名,如 MacBookPro,故而 Mac 開發也說得過去;再加上,以小寫字母開頭做爲文章名,總以爲怪怪的,是以本文混用「Mac 開發」與「macOS 開發」github

----- 長文開始警惕線;不喜請繞行 -----objective-c

0) Mac 是後孃養的嫡長子

說 Mac 是嫡長子,是由於 蘋果就是作電腦起家的。雖然說後來 iPod、iPhone 風生水起,但嫡長子的血統仍是純正的;而 iOS 正是基於 macOS 開發的。這裏的故事不少,感興趣能夠讀讀《喬布斯傳》之類的書或文章。數據庫

惋惜的是,有了 iPhone 這棵搖錢樹以後,Mac 電腦靠邊站了,macOS 天然也被冷落,不到萬不得已,不更新;即便更新,也像擠牙膏同樣。macos

Mac 哪裏被冷落了?多了去了。編程

好比,我每週都會收到一款蘋果給開發者的郵件,本意是告知本週 App 的活躍程度。而我每次收到的郵件內容都是這樣的:小程序

由於我還沒有上架 iOS 應用、只有 macOS App;而 在蘋果看來,macOS App 豈能叫 App ?!是以,這裏的數據是空的…swift

其它的,不勝枚舉。設計模式

1) Mac 是個小市場

有多小?

先說說硬件,這是 2016 第四季度出貨量對比:

設備 出貨量 營收
Mac 537 萬 72 億美圓
iPhone 7,830 萬 543 億美圓

不管是出貨量、仍是營收,均是零頭。

再來看看 App 的數量:

AppShopper 的數據來看,不足 3 萬的 macOS App 數量,不到 iOS App 的 1%;對,是「百分之一」,零頭的零頭

固然,這裏主要統計的是上架 MAS (Mac App Store) 的應用,在 MAS 以外也有不少。不過,2 個數量級的差別,沒跑。

現說說操做系統佔比:

MarketShare 的數據,macOS 僅佔 6.12%,僅有 Windows 用戶的 6.7%.

其中,macOS 版本的分散程度,雖比 Windows 好不少,但也 不如 iOS:

看到這裏,是否是以爲有些心涼,以爲 Mac 好可憐有沒有…

不過,Mac 電腦確實是在慢慢增長的,知名度也在變高。好比,國內現代都市劇中出現的電腦,大多都是 Mac;蘋果也剛剛宣佈 全球 Mac 活躍用戶有 1 億

2) Swift or Objective-C

我開發的應用 (KlibiPiciPic MoveriPasteiTimeriHosts),所有基於 Swift;不過,即便你也打算基於 Swift,仍是建議對 Objective-C 有基本的瞭解。由於,畢竟 Objective-C 是蘋果一直以來使用的開發語言,絕大多數的文檔、教程,都是基於 Objective-C 的。

雖然說能夠很容易地改編爲 Swift、或被 Swift 調用,但這就像是:你有一本英文詞典,理論上就能夠直接看英文文章,由於看見不懂的單詞能夠查嘛;但也知道,這不現實,畢竟你總不能每一個單詞都查吧?

因此:

  • 若是你已經有 Objective-C 基礎,就直接使用 Objective-C 開發 Mac 應用好了。要不要學 Swift?看你本身心情,我不提供建議;
  • 若是你並無 Objective-C 基礎,建議你先學學 Objective-C 基礎,而後再學 Swift,並基於 Swift 開發。

3) Mac 文檔及教程

官方文檔主要有這些:

實際上,因爲咱們通常是「面向 Google 編程」,通常遇到問題都是先搜索,不太須要記錄這些網址。只是,若是你想系統性、深刻地學習某個點時,能夠正向地從官方文檔入手。

不過,對於 蘋果的開發文檔,友情提醒:並不怎麼好。若是套用這句話:
「爲何懂得這麼多道理,卻仍過很差這一輩子?」

即是:
爲何我看了全部 Mac 文檔,卻仍沒法開發 Mac 應用?

文檔更可能是偏向對某個具體知識點的介紹,而若是想系統性地入門 macOS,最好是經過一本好的書,以及本身的練習。因爲 iPhone 的熱銷,市面上 iOS 的書,可謂汗牛充棟。而 macOS 的書呢?呵呵

我本身是看《Cocoa Programming for Mac OS X》這本書入門 macOS 開發的,這幾乎是我在 2015 年能找到的惟一一本基於 Swift 的 macOS 開發教程。另一本是 Swift Development with Cocoa,跟這本書無法比。

其餘 macOS 的書,我看的很少,也沒什麼好推薦的。若是你有以爲哪本書不錯,歡迎留言告訴我。

4) macOS 數據結構及持久化

首先要說的是,雖然說是 macOS 開發,但實際上不少基礎的東西都是通用的,好比 JSON 格式、MySQL 數據庫等等。

另外,macOS 和 iOS 相比,像 TouchBar 這種獨有的東西,並很少;更多的是通用的,或者說是並行的兩套。

使用 plist 文件存儲數據:

  • 默認僅支持簡單的數據結構;此方式僅適合保存少許數據,如偏好設置中的 On/Off 選項
  • 可以使用 UserDefaults 管理默認的 plist 文件。注意:沙盒模式和普通模式下默認的 plist 文件的位置不一樣
  • 可在命令行中使用 defaults 命令來管理 plist 文件中的數據
  • 可以使用 Xcode 打開 plist 文件進行管理

序列化後存儲:

  • 對於自定義類型,適配 NSSecureCoding 協議後,可以使用 NSKeyedArchiver 轉換爲 Data 格式
  • 進而,可存儲在普通文件中,也可存儲於 plist 文件中

Core Data:

  • Core Data 本質上是對數據訪問方式的封裝
  • 對於簡單的數據結構,使用 Core Data 會帶來額外的複雜度,並不划算。對於複雜的應用,Core Data 能夠顯著減小代碼量
  • 持久化方面,Core Data 提供了對象-關係映射 (ORM) 的功能,不編寫任何SQL語句,便可將數據保存在 SQLite 數據庫文件中,也能還原到內存中

CloudKit:

  • 存儲方面,CloudKit 本質上相似於雲端的關係數據庫
  • 除了存儲,CloudKit 更有用的場景,是在多設備、macOS 與 iOS 間同步數據。好比,系統自帶的 Notes 等應用,均是經過 CloudKit 來存儲、同步數據。其中,通知機制能夠最小化須要同步的數據量
  • 再有,就是提供基於 CloudKit 的共享功能

注:數據持久化存儲方式有很是多,也要視具體的需求而定;這裏僅說起一些經常使用的方式。

5) macOS 界面開發

咱們所說 macOS 開發,一般默認指開發「有界面及交互的、能運行在 macOS 上的應用」,其核心,就在於界面及交互

咱們也常聽到 Cocoa,那 什麼是 Cocoa 呢?援引《Cocoa Programming for OS X》中的介紹:

Cocoa is your application’s interface to the window server to receive events and draw to the screen. At the same time it has access to the Unix layer where it can make lower level calls.

也就是說,Cocoa 是這樣一箇中間環節:負責銜接你的應用與窗口系統,同時也可直接操做系統底層。

界面的開發,是個無底洞;能夠是個簡單的單窗口應用,也能夠是 Pages、iMovie 這樣複雜的應用。

對於初學者,建議從菜單欄程序入手。能夠暫時繞開窗口、控件這些複雜的話題,又能夠建立出能解決實際問題的一些應用。好比,iPic 主交互即位於菜單欄:

這部分,可參見我以前寫的教程:Status Bar App 教程是 16 年 4 月寫的,如今來看有些可能已通過時,好比當時是基於 Swift 2.2;不過總體仍是能夠參考的。

回到界面的開發。首先,要理解 App 的總體生命週期。尤爲是 App 啓動時,都作了哪些事、前後順序及依賴是什麼。

而後,實際的工做,就是搞定界面佈局,以及熟悉一個個控件的用法,如 NSButton、NSTextField、NSTableView 等等。建議的學習步驟:

  • 先隨意玩玩,能讓控件跑起來;一些控件複雜,跑不起來也不用以爲沮喪
  • 若是官方有 Programming Guide,認真讀一遍
  • 若是官方有示例程序,學習之,熟悉正確的用法
  • 過一遍 API Reference,瞭解控件全部的可能性和侷限
  • 解決本身實際的問題,真正用起來

我通常的開發步驟:

  • 想清楚數據結構
  • 堆 UI
  • 完成業務邏輯

6) macOS 設計模式之解耦

隨着程序變得複雜,代碼變多,也很容易交織在一塊兒。對於進一步開發和維護,是很是頭痛的事。

怎麼避免這樣的狀況呢?其中一個思路是:解耦

抽象的說,就是 把複雜的東西拆成一個個獨立的模塊,而後經過一些方式讓這些模式有機地組合在一塊兒

有哪些方式呢?順着這個思路,我列出一些概念。

MVC模式 (Model-View-Controller)

  • 這一模式在界面開發裏大量使用,好比你常常看到的 XXViewController,就是其中的 Controller 部分
  • 簡單的說,就是 把界面與邏輯分離。界面部分,如佈局、樣式等。一般,代碼量最多的,都是在 Controller 中。View 與 Controller 之間,經過引用、綁定來傳遞數據,即將數據顯示在界面中、從界面讀取用戶產生的數據

Delegate

  • 有兩個角度來理解代理。以 NSWindowDelegate 爲例,可理解爲 Window 自己有豐富的可定製性,程序可選擇性地實現某些功能、特性
  • 另外一個角度是,一樣對於 NSWindowDelegate,對事件(如窗口即將關閉)的響應,Window 自己是不知道的,或者說是具體的業務相關的。Window 本身作不到,只能委託給本身的「代理」去決定。好比,當窗口即將關閉時,程序提示用戶保存未保存的數據

Callback

  • 對於非實時的操做,可使用 Callback 回調的方式,來解耦調用者和執行者之間的等待
  • 好比,程序在從網絡下載圖片時,可能須要 1ms,也可能須要 2s,程序總不能傻等着。因而,程序告訴下載的模塊:我去忙別的事了,你下載好了告訴我。怎麼告訴?就是經過 Callback 回調機制實現
  • 與之關聯的概念,如代碼塊

Notification

  • 對於「若是…就…」這樣的邏輯,比較適合的是通知機制
  • 這裏的通知,不止是從網絡上推送下來的通知,也能夠是程序內部的通知
  • 好比,用戶在偏好設置的界面中完成帳戶升級後,在程序內發出帳戶類型變動的通知;程序的主窗口以前註冊以監聽這一通知,即可根據帳戶類型實時調整界面

7) 發佈 macOS 應用

本身辛苦開發的程序,一般是願意讓更多人來用的。若是能賺點小錢,固然更好啦。

7.0) macOS 應用簽名

對於簡單的程序,能夠複製到別的電腦上運行,但最好仍是要對程序進行簽名。尤爲是使用 CloudKit 等一些蘋果特性的程序,必須簽名。

怎麼簽名呢?前提是交錢。也就是,必須每一年交給蘋果 $99 的人頭稅,才能成爲蘋果開發者,進而給應用簽名。

7.1) MAS 與沙盒模式

在 MAS (Mac App Store) 上提交的應用,必須運行在沙盒模式中。

沙盒模式有諸多限制,好比,默認不能訪問用戶的任何文件、一些接口沒法使用等等。和 iOS 的沙盒模式相比,macOS 的沙盒模式仍是寬鬆不少的。以訪問文件的權限爲例,應用能夠申請訪問如 Downloads 等指定目錄。向誰申請呢?蘋果,而不是用戶。一旦經過(雖然並不容易),即可直接訪問該目錄,無需用戶受權。

事實上,沙盒模式確實限制了程序的發揮空間,一些應用(如屏幕取詞翻譯、截圖工具)乾脆沒法上架,或者額外開通「Accessibility」權限才能正常工做。而聽說蘋果已再也不放行須要此權限的應用上架。

7.2) MAS 付費方式

蘋果支持多種內購方式,要想經過應用收費,最簡單的方式是:設置程序必須付費才能下載。這樣,程序內無需區分免費版與高級版,無需作任何功能限制,代碼簡單。蘋果系統保證了,使用哪一個 Apple ID 下載的應用,只能在使用哪一個 Apple ID 上登陸的電腦上使用。好比,你本身購買了某個付費應用,直接把 .app 複製到朋友的電腦上,是沒法運行的

不過,這一方式也有侷限:用戶在付費以前,沒法體驗到產品的全部功能,也就很難決定是否要付費。對於這一侷限,一些程序的作法時:在產品官網提供一個全功能、但僅能運行一段時間(如 7 天)的 體驗版。這樣,用戶能夠在體驗全部功能後,決定是否購買。

再進一步,就是 免費版 + 內購的模式。用戶可免費下載應用,但應用僅開放基礎功能,須要內購才能使用高級功能。這樣,既能最大化地獲取用戶,又能適時地收費,個人全部應用都採用此方式,相信也是將來一段時間的趨勢。

對於內購,又分爲一次性購買和訂閱制。一次性購買容易理解;訂閱制能夠有按月、季度、年等不一樣週期。對於訂閱制,又分爲自動續訂和手動續訂。目前,蘋果對於訂閱制、尤爲是自動續訂的訂閱制,審覈較嚴。

另外,還有 消耗型內購,這種在遊戲中較爲常見,好比花錢買裝備,或者爲帳戶充值等。

對於內購的開發,仍是比較繁瑣的,好比要處理展現、購買、用戶購買後退款、恢復、訂閱續訂、訂閱未續訂致使過時等等邏輯。好在,我封裝了 IAPHelper,能夠很方便地處理這些邏輯(以下代碼爲購買部分);開源,能夠 Pod 方式集成,已經在個人產品中應用多年,你們可放心使用。

IAP.purchaseProduct(productIdentifier, handler: { (productIdentifier, error) in
    if let identifier = productIdentifier {
        // The product of 'productIdentifier' purchased.

    } else if let error = error as? NSError {
      if error.code == SKError.Code.paymentCancelled.rawValue {
        // User cancelled

      } else {
        // Some error happened
      }
    }
})複製代碼

7.3) 不完美的 MAS

以前蘋果與微信怒懟的打賞分紅事件,想必讓更多朋友知道了:凡是應用從用戶收到的錢中,蘋果均要收 30% 的拔毛費。

MAS 的諸多限制,以及不菲的拔毛費,讓不少知名的 macOS App 紛紛下架,如 Sketch、Dash 等等。

不過,要在 MAS 以外發布,仍是要作不少事情的,好比下載、支付、退款、激活碼等等。對於小程序,仍是挺繁瑣的,並不划算。另外,畢竟 MAS 還能帶來一些天然流量。

若是在 MAS 以外發布,還有一點須要注意:.app 程序本質上是一個文件夾。若是須要在網絡上傳送(如做爲郵件的附件),最好是進行壓縮,甚至是製做 .dmg 文件,我使用的是 create-dmg 這個小工具,很是方便,生成的樣式也簡單大方。

基於上面的緣由,目前個人應用所有在 MAS 上發佈,還沒有在 MAS 以外發布。

尾巴

macOS 開發的話題還有很是多,好比 Storyboard、綁定、動畫、併發、Undo、Pasteboard、Drag & Drop、本地化、單元測試等等,本文不可能所有說起。而且,寫起來也好累,畢竟必須對這些點有徹底的掌握,纔可能寫出來。暫且挖坑,之後再填。

對 macOS 開發感興趣?歡迎留言交流。


原文:「自在開發」公衆號

相關文章
相關標籤/搜索