π‘ μ¨λ³΄λ©, Onboarding
μ¨λ³΄λ© νμ΄μ§λ μλ‘μ΄ μ μ λ λ€μ λμμ¨ μ μ λ₯Ό νμν΄μ£Όλ μν μ νλ€. μ μ μκ² μ΄νμ μ¬μ©λ²μ μλ €μ£Όκ±°λ κΈ°λ₯μ λν ν, μ½ν μΈ μν λ±μ 보μ¬μ£ΌκΈ° μν΄ μ¬μ©λλ€.
μ²μμ μ± μ΅μ΄ μ€νμ λνλλ νμ΄μ§, μ°μ»΄ νμ΄μ§ λ±μΌλ‘ κ²μμ νμ λμλ λ°©λ²μ μ°ΎκΈ°κ° μ΄λ €μ λ€. μ¨λ³΄λ©μ΄λΌκ³ λΆλ₯Έλ€λ κ²μ μ΅κ·Όμ μκ²λμλ€. π.. κ°λ°νκ³ μ νλ λ΄μ©μ΄ 무μμΌλ‘ λΆλ¦¬λμ§ μλκ² μ€μνλ€κ³ λκΌλ€. (HIG λ₯Ό λ¨Όμ μ°Ύμλ΄€λ€λ©΄ μ½κ² μ°Ύμκ² λ€..)
μ¨λ³΄λ© νμ΄μ§λ₯Ό μΆκ°νκ³ , μ±μ μ΅μ΄ μ€νμμλ§ λνλκ² νλ μμ λ₯Ό κ°λ°ν΄λ³΄κ² μ΅λλ€!
- Xcode νλ‘μ νΈμ Onboarding storyboard μΆκ°νκΈ°
- Storyboard λ€μ 첫 λ²μ§Έ VC μ Storyboard ID μ§μ νκΈ°
- UserDefaults λ₯Ό μ΄μ©ν΄ μ±μ΄ μ΅μ΄ μ€νμΈμ§ νλ¨νκΈ°
- SceneDelegate ν΄λμ€μμ Root VC μ§μ νκΈ°
- Onboarding VC μμ Main VC λ‘ μ΄λνκΈ°
- λ !! π₯³
1. Xcode νλ‘μ νΈμ Onboarding storyboard μΆκ°νκΈ°
Onboarding μ μν μλ‘μ΄ Storyboardλ₯Ό μμ±νκ³ , View λ₯Ό κΎΈλ©°μ€λ€.
첫λ²μ§Έ View λ₯Ό initial View Controller λ‘ μ§μ ν΄μ£Όλ©΄ νμ΄νκ° μκΈ΄λ€.
2. Storyboard λ€μ 첫 λ²μ§Έ VC μ Storyboard ID μ§μ νκΈ°
λ¨Όμ OnboardingViewController λ₯Ό λ§λ€κ³ , Custom Class λ‘ μ§μ ν΄μ£Όμλ€. μ½λλ μμ§ μμ±νμ§ μμλ€.
μ±μ 첫 μ€ν μ¬λΆλ₯Ό νλ¨ν΄ Onboarding νμ΄μ§λ₯Ό λμμ€ κ²μΈλ°, μ΄λ Storyboard ID κ° νμνλ€.
μ΄λ€ κ°μΌλ‘ μ§μ νλμ§ μ νν λͺ¨λ₯΄κ² μ§λ§, ViewController ν΄λμ€ μ΄λ¦κ³Ό λμΌνκ² νλ κ²½μ°λ₯Ό λ΄μ λμΌνκ² νλ€.
μ΄κ°λ¨ ν¬λ리μ€νΈ λ§λ€κΈ° ν¬μ€ν μμ λ§λ€μ΄λ Main Storyboard μ View Controller λ Storyboard ID λ₯Ό μ§μ ν΄μ£Όμλ€.
μ¬λ¬κ°μ VC ꡬλΆμ νΈνκ² νκΈ° μν΄ ν΄λμ€λͺ λ TodoViewController λ‘ λ³κ²½νλ€.
3. UserDefaults λ₯Ό μ΄μ©ν΄ μ±μ΄ μ΅μ΄ μ€νμΈμ§ νλ¨νκΈ°
μ΄μ ν¬μ€ν μμ μμ±νλ μ½λλ₯Ό κ·Έλλ‘ μ΄μ©νλ€.
μ±μ μ΅μ΄ μ€νμΈμ§λ₯Ό νλ¨νκΈ° μν΄ method μμλ defaults DB μ isFirstTime key μ΄ μ‘΄μ¬νλμ§λ‘ νλ¨νκ³ μλ€.
public class Storage {
static func isFirstTime() -> Bool {
let defaults = UserDefaults.standard
if defaults.object(forKey: "isFirstTime") == nil {
defaults.set("No", forKey:"isFirstTime")
return true
} else {
return false
}
}
}
4. SceneDelegate ν΄λμ€μμ Root VC μ§μ νκΈ°
κ²μμ ν΄λ³΄λ©΄ AppDelegate ν΄λμ€μμ Root VC λ₯Ό μ§μ νλ λ°©λ²λ λμ€λλ°, iOS13 μ΄μ μ λ°©μμΌλ‘ μ±μ΄ crash λ μλ μλ€.
iOS13 μ΄νμ SceneDelegate ν΄λμ€κ° μΆκ°λμκ³ , ν΄λΉ ν΄λμ€μμ Root VC λ₯Ό μ§μ νλ λ°©μμ΄ μ ν©ν κ² κ°λ€.
μ΄μ λ°©μμΌλ‘ μ¬μ©νκ³ μΆλ€λ©΄ μ¬κΈ° μμ νμΈν μ μλ€.
SceneDelegate ν΄λμ€μ scene method μμ Root View Controller λ₯Ό μ§μ νλ©΄ λλ€.
setRootViewController(scene) method λ₯Ό λ°λ‘ μ μν΄μ νΈμΆνλ€.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
setRootViewController(scene)
}
// ...
}
setRootViewController(_ scene:) method λ 첫 λ²μ§Έ μ€νμΈμ§ μ¬λΆμ λ°λΌ Storyboard μ΄λ¦κ³Ό μλ³μλ₯Ό μ§μ νκΈ° μν μν μ νλ€.
setRootViewController(_ scene: name: identifier:) method λ Storyboard μ΄λ¦κ³Ό μλ³μλ₯Ό μΈμλ‘ λ°μ, ν΄λΉνλ ViewController λ₯Ό Root View Controller λ‘ μ§μ νκΈ° μν μν μ νλ€.
extension SceneDelegate {
private func setRootViewController(_ scene: UIScene){
if Storage.isFirstTime() {
setRootViewController(scene, name: "Onboarding",
identifier: "OnboardingViewController")
} else {
setRootViewController(scene, name: "Main",
identifier: "TodoViewController")
}
}
private func setRootViewController(_ scene: UIScene, name: String, identifier: String) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let storyboard = UIStoryboard(name: name, bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: identifier)
window.rootViewController = viewController
self.window = window
window.makeKeyAndVisible()
}
}
}
1. private method λ₯Ό λ°λ‘ λνλ΄κΈ° μν΄μ extension ν€μλλ₯Ό μ΄μ©ν΄ ν΄λμ€λ₯Ό νμ₯μμΌ°λ€.
2. λ method λ μ΄λ¦μ κ°μ§λ§, νλΌλ―Έν°λ₯Ό λ€λ₯΄κ² ν΄ Overloading λ°©μμ μ μ©μμΌ°λ€.
μ΄ λ°©λ²λ€μ κ°μΈμ μΌλ‘ μ μ©ν λ°©μμ΄λΌ μ ν©ν λ°©λ²μ΄ μλ μλ μλ€. ( νΉμ κ°μ ν΄μΌν λΆλΆμ΄ μλ€λ©΄ λκΈ λ¨κ²¨μ£ΌμΈμ π₯Ί)
5. Onboarding VC μμ Main VC λ‘ μ΄λνκΈ°
μμ κ³Όμ κΉμ§ μ§ννλ©΄, μ¨λ³΄λ© νμ΄μ§κ° λ° κ²μ΄λ€! νμ§λ§ Onboarding VC μμ Main VC λ‘ μ΄λνλ μ½λλ₯Ό μμ±ν΄μ£Όμ΄μΌ μ΄λμ΄ κ°λ₯νλ€. κ°λ³μ μΌλ‘ μμ±νμ ¨μΌλ©΄ λ¬Έμ κ° μλ€ π
μ€ν 리보λμμ λ§λ€μλ λ²νΌμ Action μ μΆκ°ν΄μ£Όμκ³ , MainVC λ‘ μ΄λνλ μ½λλ₯Ό μμ±νλ€.
SceneDelegate μμ RootVC λ₯Ό μ§μ νλ λ°©μκ³Ό λΉμ·νλ€.
presentMainVC method μ λ°©μμ μλμ κ°λ€.
- storyboard μ§μ νκΈ°
- view controller μ§μ νκΈ°
- view controller κ° λνλλ λ°©μ μ€μ νκΈ°
- view controller λμμ£ΌκΈ°
import UIKit
class OnboardingViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func nextButtonClicked(_ sender: Any) {
presentMainVC()
}
private func presentMainVC() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "TodoViewController") as! TodoViewController
vc.modalPresentationStyle = .fullScreen
present(vc, animated: false, completion: nil)
}
}
6. λ !! π₯³
λλ°μ΄μ€μμ μ€ννλ©΄ Onboarding νμ΄μ§κ° λνλκ³ , Next λ²νΌ ν΄λ¦μ Todo νμ΄μ§κ° λνλλ€.
μ°Έκ³ λ‘, UserDefaults λ‘ μ μ₯ν κ°μ μ±μ μμ νμ λ μμ λκΈ° λλ¬Έμ λλ°μ΄μ€μμ λ€μ νμΈνκ³ μΆλ€λ©΄ μμ ν μ€μΉν΄μ€μΌνλ€.
μ¨λ³΄λ© κ°μ΄λμ λν΄ μ°Έκ³ νλ©΄ μ’μ λ¬Έμ λ° λ§ν¬
- κ°μΈμ μΌλ‘ λμμΈκ³Ό κΈ°νμ λν΄μλ μκ²λλ©΄ λ κ°λ°μ΄ μλ―Έμμ΄μ§λ κ² κ°λ€.
- brunch.co.kr/@blackindigo-red/16
- developer.apple.com/design/human-interface-guidelines/ios/app-architecture/onboarding/
μ°Έκ³ ν λ§ν¬
μ°κ΄λ ν¬μ€ν