λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🍎 iOS/UIKit

[iOS/Swift] μ˜¨λ³΄λ”©(Onboarding) νŽ˜μ΄μ§€ λ§Œλ“€κΈ° - Storyboard, UserDefaults, SceneDelegate

by Danna 2021. 3. 8.
728x90
728x90

πŸ’‘ μ˜¨λ³΄λ”©, Onboarding

μ˜¨λ³΄λ”© νŽ˜μ΄μ§€λŠ” μƒˆλ‘œμš΄ μœ μ €λ‚˜ λ‹€μ‹œ λŒμ•„μ˜¨ μœ μ €λ₯Ό ν™˜μ˜ν•΄μ£ΌλŠ” 역할을 ν•œλ‹€. μœ μ €μ—κ²Œ μ–΄ν”Œμ˜ μ‚¬μš©λ²•μ„ μ•Œλ €μ£Όκ±°λ‚˜ κΈ°λŠ₯에 λŒ€ν•œ 팁, μ½˜ν…μΈ  μƒ˜ν”Œ 등을 보여주기 μœ„ν•΄ μ‚¬μš©λœλ‹€.

 

μ²˜μŒμ— μ•± 졜초 μ‹€ν–‰μ‹œ λ‚˜νƒ€λ‚˜λŠ” νŽ˜μ΄μ§€, μ›°μ»΄ νŽ˜μ΄μ§€ λ“±μœΌλ‘œ 검색을 ν–ˆμ„ λ•Œμ—λŠ” 방법을 μ°ΎκΈ°κ°€ μ–΄λ €μ› λ‹€. μ˜¨λ³΄λ”©μ΄λΌκ³  λΆ€λ₯Έλ‹€λŠ” 것을 μ΅œκ·Όμ— μ•Œκ²Œλ˜μ—ˆλ‹€. πŸ™‚.. κ°œλ°œν•˜κ³ μž ν•˜λŠ” λ‚΄μš©μ΄ λ¬΄μ—‡μœΌλ‘œ λΆˆλ¦¬λŠ”μ§€ μ•„λŠ”κ²Œ μ€‘μš”ν•˜λ‹€κ³  λŠκΌˆλ‹€. (HIG λ₯Ό λ¨Όμ € μ°Ύμ•„λ΄€λ‹€λ©΄ μ‰½κ²Œ μ°Ύμ•˜κ² λ‹€..)

 

Human Interface Guidelines

 

μ˜¨λ³΄λ”© νŽ˜μ΄μ§€λ₯Ό μΆ”κ°€ν•˜κ³ , μ•±μ˜ 졜초 μ‹€ν–‰μ‹œμ—λ§Œ λ‚˜νƒ€λ‚˜κ²Œ ν•˜λŠ” 예제λ₯Ό κ°œλ°œν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€!

  1. Xcode ν”„λ‘œμ νŠΈμ— Onboarding storyboard μΆ”κ°€ν•˜κΈ°
  2. Storyboard λ“€μ˜ 첫 번째 VC 의 Storyboard ID μ§€μ •ν•˜κΈ°
  3. UserDefaults λ₯Ό μ΄μš©ν•΄ 앱이 졜초 싀행인지 νŒλ‹¨ν•˜κΈ°
  4. SceneDelegate ν΄λž˜μŠ€μ—μ„œ Root VC μ§€μ •ν•˜κΈ°
  5. Onboarding VC μ—μ„œ Main VC 둜 μ΄λ™ν•˜κΈ°
  6. 끝 !! πŸ₯³

1. Xcode ν”„λ‘œμ νŠΈμ— Onboarding storyboard μΆ”κ°€ν•˜κΈ°

Onboarding 을 μœ„ν•œ μƒˆλ‘œμš΄ Storyboardλ₯Ό μƒμ„±ν•˜κ³ , View λ₯Ό κΎΈλ©°μ€€λ‹€.

첫번째 View λ₯Ό initial View Controller 둜 지정해주면 ν™”μ‚΄ν‘œκ°€ 생긴닀.

 

[v] is Initial View Controller

2. Storyboard λ“€μ˜ 첫 번째 VC 의 Storyboard ID μ§€μ •ν•˜κΈ°

λ¨Όμ € OnboardingViewController λ₯Ό λ§Œλ“€κ³ , Custom Class 둜 μ§€μ •ν•΄μ£Όμ—ˆλ‹€. μ½”λ“œλŠ” 아직 μž‘μ„±ν•˜μ§€ μ•Šμ•˜λ‹€. 

 

μ•±μ˜ 첫 μ‹€ν–‰ μ—¬λΆ€λ₯Ό νŒλ‹¨ν•΄ Onboarding νŽ˜μ΄μ§€λ₯Ό λ„μ›Œμ€„ 것인데, μ΄λ•Œ Storyboard ID κ°€ ν•„μš”ν•˜λ‹€.

μ–΄λ–€ κ°’μœΌλ‘œ μ§€μ •ν•˜λŠ”μ§€ μ •ν™•νžˆ λͺ¨λ₯΄κ² μ§€λ§Œ, ViewController 클래슀 이름과 λ™μΌν•˜κ²Œ ν•˜λŠ” 경우λ₯Ό λ΄μ„œ λ™μΌν•˜κ²Œ ν–ˆλ‹€. 

 

Onboarding Storyboard

 

μ΄ˆκ°„λ‹¨ νˆ¬λ‘λ¦¬μŠ€νŠΈ λ§Œλ“€κΈ° ν¬μŠ€νŒ…μ—μ„œ λ§Œλ“€μ–΄λ‘” Main Storyboard 의 View Controller 도 Storyboard ID λ₯Ό μ§€μ •ν•΄μ£Όμ—ˆλ‹€.

μ—¬λŸ¬κ°œμ˜ VC ꡬ뢄을 νŽΈν•˜κ²Œ ν•˜κΈ° μœ„ν•΄ 클래슀λͺ…도 TodoViewController 둜 λ³€κ²½ν–ˆλ‹€.

 

Main Storyboard

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 둜 μ €μž₯ν•œ 값은 앱을 μ‚­μ œν–ˆμ„ λ•Œ μ‚­μ œλ˜κΈ° λ•Œλ¬Έμ— λ””λ°”μ΄μŠ€μ—μ„œ λ‹€μ‹œ ν™•μΈν•˜κ³  μ‹Άλ‹€λ©΄ μ‚­μ œ ν›„ μ„€μΉ˜ν•΄μ€˜μ•Όν•œλ‹€.

 

 


μ˜¨λ³΄λ”© κ°€μ΄λ“œμ— λŒ€ν•΄ μ°Έκ³ ν•˜λ©΄ 쒋을 λ¬Έμ„œ 및 링크

μ°Έκ³ ν•œ 링크

μ—°κ΄€λœ ν¬μŠ€νŒ…

 

[iOS] UserDefaults λ₯Ό μ΄μš©ν•΄ 데이터 μ €μž₯ν•˜κΈ°, μ•± 졜초 μ‹€ν–‰ μ—¬λΆ€ νŒλ‹¨ν•˜κΈ°

UserDefaults class UserDefaults : NSObject πŸ’‘ An interface to the user’s defaults database, where you store key-value pairs persistently across launches of your app. μ‚¬μš©μžμ˜ defaults λ°μ΄ν„°λ² μ΄μŠ€..

jellysong.tistory.com

 

[iOS] TableView 둜 μ΄ˆκ°„λ‹¨ TodoList λ§Œλ“€κΈ°

이전에 ν¬μŠ€νŒ…ν•œ UITableView, UITableViewCell, Protocols 을 μ΄μš©ν•΄μ„œ 앱을 μ‹€μ œλ‘œ λ§Œλ“€μ–΄λ³Όκ²Œμš”. κ³΅μ‹λ¬Έμ„œλ₯Ό 보고 μ •λ¦¬ν–ˆλ˜ λ‚΄μš©λ“€μ΄λΌ μ–΄λ ΅κ²Œ μž‘μ„±ν•œκ²ƒ κ°™μ•„μ„œ μ‹€μŠ΅μœΌλ‘œ ν•œ 번 더 ν™˜κΈ°ν•˜λ €κ³  ν•©λ‹ˆλ‹€!

jellysong.tistory.com

 

728x90
728x90