๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS/iOS

[iOS] Background์—์„œ Timer์ž‘๋™ํ•˜๊ฒŒ ํ•˜๊ธฐ(Allow timer to work in the background) Swift

by Fomagran ๐Ÿ’ป 2020. 12. 7.
728x90
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š” Foma ์ž…๋‹ˆ๋‹ค!

 

์˜ค๋Š˜์€ ํƒ€์ด๋จธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋‹ค๊ฐ€ ํ™”๋ฉด์„ ์ž ๊ทธ๊ฑฐ๋‚˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ๊ฐ”๋”๋‹ˆ ํƒ€์ด๋จธ ์‹œ๊ฐ„์ด ์ž˜ ์ž‘๋™๋˜์ง€ ์•Š๋Š”๊ฑฐ์—์š”.

 

๊ทธ๋ž˜์„œ ์ด๊ฒŒ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ๋Š” ์•ˆ๋Œ์•„๊ฐ€๋Š”๊ฑด๊ฐ€? ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜์ง€? ํ•˜๋ฉด์„œ ๊ตฌ๊ธ€๋ง์„ ํ•˜๋‹ค๋ณด๋‹ˆ "์•ฑ์ด ํฌ์–ด๊ทธ๋ผ์šด๋“œ์— ์žˆ์ง€ ์•Š์œผ

 

๋ฉด 100% ์ž‘๋™๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค" ๋ผ๊ณ  ํ•˜๋”๋ผ๊ตฌ์š”. (์–ด๋–ป๊ฒŒ ๋ณด๋ฉด ๋‹น์—ฐํ•œ ์†Œ๋ฆฌ์ผ์ˆ˜๋„...)

 

๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด๊ฐ”์„ ๋•Œ๋„ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ• ๊นŒ? ์— ๋Œ€ํ•ด์„œ ์ƒ๊ฐํ•˜๋‹ค๊ฐ€ ์ € ๋‚˜๋ฆ„์˜

 

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋‚ด์„œ ๊ณต์œ ๋“œ๋ฆฌ๊ณ  ์‹ถ์–ด์„œ ๊ธ€์„ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!


์ž ๊ทธ๋Ÿฌ๋ฉด ๋ฐ”๋กœ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€ ์„ค๋ช…๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋จผ์ € ์˜ˆ์ „์— ์•ฑ๋ผ์ดํ”„์‚ฌ์ดํด์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ–ˆ์—ˆ๋Š”๋ฐ์š”. (ํ˜น์‹œ ๋ชจ๋ฅด์‹œ๋Š” ๋ถ„๋“ค์€ ์—ฌ๊ธฐ ์—์„œ ํ™•์ธํ•ด์ฃผ์„ธ์š”~)

 

SceneDelgate๋ฅผ ํ†ตํ•ด์„œ ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด๊ฐ”์„ ๋•Œ๋ž‘ ํฌ์–ด๊ทธ๋ผ์šด๋“œ์—  ๋“ค์–ด๊ฐ”์„ ๋•Œ๋ฅผ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

์ด๊ฒƒ์„ ์ด์šฉํ•ด์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๊ฐ„ ์‹œ๊ฐ„์„ ์ €์žฅํ•ด๋†“๊ณ  ํฌ์–ด๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด์™”์„ ๋•Œ ์ฐจ์ด๋ฅผ ๊ณ„์‚ฐํ•ด์„œ ๋”ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

"ํฌ์–ด๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด์˜จ ์‹œ๊ฐ„์—์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๊ฐ„ ์‹œ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌํ•˜์ง€?"

 

์šฐ์„  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด๊ฐ”์„ ๋•Œ Date()๋ฅผ ์ด์šฉํ•ด์„œ ํ˜„์žฌ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์„ ๊ธฐ์–ตํ•ด์ค๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ํฌ์–ด๊ทธ๋ผ์šด๋“œ์— ๋‹ค์‹œ ๋Œ์•„์™”์„ ๋•Œ timeIntervalSince๋ฅผ ์ด์šฉํ•ด์„œ ์ฐจ์ด๋ฅผ ๊ตฌํ•ด์ค๋‹ˆ๋‹ค.

 

๋๋‚œ ์‹œ๊ฐ„.timeIntervalSince(์‹œ์ž‘ํ•œ ์‹œ๊ฐ„) <- ์ด์™€  ๊ฐ™์ด ๋๋‚œ ์‹œ๊ฐ„์„ ์•ž์— ์“ฐ๊ณ  .timeIntervalSince ๊ด„ํ˜ธ ์•ˆ์— ์‹œ์ž‘ํ•œ ์‹œ๊ฐ„์„ ์“ฐ๋ฉด

 

์‹œ๊ฐ„์˜ ์ฐจ์ด๊ฐ€ ๋”๋ธ”๊ฐ’์œผ๋กœ ๋‚˜์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

SceneDelegate


์ €๋Š” ์ดˆ๋งŒ ๊ตฌํ•  ์˜ˆ์ •์ด์—ˆ์œผ๋ฏ€๋กœ Intํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ์–ด์„œ interval์ด๋ผ๋Š” ๋ณ€์ˆ˜ ์•ˆ์— ์ฐจ์ด๋ฅผ ์ €์žฅํ•ด๋†“์•˜์Šต๋‹ˆ๋‹ค.

 

 

"๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด๊ฐ„ ์‹œ๊ฐ„์€ ์–ด๋–ป๊ฒŒ ์ €์žฅํ•˜์ง€?"

 

์ œ๊ฐ€ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•์€ UserDefault๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

UserDefault๋ž€ ๋””๋ฐ”์ด์Šค์— ์ž„์‹œ๋กœ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ํ‚ค๊ฐ’์œผ๋กœ ์ด  ๊ฐ’์„ ๊บผ๋‚ด์„œ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค!

 

์ด๊ณณ์— ๊ฐ’์„ ์“ฐ๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์›ํ•˜๋Š” ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ณ  ์ด๊ฒƒ์„ ๊บผ๋‚ด์“ธ ํ‚ค๊ฐ’์„ string์œผ๋กœ ์ •ํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

"ํ‚ค๊ฐ’์œผ๋กœ ์–ด๋–ป๊ฒŒ ๊บผ๋‚ด์„œ ์“ฐ์ง€?"

 

์ €์žฅํ•œ ๊ฐ’์ด string์ผ ๊ฒฝ์šฐ์—” UserDefault.standard.string()  bool์ผ ๊ฒฝ์šฐ์—” UserDefault.standard.bool()

 

์ด์™€ ๊ฐ™์ด ์ €์žฅํ•œ ๊ฐ’์— ๋”ฐ๋ผ์„œ ๋‹ฌ๋ผ์ง€๋Š”๋ฐ์š”. ๊ทธ๋Ÿผ ์ œ๊ฐ€ ์ €์žฅํ•œ ๋ฐ์ดํŠธ๋Š” ์–ด๋–ป๊ฒŒ ๋ถˆ๋Ÿฌ์˜ฌ๊นŒ์š”?

 

๋ฐ”๋กœ ์˜ค๋ธŒ์ ํŠธ๋กœ ๋ถˆ๋Ÿฌ์™€์„œ Date๋กœ ํ˜•๋ณ€ํ™˜์„ ์‹œ์ผœ์ค๋‹ˆ๋‹ค.

๋ฐฑ๊ทธ๋ผ์šด๋“œ์˜ ์‹œ๊ฐ„์„ ์ €์žฅํ•˜๊ณ  ๊บผ๋‚ด์“ฐ๋Š” ๋ฐฉ๋ฒ•๋„ ์•Œ์•˜๊ณ  ํฌ์–ด๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด๊ฐ„ ์‹œ๊ฐ„์—์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๊ฐ„ ์‹œ๊ฐ„์˜ ์ฐจ์ด๋„ ๊ตฌํ–ˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ๊ฐ€์žฅ ๊ถ๊ธˆํ•ดํ•˜์‹ค ๊ฑด ์•„๋ž˜ ์งˆ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

 

"๊ทธ๋Ÿผ ์ด ์‹œ๊ฐ„์„ ์–ด๋–ป๊ฒŒ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ์— ์•Œ๋ ค์ฃผ๋Š”๊ฑด๋ฐ?"

 

๋ฐ”๋กœ NotificationCenter๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

NotificationCenter๋Š” ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ฌ์„ ๋•Œ ์•Œ๋ฆผ์„ ์ค„ ์ˆ˜ ์žˆ๊ณ  ๋‹ค๋ฅธ ๊ณณ์—์„œ addObserver๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

 

(์‚ฌ์šฉ๋ฐฉ๋ฒ•์€ ์—ฌ๊ธฐ ๋ฅผ ์ฐธ์กฐํ•ด์ฃผ์„ธ์š”.)

 

์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด์™”์„ ๋•Œ์™€ ํฌ์–ด๊ทธ๋ผ์šด๋“œ๋กœ ๋Œ์•„๊ฐˆ ๋•Œ ๊ฐ๊ฐ Notification์„ postํ•ด์ค๋‹ˆ๋‹ค.

 

์•„ ์—ฌ๊ธฐ์„œ ์•„๊นŒ ๊ตฌํ•œ ์‹œ๊ฐ„์˜ ์ฐจ์ด๋Š” NotificationCenter์˜ userInfo๋ฅผ ํ†ตํ•ด์„œ dictionaryํ˜•ํƒœ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

(ํ˜น์‹œ NotificationCenter์—์„œ ๊ฐ’์„ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด์‹œ๋Š” ๋ถ„์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!)

1
2
3
4
5
6
7
8
9
10
11
 func sceneWillEnterForeground(_ scene: UIScene) {
        guard let start = UserDefaults.standard.object(forKey: "sceneDidEnterBackground"as? Date else { return }
        let interval = Int(Date().timeIntervalSince(start))
        NotificationCenter.default.post(name: NSNotification.Name("sceneWillEnterForeground"), object: nil,userInfo: ["time" : interval])
    }
 
    func sceneDidEnterBackground(_ scene: UIScene) {
        NotificationCenter.default.post(name: NSNotification.Name("sceneDidEnterBackground"), object: nil)
        UserDefaults.standard.setValue(Date(), forKey: "sceneDidEnterBackground")
    }
    

 

ViewController


์ด์ œ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ด๋™ํ•ด์„œ ์•„๊นŒ ๋ณด๋‚ธ ์•Œ๋ฆผ์„ addObserver๋ฅผ ๋‹ฌ์•„์ค˜ ๊ด€์ฐฐํ•ด์ค๋‹ˆ๋‹ค. (setnotification์€ viewDidLoad์— ์‹คํ–‰์‹œ์ผœ์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.)

1
2
3
4
5
6
    func setNotifications() {
        //๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํฌ์–ด๊ทธ๋ผ์šด๋“œ๋กœ ๋Œ์•„์˜ฌ๋•Œ
        NotificationCenter.default.addObserver(self, selector: #selector(addbackGroundTime(_:)), name: NSNotification.Name("sceneWillEnterForeground"), object: nil)
        //ํฌ์–ด๊ทธ๋ผ์šด๋“œ์—์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ๊ฐˆ๋•Œ
        NotificationCenter.default.addObserver(self, selector: #selector(stopTimer), name: NSNotification.Name("sceneDidEnterBackground"), object: nil)
    }

 

๊ฐ๊ฐ @objc ํ•จ์ˆ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์ค๋‹ˆ๋‹ค. (ํ•จ์ˆ˜ ์•ˆ์— ์žˆ๋Š” ๋‚ด์šฉ์€ ๊ฐ์ž ์ƒํ™ฉ์— ๋งž๊ฒŒ ๋ฐ”๊พธ์…”์•ผํ•ฉ๋‹ˆ๋‹ค!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    @objc func addbackGroundTime(_ notification:Notification) {
        if startorstop == true {
            //๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜์„ผํ„ฐ๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋ฐ›์•„์˜ด
            let time = notification.userInfo?["time"asInt ?? 0
            //๋ฐ›์•„์˜จ ์‹œ๊ฐ„์„ 60์œผ๋กœ ๋‚˜๋ˆˆ ๋ชซ์€ ๋ถ„
            minutes += time/60
            //๋ฐ›์•„์˜จ ์‹œ๊ฐ„์„ 60์œผ๋กœ ๋‚˜๋ˆˆ ๋‚˜๋จธ์ง€๋Š” ์ดˆ
            seconds += time%60
            setLottieAnimation(play: true)
            timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(TimerViewController.keepTimer), userInfo: nil, repeats: true)
        }
    }
    
    @objc func stopTimer() {
        timer.invalidate()
    }

 

์•„๋ž˜ ์˜์ƒ์„ ๋ณด์‹œ๋ฉด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ๋“ค์–ด๊ฐ”๋‹ค ๋‹ค์‹œ ๋Œ์•„์™”์„ ๋•Œ ํƒ€์ด๋จธ๊ฐ€ ๊ทธ ์‹œ๊ฐ„๋งŒํผ ๋”ํ•ด์ง€๊ณ  ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!!

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€