CoreData with background task

前言

雖然在 iOS 上開發了幾年的時間,但一直到最近才開始使用 CoreData;之前在第一份工作的專案之中是使用 FMDB 來處理資料存取,而後續則是用了 Realm

選擇的原因分別是當時 FMDB 的速度較其餘兩者快速,而後來看上 Realm 的跨平台特色,不過近期開發的感想是能以原生為主的話,就儘量降低對於第三方套件的依賴性。

這篇文章會記錄些什麼

其實這篇文章並不會從頭到尾寫下教學,而把重點放在一些我踩到的雷上,像是⋯⋯

記得要附上 sqlite 的路徑

原先我的 persistentContainer 的產生方式如下

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "OfflineWallet")
    let description = NSPersistentStoreDescription()
    description.shouldInferMappingModelAutomatically = true
    description.shouldMigrateStoreAutomatically = true
    container.persistentStoreDescriptions = [description]
    container.loadPersistentStores { _, error in
        if let error = error {
            fatalError("Unresolved error \(error), \(String(describing: error._userInfo))")
        }
    }
    return container
}()

在模擬器上存取了幾次,每次都有 save 且第二次進入畫面的時候,都可以 fetch 得到資料,但是只要重開 App 就會從頭來過⋯⋯

也就是說其實都只是像是存在 NSManagedObjectContext 上,而並沒有實際地轉成 sqlite

補上指定的 URL 即可解決。

...
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let sqliteURL = documentsDirectoryURL?.appendingPathComponent("OfflineWallet.sqlite")
description.url = sqliteURL
...

performBackgroundTask v.s newBackgroundContext

要實作 backgroundTask 有兩種作法

NSPersistentContainer.performBackgroundTask

persistentContainer.performBackgroundTask { context in
    //do something in background thread
}

NSPersistentContainer 會建立一個 context 在這個 closure 裡頭使用,而重點是當這條 thread 結束之後,這個 context 所管理的物件(NSManagedObjectModel)的所有變數會釋放掉,也就是都會變成 nil

適合用於取得資料並轉型成其他 class / structure 的時候使用。

newBackgroundContext

而如果你必須在後續的程式之中繼續使用 context 所產生的 NSManagedObjectModel 時,你就得要保存其 context;像是建立一個 backgroundContext 並存下來使用:

lazy var backgroundContext = persistentContainer.newBackgroundContext()

//you should use this context to do something what you want
backgroundContext.perform {
//do something like before
}

此時由於這個 context 並沒有被釋放掉,所以其 NSManagedObjectModel 的所有變數便也會持有著;而依然是在其他 thread 上進行,並不會佔據 main thread。

待續

分頁讀取

筆記一下 NSFetchRequest 有提供 fetchLimit 以及 fetchOffset 可以用來做分頁讀取的功能。

SwiftLint

SwiftLint

去年(2018)年末的時候,在 Twitter 上看到一些朋友們在討論著 SwiftLint 的使用,於是便也嘗試在目前公司的專案中導入,來解決 Coding Style 的問題。

Coding Style 的問題

剛進入到這家公司時,最痛苦的事情莫過於毫無章法的 Coding Style,這部分就不一一細數了,詳情可以看前陣子我的 Twitter 動態

專案裡頭每個人寫的格式不同,會造成其他人在閱讀專案時,大幅增加理解彼此想法的成本

簡單來說就是浪費一堆時間在猜你在寫什麼

為了讓專案裡頭的大家有差不多的 Coding Style,可以選擇使用 SwiftLint 來處理這個情況。

實際嘗試

首先先以 SwiftLint 的官方教學來安裝和建構環境,並利用 EthanSwiftLint rules 當作基底來調整,先以別人的規範來看看差異性。

一跑下去便是直接噴了 3000+ issues⋯⋯

可以透過 Rules.md 來逐條看看定義並透過 example 來看怎麼算是 Non TrggeringTriggering;再來一條一條調整改進。

一些心得

目前公司的專案從 3000+ ➡️ 17 warings,而這 17 條是我還沒 refactor 到的 features,所以就還沒那麼急著去調整。

private_outlet 和 private_action

而其中一條規則 private_outlet 給我的感觸挺深刻的,由於我大多數的工作經歷是獨立開發居多,而每個 IBOutlet 都必須為 private 是第一份工作時所踩到的坑;當時公司共有兩位 iOS 工程師,彼此皆為 Junior 的程度,故沒什麼規範和概念,於是便會出現一些神秘的情境⋯⋯

像是不知道為什麼你負責的 UIViewController 刻出來的畫面就是和你想的不太一樣,才發現另一個地方(別人寫的 code)在直接修改畫面的 Layout / value⋯⋯

後來就體會到物件的每個變數和 functions 的 access 問題,而這條規則便是解釋著 IBOutlet 不應該可以直接從其他地方呼叫、修改,像是被這麼做:

fooViewController.fooLabel.text = "Test"

從那時候開始養成的習慣到現在,當發覺其實有其他人也是這麼做,並將它視為一條 rule 的時候真的覺得有點小感動!

整體來說

你可以透過這個 SwiftLint 來反覆思考一些寫程式上的問題,像是 function 的長度、class 的長度以及 Swift 檔案的長度等;如何切割每個物件和 function 等,都是相當值得去思索的習慣問題。

不過也不需要逐條都導入到專案之中,建議是花一些時間找到你最認同的那幾條 rules 來遵循即可!

AWS EC2 with WordPress

前言

Vultr

這個網站原本是在 Vultr 上開一台機器,每個月大概的費用為 USD $6 - 7 元之間,並利用 Certbot 自動更新 SSL 憑證。但後來發現不太會維護那台機器,時常因為記憶體造成資料庫錯誤,每隔兩三天就得去手動重新啟動來解決問題,乾脆就搬家到 WordPress.com 的服務。

WordPress.com

WordPress.com 的好處就是全部幫你處理好好的,然後我使用的是個人版的方案;NT$ 130 / 月,便有提供轉址的功能和一年份免費的網域。不過由於我自己是向 PChome 買 Archie.tw,所以主要是為了轉過去而付費。

但使用服務和自己開一台機器的差異性就在於彈性,像是安裝外掛便被放在商務版的功能之中,而費用為 NT$ 799 / 月。

這樣一用也用了一段時間,直到近期註冊了 AWS 的服務,便決定搬移到 AWS 上。

AWS

在 AWS 上新註冊的用戶可以擁有一年的免費方案,而這個網站目前使用到幾個 AWS 服務分別為

  • EC2
  • Load Balancer
  • Certificate Manager
  • Route 53

這邊來介紹我的流程:

Key Pairs

首先我們先到 EC2 的頁面選擇 NETWORK & SECURITY ➡️ Key Pairs 來建立一組 Key pair,用於之後連接到 EC2 instance

EC2

透過 AWS Markeyplace 開一台新的 instance,使用 WordPress Certified by Bitnami 搭配 t2.micro 的免費方案;而之後若有收費的時候,約為 USD$ 0.012 / 小時,也就是一個月 USD$ 8.64 / 月。
一路照著步驟走,若你本身沒有其他服務要規劃的話,後續的動作都不需要做任何調整,就可以開好一台裡頭已經安裝好 WordPress 的 EC2 了。

這時候你就可以使用那台 EC2 的 Public IP 來開啟你的 WordPress 了!

使用者

在網址的最後加上 /admin 可以開啟管理後台,預設的使用者名稱為 user,而密碼的部分可以透過 EC2 Actions ➡️ Instance Settings ➡️ Get System Log 來查看,裡頭會有標註出密碼的欄位。

綁定個人網域

我們需要透過 Route 53 來處理個人網域的綁定動作,並使用 Load Balancer 和 Certicate Manager 來處理 HTTPS 的連線。

首先先到 Route 53 的 Hosted zones 建立一個 Hosted Zone 備著,其中你會需要將 NS 帶入到購買網域的管理頁面去設定,並進行 Certificate Manager 建立 SSL certificate。

建立憑證的時候,會需要將 CHAME 帶入到 Route 53 裡頭,再來建立一個 Load Balancer 來取得 DNS name,這時候再填入到 Route 53 裡頭便完成了 AWS 這部分的建構。

最後還需要使用最前面所建立的 Key pair 連線到 instance 上,來開啟 HTTPS 的功能。

Bitnami WordPress 詳細的 SSL 圖文教學

⚠️ 幾個需要注意的地方

  • Key Pairs 需要建立在 EC2 instance 之前,且弄丟了你就無法連回去那台 instance 了
  • Route 53、Certificate Manager CHAME 那些設定是需要一些時間轉移的
  • Route 53 和 Load Balancer 是需要收費的功能

整體費用的部分我一個月收再來更新這網站一共得支出多少在 AWS 上,處理完這個之後就可以來補上前陣子的 iOS 心得了!

Bitnami