## first View
- 在 storyboard 中點選要設為啟動的 controller 後, 在屬性視窗勾選 is initial controller
## nav, tab controller 使用
- embed in: 是在當前所選的 controller 使用
- cmd + shift + L: 是直接新增一個獨立的
## 切換 controller
Use this shortcut to instantiate ViewController in Swift
https://chanakya-hirpara.medium.com/use-this-shortcut-to-instantiate-viewcontroller-in-swift-ecba7ea6136f
How to transition from login screen to tab bar controller
https://fluffy.es/how-to-transition-from-login-screen-to-tab-bar-controller/
IOS Swift 界面跳轉以及傳值
https://www.twblogs.net/a/5ee86a086040a668d92fdc83
Swift 不同Controller互動 與 Navigation Bar
https://cdfq152313.github.io/2016-10-03/
## 少量的使用者資訊
UserDefault
https://medium.com/@albert1994/%E4%BD%BF%E7%94%A8swift%E9%96%8B%E7%99%BCapp-%E7%B0%A1%E6%98%93%E5%84%B2%E5%AD%98-userdefault-eda46f6e28ea
save time
https://stackoverflow.com/questions/55776143/how-to-store-date-in-userdefaults
## Xcode 中如果檔案重複會怎麼樣呢?
在你腦袋不清楚的時候會掉入無窮迴圈, 試著做了所有的嘗試之後. 最後還需要你剛好從版本控制中看到那筆可愛的檔案
errMsg
Multiple commands produce '/Users/CymmetrikDev2/Library/Developer/Xcode/DerivedData/EzPrint-egdfssexygmyfocjtgihqezjdaqd/Build/Intermediates.noindex/EzPrint.build/Debug-iphoneos/EzPrint.build/Objects-normal/arm64/BaseHttpAPI.stringsdata'
Target 'EzPrint' (project 'EzPrint') has compile command for Swift source files
## custom tableview cell, u need konw
其實主因是不熟悉 uikit 框架, 在使用某些物件時沒有依據規則導致發生預期的例外。比如這次使用到的 UINib(nibname, identity)....
## bluetooth - pravicy
需要設定相關的權限說明,否則無法使用藍芽。以下兩個屬性在開啟新專案時就已經建立在 project info 中。(不確定是不是 brook 添加的)
而且有預設的提示文字,根據手機當言的語系來做呈現
```swift=
< ios 13: Privacy - Bluetooth Peripheral Usage Description
>= ios 13: Privacy - Bluetooth Always Usage Description
```
## stroyboard view 與 view 在畫面中是誰在誰上面?
透過 storyboard 左邊控件列表越往下,显示就会越往上,这个是可以拖动顺序的。
## button layer.cornerRadius
在設定 background 時,執行到目標手機時效果都沒有出來(background configuration)。所以後來改用另一個設定(view)的 background,但沒辦法直接設定 connerRadius。所以改從 user defined runtime attribute 增加屬性
```swift=
//key path
layer.cornerRadius
//Type
Number
//value
16
```
上述設定都透過 storyboard,都沒有透過程式碼。
## swift 計算小數點的運算
由於 Swift 程式語言儲存浮點型的方式問題, 浮點型 (Double/Float) 的精度丟失問題是必然會發生的。解決這個問題的方法不多,但是講回來他的小數位數補得很滿,所以也不至於丟失太多。(其實其他語言也是一樣,只是大多會自動配上四捨五入
網上查了很大多數的解決方案
要點是運算都用同一個型別,最後轉出給伺服器實在改為字串。
- Json 全部改用 Double,不用 Float。在各系統間也能達到一制,不用再轉來轉去
- Json 全部改用 Decimal,但在 Json decode & encode 需要多一手轉換,移去預設的 Double 機制。
- Json 全部改用 String,比較麻煩的是如果要計算都還需要再轉乘數值,到後端也是相同的概念。但這個方法幾乎可以避免精度失真
- 最後是將小數位數變成整數做運算,ex: 10.23 先乘上 100 得到 1023 後再下去做整數的運算,其實很多金錢的運算也會這麼做。
最後考量 App 本身對於這些後端來的資料不進行計算,為了降低網路傳輸量。想讓後端如果有小數點的都用字串來交換資料,當然也可以再轉換成四捨五入,但可能未來在邏輯增加時有丟失資料的可能性。
## localization
- [Cocoa Keys](https://dev**eloper.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW1)
- [iOS 10 and Permissions localization description](https://stackoverflow.com/questions/38954885/ios-10-and-permissions-localization-description)
- [#31 多語系設定 Localization](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E6%95%99%E5%AE%A4/ios-31-%E5%A4%9A%E8%AA%9E%E7%B3%BB%E8%A8%AD%E5%AE%9A-localization-ffe31a772677)
- localized 帶參數,可透過 string format & String.localizedStringWithFormat & CVarArg 來完成
- [Formatting Localized Strings with Multiple Values](https://stackoverflow.com/questions/51369282/formatting-localized-strings-with-multiple-values)
- [How to create a String with format?](https://stackoverflow.com/questions/24074479/how-to-create-a-string-with-format)
- [localizeWithFormat and variadic arguments in Swift](https://stackoverflow.com/questions/27914053/localizewithformat-and-variadic-arguments-in-swift)
- sample code
```swif=1
// localable.string
"loginFailedAPI"="error msg:%1$@, code: %2$d";
// code
var args = [CVarArg]()
args.append("internal err")
args.append(500)
let nsStr = NSLocalizedString("loginFailedAPI", comment: "")
let result = String.localizedStringWithFormat(nsStr, args)
```
關於藍芽、GPS 的提示如果要走自定義的多語系,需要新增 string file 檔名只能是 InfoPlist,然後有固定的 key 值,比如 “Privacy - Bluetooth Peripheral Usage Description” 對應的 key 會是 "NSBluetoothPeripheralUsageDescription",那就必須使用這組 key 來調整開啟藍芽的提示訊息內容。
## xcode 不同專案要複製檔案
通常你會看到兩種情形,加進來的 swift 檔案找不到 target membership,另一種是看的到 target membership 但無法加入版控....
上述的步驟先在專案中建立相同的 group,再將檔案透過 finder 複製過來,並且透過 add files to "your project name"。(另外也試過不建立 group 直接加入複製過來的 folder + file)
[將 Xcode 專案的檔案 & 畫面複製到另一個專案](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E5%B0%87-xcode-%E5%B0%88%E6%A1%88%E7%9A%84%E6%AA%94%E6%A1%88-%E7%95%AB%E9%9D%A2%E8%A4%87%E8%A3%BD%E5%88%B0%E5%8F%A6%E4%B8%80%E5%80%8B%E5%B0%88%E6%A1%88-7759ca37e02e)
- Step1: 讓兩個專案的目錄同時出現在螢幕中
- Step2: 將要複製的檔案透過拖拉的方式移動到另一個專案對應的位置
- Step3: **這裡的選擇很重要** 請選擇:
- Destination: 勾 copy items if needed
- Added folders: 選 create groups
- add to targets: 選 "your project name"
## change info.plist location
### step
- 將 info.plist 移動到位置後,設定 location 為 relative to project
- 找專案屬性的 Target -> Build Setting -> packaging -> info.plist File -> 將路徑改為現在的路徑
## SceneDelegate function is never called
情竟是在初始化 storyboard app 專案時,依據現有專案調整專案目錄後 debug 時會出現黑畫面網上還找不到解方(情境不相同
後來開新專案後可正常執行,所以紀錄以下步驟,請依序做
- 專案建立後先跑 debug
- 設定專案屬性 ex: env, core, infra, debug/release config, project setting
- 設定好後再跑一次 debug
- 移動 info.plist 到指定目錄,並到 project setting
- 再跑一次 debug
- 在移動 SceneDelegate AppDelegate 到指定目錄
- 再跑一次 debug
- 最後在移動跟 view 相關的
- 這樣就不會再遇到這個問題了
## segmented controll & 畫面切換
segmented controll 可以想像畫面上方有 nav bar,但沒有實作切換分頁的效果。以下的文章介紹都是如何透過 segmented controll 來達成畫面切換。
**segmented controll 常見搭配招式如下**
- 搭配 contrainer view,是 apple 提供的 component。[# Switch between container views using segmented control](https://www.youtube.com/watch?v=A6vxDDAUj2o)、[# 利用多個 container view 切換頁面](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E5%88%A9%E7%94%A8%E5%A4%9A%E5%80%8B-container-view-%E5%88%87%E6%8F%9B%E9%A0%81%E9%9D%A2-6d00fe848572)
- 搭配 controller view,透過撰寫程式碼來完成控制。約六份中那 [# How to Use Child ViewControllers (Container Views) in Swift](https://www.youtube.com/watch?v=B5-1_aR20rE)
- 多個子 view 可透過 array 來管理,就只需一個屬性。ex: uiViews = \[UIView\]()
**手刻 segmented**
[# How to Make a Custom Segmented Control (iOS, Xcode 8, Swift 3)](https://www.youtube.com/watch?v=xGdRCUrSu94)
## scroll view & stackview 切換畫面
[ref][https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/stack-view-scroll-view-%E8%A3%BD%E4%BD%9C%E5%88%86%E9%A0%81-tutorial-%E6%87%B6%E5%BE%97%E5%AF%AB%E7%A8%8B%E5%BC%8F%E7%89%88-7ff9021317a0]
因為設定上不熟悉,因而特別記錄這篇。
- 要點
- scroll view 必要設定除了上下左右的約束,詳細的拖拉範圍大小
- scroll view 拖拉範圍大小對應的是 **content layout guide**
- scroll view 中的 ui item 要設定與螢幕對應的關係是 **frame layout guide**
**步驟**
1. 新增 scroll view 並設定上下左右 constraint
2. 新增 stackview 於 scroll view 中
- 設定 distribution(cmd + opt + 5) 為 fill equally
- 透過 cmd 同時選取 "stack view" & "content layout guide" 並設定上下左右的 constraint
3. 新增 View 於 stackview 透過 cmd 同時選曲 "View" & "frame layout guide" 並設定大小同螢幕
- 勾選 "Equal Widths" & "Equal Heights"
## Apple devoloper 新增 account
[Authorise an Additional User to your iOS Developer Account ](https://support.appmachine.com/support/solutions/articles/80000978467)
**Step**
1. Login to App Store Connect (https://appstoreconnect.apple.com/).
2. Open the Users and Access section.
3. Click the '+' button in the top-left corner of the page.
4. Enter the new users details.
5. Grant the user with at least the Admin or App Manager role.
6. Enable 'Access to Certificates, Identifiers & Profiles'.
**後台相關**
- [Apple store connect](https://appstoreconnect.apple.com)
- MAC 上架 app 的程式: Transpoter
## signin with apple id on website
- [Sign in with Apple Tutorial, Part 4: Web and Other Platforms](https://sarunw.com/posts/sign-in-with-apple-4)
- [How to configure Sign In with Apple](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003)
- [sign_in_with_apple clientconfigi scope](https://developer.apple.com/documentation/sign_in_with_apple/clientconfigi/3230955-scope)
下述的流程是由第一個跟第二個參考連結而來的,一開始只看第二個後來發現文章中沒有特別提及 App IDs (推測是在其他部分提到),所以才去找了第一個。
### Step
**Step** register App IDs => register ServiceID(client ID, redirectURL) => private key => Apple Service Email Notification(有使用我們服務並且想跟我們聯絡的)
- Step1 register App IDs (主要設定這組 App IDs 有提供哪些能力,供後面其它的服務來設定 App IDs 取得能力)
- 從 Apple Develope 後台找到 **Certificates, Identifiers & Profiles** => 點選左邊選單 Identifiers => 點擊上面的 "+" 號在上面的 “Identifiers” 的左側
- 選取 App IDs 並點擊 continue
- 跳轉畫面後要輸入 Description 與 Bundle ID(畫面上面有規則),滑動到下方的功能清單點選 **Domain associated**、 **Sign In with Apple** (右邊有 edit 按鈕記得點進去看一下),回到上點 continue
- 到了確認頁面後確認沒問題後按 Register
- Step2 register ServiceID(client ID, redirectURL) (主要是提供 Web 能使用 Apple ID 登入的功能)
- 從後台找到 Certificates, Identifiers & Profiles => 點選左邊選單 Identifiers => 點擊上面的 "+" 號在上面的 “Identifiers” 的左側
- 選取 Service IDs 點擊 Continue
- 跳轉畫面後要輸入 **Description 與 identifier** 並且勾選 **Sign In with Apple**,此時點擊它旁邊的 **Configure**
- 選取對應的 **App ID**
- 設定 **domain name** (不需要包含 https://
- 設定 return url 提供 Apple ID 登入後回傳的資訊
- 按下 Save
- Step3 create private key (主要提供 server 與 Apple servie 通訊時所需使用的 client_secret)
- Certificates, Identifiers & Profiles => 點選左邊選單 Identifiers => 點擊上面的 "+" 號在上面的 “Identifiers” 的左側
- 選取 Key 並點 continue => 點擊 register a new key
- 跳轉畫面後輸入 key a name 並勾選 **Sign In with Apple** ,接著點擊旁邊的 Configure 選取對應的 App ID 後按下 save
- Apple 會生成 key ID & p8 檔案,這個檔案要保存好只會有這一次下載,不見只能重新再生成一個
- Step4 設定 Apple Service Email Notification
### notice
- Apple ID 登入使用到的技術是等同於: OAuth 2.0 and OpenID Connect
- user email 可能會取不到,這段到時要確認。若真的得另想解決方案
- 使用 Apple JS 時有四個參數
- clientId : Service ID,
- scope : 可以請求使用者提供 name & Emai,for example, `"scope=name email"`.
- redirectURI: Apple ID 登入後要將資訊給?
- state: 減少 CSRF 攻擊的風險,文章中有提供如何產生唯一碼 [Google where they use SHA1 over a random string]([https://developers.google.com/identity/protocols/OpenIDConnect?hl=fr#createxsrftoken](https://developers.google.com/identity/protocols/OpenIDConnect?hl=fr#createxsrftoken))