也許會遇到被要求不用 Storyboard 的前提進行編程開發,這裡記錄一下詢問 GPT 大概的流程是什麼,見以下
如果沒有要使用 storyboard,採用全編碼方式編程應該要怎麼做?
GPT :
首先,要從你的AppDelegate
或SceneDelegate
(取決於你的專案設定)開始。在這裡,你需要創建一個窗口(UIWindow
),並設置一個根視圖控制器。不像在Storyboard中,一切都要手動設置。
接著,你的視圖控制器(UIViewController
)將會是構建使用者介面的主戰場。這裡你可以創建視圖(UIView
)、按鈕(UIButton
)、標籤(UILabel
)等UI元件,並且透過程式碼來管理它們的佈局。Auto Layout是你的好朋友,使用約束(Constraints)來確保你的UI在不同裝置和螢幕尺寸上看起來仍然完美。
最後,別忘了對事件進行處理。在Storyboard中,你可能習慣了拖拉連線來處理按鈕點擊等事件,但在全編碼方式中,你需要使用 addTarget 方法來添加這些事件。
這裡有個簡單的範例代碼,幫助你開始:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
return true
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let label = UILabel()
label.text = "Hello, World!"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
這個例子展示了如何創建一個簡單的視圖控制器,並在其中加入一個標籤。當然,這只是冰山一角,真正的挑戰在於如何將這種方式應用於更複雜的界面設計中。
我需要把什麼東西刪掉嗎?
GPT :
當你決定不使用Storyboard,並完全採用編碼方式時,的確有一些事情需要做來調整你的專案設定。首先,你需要移除現有的Storyboard文件,然後更新專案設定,以確保應用啟動時不會尋找或加載Storyboard。來,跟著我做:
刪除Storyboard文件:
- 打開你的Xcode專案,找到
Main.storyboard
(和LaunchScreen.storyboard
,如果你也想用代碼來處理啟動畫面的話),右鍵它們,然後選擇"Move to Trash"(移到垃圾桶)。
更新專案設定:
- 打開你的專案設定,選擇你的應用目標(Target)。
- 在”General”標籤頁下,尋找”Main Interface”,並清空這個欄位(這會告訴Xcode你的應用不會使用Storyboard來加載初始視圖控制器)。
- 如果你刪除了
LaunchScreen.storyboard
,也在"App Icons and Launch Images"下的"Launch Screen File"欄位清空。
修改Info.plist
文件:
- 如果
Info.plist
中有參考到Storyboard的話(如UIMainStoryboardFile
),你需要移除這些參考。 - 如果你移除了
LaunchScreen.storyboard
,也確保從Info.plist
中刪除有關啟動畫面的設定。
更新應用代理(AppDelegate):
- 確保在
AppDelegate
的application(_:didFinishLaunchingWithOptions:)
方法中創建一個UIWindow
實例,並設置一個根視圖控制器,如我之前提供的範例代碼所示。
最後的檢查:
- 清理(Clean)你的專案。
- 建構(Build)並運行(Run),看看是否一切運作正常。
完成這些步驟後,你的專案應該已經完全從Storyboard轉換為編碼方式了。這是一個重要的變更,但只要細心地跟著步驟來,就不會有太大問題。當然,從現在開始,你的UI設計和佈局都將依賴於Swift代碼了。
基於以上條件,如要使用 UITabbarController 需要保留 SceneDelegate 嗎?
GPT :
當你採用全編碼方式開發iOS應用,並且打算使用UITabBarController
時,你確實需要保留SceneDelegate
(如果你的專案是在iOS 13或更高版本上建立的)。在iOS 13及以後的版本中,SceneDelegate
負責管理應用的視圖和生命週期,這與之前的版本(只用AppDelegate
)有所不同。
這裡要強調的是,SceneDelegate
和AppDelegate
在應用架構中扮演不同的角色:
AppDelegate
負責全局的應用級別事件,例如應用啟動、終止等。SceneDelegate
則更集中於管理特定的UI場景(scene)。在支持多任務的iOS設備上,一個應用可以同時擁有多個活躍的場景。
要在全編碼方式下使用UITabBarController
,你可以在SceneDelegate
中設置它作為窗口(window)的根視圖控制器。以下是一個簡單的例子:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
// 創建 UITabBarController 並設置它的視圖控制器
let tabBarController = UITabBarController()
tabBarController.viewControllers = [
createViewController(title: "首頁", backgroundColor: .white),
createViewController(title: "設定", backgroundColor: .lightGray)
]
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
}
private func createViewController(title: String, backgroundColor: UIColor) -> UIViewController {
let viewController = UIViewController()
viewController.view.backgroundColor = backgroundColor
viewController.tabBarItem.title = title
return viewController
}
}
這個範例中,我們創建了一個UITabBarController
,並為它添加了兩個簡單的視圖控制器作為標籤。你可以根據需求進行擴展,加入更多的功能和自定義。
記住,即使是在全編碼的情況下,SceneDelegate
仍然扮演著重要的角色。當你開始搭建你的應用界面時,不要忽略了它。
我該如何判斷 SceneDelegate 是否要刪掉?
GPT :
判斷是否需要刪除SceneDelegate
取決於幾個因素,包括你的應用目標iOS版本、你希望應用支援的功能,以及你的個人偏好。讓我來幫你梳理一下:
目標iOS版本:
- 如果你的應用僅需支持iOS 13及以上版本,保留
SceneDelegate
是有意義的,因為它提供了更靈活的多任務和多窗口管理功能。 - 如果你的應用需要兼容iOS 12或更早版本,你可能會考慮移除
SceneDelegate
,因為這些版本的iOS並不支持多場景(scene)API。
多任務和多窗口支援:
SceneDelegate
的出現主要是為了支援iPad上的多任務功能,如分屏和多窗口。如果你的應用需要這些功能,或者你想為iPad用戶提供更佳體驗,則應保留SceneDelegate
。- 如果你的應用主要是為iPhone用戶設計,且不需要多任務或多窗口支援,你可以選擇移除
SceneDelegate
。
個人偏好和應用架構:
- 有些開發者喜歡保留
SceneDelegate
,因為它可以使應用架構更清晰,並將UI相關的代碼與其他應用生命週期代碼分離。 - 如果你偏好一個更簡單的架構,並且不需要
SceneDelegate
提供的特定功能,那麼刪除它可能會讓你的應用更加精簡。
如果你決定移除SceneDelegate
,記得要進行以下步驟:
- 從你的專案中刪除
SceneDelegate.swift
文件。 - 更新
Info.plist
文件,移除有關UIScene
的配置。 - 修改
AppDelegate
以管理窗口(UIWindow
)的創建和顯示。
最後,無論你選擇保留還是刪除SceneDelegate
,都要確保你的決定符合你的應用需求和目標。
假設我將 SceneDelegate 刪掉的話,UITabBarController 該如何實現?
GPT :
如果你決定刪除SceneDelegate
並使用UITabBarController
,你需要在AppDelegate
中處理窗口(UIWindow
)的創建和配置根視圖控制器。這意味著所有的界面設置和初始視圖控制器的配置將在AppDelegate
中完成。
以下是實現UITabBarController
的步驟,假設你已經從專案中移除了SceneDelegate
:
在AppDelegate
中創建窗口: 首先,需要在AppDelegate
中創建一個新的UIWindow
實例,並將其設置為應用的主窗口。
配置UITabBarController
: 接著,創建一個UITabBarController
實例,並將其設為窗口的根視圖控制器。你可以在這裡添加多個子視圖控制器到標籤欄控制器。
顯示窗口: 最後,需要讓窗口可見,並設置它為主窗口。
以下是一個基本的示例代碼,展示如何在AppDelegate
中設置一個包含兩個標籤的UITabBarController
:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
// 創建 UITabBarController 並設置它的視圖控制器
let tabBarController = UITabBarController()
tabBarController.viewControllers = [
createViewController(title: "首頁", backgroundColor: .white),
createViewController(title: "設定", backgroundColor: .lightGray)
]
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
}
private func createViewController(title: String, backgroundColor: UIColor) -> UIViewController {
let viewController = UIViewController()
viewController.view.backgroundColor = backgroundColor
viewController.tabBarItem.title = title
return viewController
}
}
在這個例子中,setupTabBarController
函數創建了一個UITabBarController
,並為它添加了兩個簡單的視圖控制器作為標籤。你可以根據自己的需求自定義視圖控制器。
記住,一旦移除SceneDelegate
,所有與窗口和視圖控制器相關的配置都應該在AppDelegate
中完成。這樣做的好處是結構更簡單、更直接,尤其是對於不需要iOS 13的多場景特性的應用來說。
開頭的 @UIApplicationMain 跟 @main 有什麼差別嗎?
GPT :
@UIApplicationMain
和@main
都用於標記一個Swift類別作為應用的入口點,但它們在使用和語義上有一些差異:
@UIApplicationMain
:
- 這是較舊的標籤,用於iOS應用開發。
- 當你使用
@UIApplicationMain
標記一個類別時,這個類別需要實現UIApplicationDelegate
協議。 - 這個標記會讓Swift自動生成應用的主函數(
main
函數)。在這種情況下,你不需要手動寫main.swift
文件。 - 它特別針對
UIApplication
,是iOS開發中的特定用法。
@main
:
@main
是一個更現代、更通用的入口點標記,引入於Swift 5.3。- 它可以用於任何Swift應用或程序,不僅限於iOS。這意味著你可以在其他類型的Swift項目中,比如命令行工具或者其他平台的應用中使用它。
- 被
@main
標記的類別同樣是程序的入口點,但這個類別不一定要實現特定的協議。相反,它通常有一個無參數的靜態方法main()
,作為程序開始執行的地方。
在大多數iOS應用案例中,@UIApplicationMain
和@main
可以互換使用。然而,如果你在開發非iOS平台的Swift應用或想要更多的靈活性,@main
是一個更通用的選擇。舉個例子,如果你想要自己管理main
函數的行為,或者在一個Swift程序中有多個類別並希望指定其中一個作為入口點,那麼@main
會是更合適的選擇。
總的來說,@UIApplicationMain
更適用於標準的iOS應用開發流程,而@main
提供了更多的通用性和靈活性,適用於各種Swift程序。