Xcode beta with CocoaPods

Xcode 10 beta 的 Swift 版本為 4.2,而若你目前所使用的 Pods 多數為 Swift 4 的話,該怎麼辦呢?
你可以在 Podfile 裏頭加上全域的參數來規範所有 Pods 的 Swift version:

post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['SWIFT_VERSION'] = '4'
        end
    end
end

如此一番便可以輕鬆地在 Pods 還沒全面支援 Swift 4.2 時就可以使用 Xcode 10 Beta 開發👏

CompactMap vs flatMap

直接從 code 來看兩者之間和 map 的差異
CompactMap

let scores = ["1", "2", "3", "four", "5"]
let mapped: [Int?] = scores.map { str in Int(str) }
// [1, 2, 3, nil, 5] 
let compactMapped: [Int] = scores.compactMap { str in Int(str) }
// [1, 2, 3, 5]

flatMap

let users = [User(name: "Archie", scores: [1, 2, 4]), User(name: "ArchieChang", scores: [3,2,5])]
let mapped = users.map { $0.scores }
// [[1, 2, 4], [3, 2, 5]]
let flatMapped = users.flatMap { $0.scores }
// [1, 2, 4, 3, 2, 5]

在使用情境上,CompactMap 可以將 nil 給過濾掉,使得回傳的陣列為 non optional 的型態;
原先還在使用 map + filter 來處理 nil 的部分,可以直接使用 CompactMap 處理,減少多一次的陣列迴圈。
而 flatMap 則是在將所有陣列的內容整合進同一個陣列,如我們需要計算全體使用者的總得分時,便可以先將個別使用者的分數集結成一個陣列來處理。

UserDefaults with Structure

有時候我們會將一些用戶資訊存在 UserDefaults 裡頭,是個方便且直覺的存取方式。
而 UserDefaults 並非是所有型別都可以接受,如你自己建構的 struct 或 class,
就需要先轉成 Data 的格式來存取。
這邊就來介紹如何存取 User 這個 struct:

struct User {
    var ID: String
    var name: String
    var email: String?
}

這是一個簡單的 User structure,若要轉成 Data 的話,得先將 User 宣告成 Codable,
這樣就可以透過 PropertyListEncoder 和 PropertyListDecoder 來處理 User 和 Data 之間的 encode decode。
而最近喜歡使用 extension 的方式來處理 UserDefaults:

extension UserDefaults {
    var user: User? {
        get {
            guard let data = data(forKey: #function) else { return nil }
            return try? PropertyListDecoder().decode(Profile.self, from: data)
        }
        set {
            if let profile = newValue {
                set(try? PropertyListEncoder().encode(profile), forKey: #function)
            } else {
                set(nil, forKey: #function)
            }
        }
    }
}

我們利用 #function 的特性,將 function name (user) 直接作為 UserDefaults 的 key,
再加上一些判斷是否為 nil 的處理,便可以輕鬆底使用 UserDefaults 存取我們所定義的 structure。
存取 UserDefaults 裡頭的 User 就可以變成很單純的 get 和 set:

// get user from UserDefaults
let user = UserDefaults.standard.user
// set user
UserDefaults.standard.user = user

DeviceSupport

每當 iOS Beta 更新時,原先的 Xcode  便會無法支援,需要透過從 Xcode Beta 的 DeviceSupport 複製新的版本到正式版之中才能使用;
反正都會做這件事,不如就將 Xcode Beta 裡頭的 DeviceSupport 上傳到 GitHub 上提供給 iOS 有更新,但還沒下載新的 Xcode Beta 的人使用吧!
傳送門點我

iOS Taiwan jobs

iOS Taiwan jobs

緣起

最近剛把手上的專案都告一個段落,便開始尋找工作上的合作機會。
恰巧看到 f2etw/jobs,透過 GitHub Issues 的方式提供工作資訊,
感覺挺好的,且是個大家都可以共同編輯的地方,於是便有了建立一個 iOS 版本的念頭。

和 f2etw/jobs 差異性

issue title

iOSTaiwan/jobs 僅提供 iOS 的工作機會,且技術較為單純(Objective-CSwift),
所以便選擇在 issue title 上僅提供公司名稱而已;
職稱以及使用的語言則使用 label 來作為區分依據,如 Intern、Junior、Senior、Swift 等。

issue template

我先是參考了 f2etw/jobs 的範本,並加入部分 PTT Soft_Job 版上的徵才格式,如

  • 員工是否需自備工具? (是/否)
  • 公司地址(填寫詳細至號)

 

後記

並在 README 之中,附上一些求職的網站,如 Yourator、indeed 等;
裡頭也都先下好關鍵字,點擊連結可以直接看搜尋結果。
希望可以透過這個專案讓台灣的 iOS 工程師在求職路上有個幫助!
 
之後再陸續整合一些資源到 Archie.tw 以及 iOSTaiwan,仿效 f2etw 的模式,
有興趣的朋友歡迎多加利用👏

ProvisionedDevices

前言

這篇文章的內容會是記錄如何確認目前的 Provisioning Profile 擁有哪些測試裝置,
以便在使用 adhoc 打包時,確保裝置可以執行。

Provisioning Profile Path

~/Library/MobileDevice/Provisioning Profiles/

在 terminal 下執行

security cms -D -I /path/to/MyProfile.mobileprovision

便可以看到相關的資訊,如下圖:
iamge

Facebook 隱私權條款問題

由於之前上架的 App 有使用到 Facebook 的登入功能,
於是這幾天一直收到這類的信件:
Demo
但是由於本身對這方面可以說是完全沒有涉略,
所以便找找有沒有什麼辦法解決。

Free Privacy Policy

於是找到了這個,回答五種題型便可以得到它們產生的條款,
再找個地方貼上補連結到 Facebook 即可!

FirebaseDatabase – Read

之前有寫過 FirebaseDatabase REST API的文章,
而這篇則會是在 iOS 上的使用。

安裝套件

由於 Google 認為 Carthage 的方式不符合他們的使用模式,
畢竟 Firebase 的 framework 並非是開源的,
所以只有提供 CocoaPods 的安裝方式或是直接下載檔案;
而我這邊就以 CocoaPods 來安裝 Firebase 相關的套件,其他則用 Carthage 來管理。

設定

我們在 Firebase console 那先建立好專案並匯入 GoogleService-Info.plist,
如果你有多個 Target 要使用的話,建議放在不同的資料夾,並且設定好 Target Membership。
並且要注意 Firebase console 內的 Database rules,
若沒有做 auth 相關內容的話,記得要調整;
如我開放給 App 讀取但不可寫入的話:

{
  "rules": {
    ".write": "auth != null",
    ".read": true
  }
}

接著在 AppDelegate.swift 中加入

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    // --**--
}

順道提醒一下,若要讓 Database 的資料在離線也能使用上一次的 cache 的話,
需要在 AppDelegate.swift 裡頭加入

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // --**--
    Database.database().isPersistenceEnabled = true
    // --**--
}

官方文件中沒有特別註記,但若在其他地方執行這段程式,則會直接報錯。

讀取資料

Firebase Database 所提供的是一個可監聽的資料庫,
來做到 Realtime Database 的效果;
Reference 便是 path 的概念,
假設我的資料長這樣:

{
    "test": {
        "user": {
            "name": "Archie"
        }
    }
}

則 ref 有幾種設法;

  • 觀察全部的資料: Database.database().reference.observe
  • 只看 test 下的異動: Database.database().reference.child("test").observe
  • 只看 user:Database.database().reference.child("test").child("user").observe

隨著資料的結構,我們可以讓每個地方只專注它需要監聽的部分就好。

CocoaPods

CocoaPods

上一篇介紹 Carthage,這篇寫一下 CocoaPods。
其實我個人是先使用 CocoaPods,後來才部分改用 Carthage 作為主要的管理方式;
而 CocoaPods 的安裝方式也很簡單,可以透過 gem 來安裝:

安裝

sudo gem install cocoapods

不同於 Carthage 的 Cartfile,CocoaPods 的是使用 Podfile
格式有些不同,不過都可以在資料夾下使用 Terminal 輸入初始化的指令:

pod init

系統就會自行建立一個 Podfile,並用 pod search 的指令來找找你要什麼東西。
弄完 Podfile 之後,就可以執行安裝進專案:

pod install

並打開它幫你建立的 .xcworkspace 就好了。

一些分享

  • 可安裝的版本和 GitHub 上寫的不同?

CocoaPods 會建立一個 local 的所有 repo 資訊,若找不到的時候,可以先試著更新它:

pod repo update
  • Carthage 和 CocoaPods 是可以混用的

Carthage

Carthage

Carthage 是一個套件管理的開源軟體,可以使用 Homebrew 安裝:

brew install carthage

和 CocoaPods 的差異在於它並不會將第三方的 Framework 直接加入專案,
而是獨立在外,並在 build 的時候直接將 framework 複製進去到 App 內;
CocoaPods 的話則會在每次 build 的時候同時 build 你所匯入的 framework,
而隨著專案使用到的套件內容越多,則會花越多時間。

去中心化

這個詞最近隨著區塊鏈的爆紅,也常常可以看見。
不過在這邊的情境是,CocoaPods 是由它那邊搜集很多個 repo,提供給我們來安裝;
所以若 CocoaPods 的 repo 資料沒更新,或是作者只放在 GitHub 上,沒有提交到 CocoaPods 的話,
則無法使用。
而 Carthage 則沒有這方面的問題,可以自行將 GitHub 上的專案加入到 Cartfile

github "ReactiveX/RxSwift"

不過這也是比較麻煩的地方,我們就沒有辦法像 CocoaPods 一樣直接在 Terminal 下 pods search RxSwift 來取得資訊。

個人的使用方式

由於我自行在開發,同時會有很多個專案用到相同的 framework(e.g RxSwift、Siren),
原本若是使用 CocoaPods 的話,則會在很多資料夾內都有一樣的東西;
而 Carthage 的話,則是將 FRAMEWORK_SEARCH_PATHS 都指定到同一個資料夾即可,
並在 Build phase 加上 Carthage 的 Run script。
而我大多數只會開發 iOS 的 App,Carthage update 的時候則可以只更新 iOS 的部分:

carthage update --platform iOS