55839


[![画像の説明をここに入力](https://i.stack.imgur.com/irYgQ.png)](https://i.stack.imgur.com/irYgQ.png)  
[![画像の説明をここに入力](https://i.stack.imgur.com/NPwsg.png)](https://i.stack.imgur.com/NPwsg.png)

上の画像のような違う**.swift**間で変数を共有したいのですがどのようにしたら良いでしょうか

[code]

    //ViewController.swift
    class NextViewController {
        var number: Int = 60
    }
    
    //TimerManagar.swift
    class TimerManagar {
        let nextViewController = NextViewController()
        var timerNumber = nextViewController.number  //エラーCannot use instance member 'nextViewController' within property initializer; property initializers run before 'self' is available
      }
    
[/code]

## **本当にやりたいことです↓↓**

グチャグチャしたコードで頭がこんがらがると思うのですがよろしくお願いします  
僕の頭はもうグチャグチャです。

**異なるファイル間での変数のやりとりについて** の質問のコードのところにのマークのコメントをつけています

[![左:ViewCOntroller
、右：NextViewController](https://i.stack.imgur.com/91V0w.png)](https://i.stack.imgur.com/91V0w.png)

[code]

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var characterImage: UIImageView!
        @IBOutlet weak var timerlabel: UILabel!
        @IBOutlet weak var startButton: UIButton!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            startButton.layer.cornerRadius = 25.0
        }
    
    }
    
[/code]

[code]

    import UIKit
    
    class NextViewController: UIViewController {
    
        @IBOutlet weak var countdwonTimer: UILabel!
        @IBOutlet weak var executionTimer: UILabel!
        @IBOutlet weak var stopButton: UIButton!
        @IBOutlet weak var kyannseruButton: UIButton!
        @IBOutlet weak var twentyButton: UIButton!
        @IBOutlet weak var thirtyButton: UIButton!
        @IBOutlet weak var sixtyButton: UIButton!
        @IBOutlet weak var ninetyButton: UIButton!
    
        var nowNumber = 0
        var timer : Timer?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            stopButton.layer.cornerRadius = 30.0
            kyannseruButton.layer.cornerRadius = 30.0
            twentyButton.layer.cornerRadius = 22.5
            thirtyButton.layer.cornerRadius = 22.5
            sixtyButton.layer.cornerRadius = 22.5
            ninetyButton.layer.cornerRadius = 22.5
    
            TimerManager.shared.labelUpDate(TimerManager.shared.count)
    
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            TimerManager.shared.onCountDidSet = { count in TimerManager.shared.labelUpDate( Int(count))}
    
        }
    
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
    
            TimerManager.shared.onCountDidSet = nil
    
        }
    
                        @IBAction func stopButtonAction(_ sender: UIButton) {
    
                            if timer?.isValid != true {
                        if nowNumber == 20 || nowNumber ==  30 || nowNumber == 60 || nowNumber == 90 {
    
                         if nowNumber == 20 {
                         //TimerscheduledTimer
    
                        } else if nowNumber == 30 {
    
                        } else if nowNumber == 60 {
    
                        } else if nowNumber == 90 {
    
                        }
    
                    stopButton.setTitle("stop", for: .normal)
                    twentyButton.isUserInteractionEnabled = false
                    thirtyButton.isUserInteractionEnabled = false
                    sixtyButton.isUserInteractionEnabled = false
                    ninetyButton.isUserInteractionEnabled = false
    
                                    }
                            } else {
                            if let nowTimer = timer {
                                if nowTimer.isValid == true {
                                    nowTimer.invalidate()
    
                                    stopButton.setTitle("start", for: .normal)
                                    twentyButton.isUserInteractionEnabled = true
                                    thirtyButton.isUserInteractionEnabled = true
                                    sixtyButton.isUserInteractionEnabled = true
                                    ninetyButton.isUserInteractionEnabled = true
                                }
              }
             }
    
        }
    
        @IBAction func cancelButtonAction(_ sender: UIButton) {
            if let nowTimer = timer {
                if nowTimer.isValid == true {
                    nowTimer.invalidate()
                }
            }
            twentyButton.isUserInteractionEnabled = true
            thirtyButton.isUserInteractionEnabled = true
            sixtyButton.isUserInteractionEnabled = true
            ninetyButton.isUserInteractionEnabled = true
    
            nowNumber = 0
            TimerManager.shared.labelUpDate(0)
    
            stopButton.setTitle("start", for: .normal)
    
        }
    
        @IBAction func twentyButtonAction(_ sender: UIButton) {
            TimerManager.shared.labelUpDate(1200)
            nowNumber = 20
        }
    
        @IBAction func thertyButtonActiojn(_ sender: UIButton) {
            TimerManager.shared.labelUpDate(1800)
            nowNumber = 30
        }
    
        @IBAction func sixtyButtonAction(_ sender: UIButton) {
            TimerManager.shared.labelUpDate(3600)
            nowNumber = 60
        }
    
        @IBAction func ninetyButtonAction(_ sender: UIButton) {
            TimerManager.shared.labelUpDate(5400)
            nowNumber = 90
        }
    
    }
    
[/code]

[code]

    import UIKit
    
    class TimerManager : UIViewController {
        static var shared = TimerManager()
    
        let settingKey = "timer_value"
        let settingKeytwenty = "timer_twenty"
        let settingKeythirty = "timer_thirty"
        let settingKeysixty  = "timer_sixty"
        let settingKeyninety = "timer_ninety"
    
        var timer : Timer?
        var startDate : Date?
    
        var countString = "00 : 00"
    
        var count = 0 {
            didSet {
            onCountDidSet?(Double(count))
            }
        }
        var onCountDidSet : ((_ count : Double) -> Void)? = nil
    
        let nextViewController = NextViewController()     //ここです！！！！！
        var timerNowNunber = nextViewController.nowNumber //ここです！！！！！
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let settings = UserDefaults.standard
            settings.register(defaults: [settingKey : 216000])
            let settings20 = UserDefaults.standard
            settings20.register(defaults: [settingKeytwenty : 1200])
            let settings30 = UserDefaults.standard
            settings30.register(defaults: [settingKeythirty : 1800])
            let settings60 = UserDefaults.standard
            settings60.register(defaults: [settingKeysixty : 3600])
            let settings90 = UserDefaults.standard
            settings90.register(defaults: [settingKeyninety : 5400])
    
        }
    
        func startCount() {
            startDate = Date()
            if timer == nil {
                if timerNowNunber == 20 || timerNowNunber == 30 || timerNowNunber == 60 || timerNowNunber == 90 {       //timerNowNunberで処理を分岐したい
    
                    if timerNowNunber == 20 {
                        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
                            self.twntytimer(timer)
                        })
                    } else if timerNowNunber == 30 {
    
                        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: {timer in self.thritytimer(timer)})
    
    
                    } else if timerNowNunber == 60 {
    
                        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
                        self.sixtytimer(timer)})
    
    
                    } else if timerNowNunber == 90 {
    
                        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
                            self.ninetytimer(timer)})
    
              }
            }
          }
        }
        func twntytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeytwenty)
    
            count = timeValue - Int(dateDifference)
    
            labelUpDate(count)
         }
    
        func thritytimer (_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeythirty)
    
            count = timeValue - Int(dateDifference)
            labelUpDate(count)
        }
    
        func sixtytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeysixty)
    
            count = timeValue - Int(dateDifference)
    
            labelUpDate(count)
        }
    
        func ninetytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeyninety)
    
            count = timeValue - Int(dateDifference)
    
            labelUpDate(count)
    
        }
    
        func labelUpDate (_ minutes : Int) {
            let s = minutes % 60
            let m = (minutes - s ) / 60
    
            countString = String(format: "%02d : %02d", m, s)  //ここにNextViewControllerの　executionTimerのラベルを変更する処理を加えたいができない。。。
        }
    
    }
    
[/code]

例えば`NextViewController` の
20のボタンを押しstartのボタンを押したら２０分のカウントダウンが始まる処理を書きたいのですがなかなかうまくいきません

## 編集後↓↓

[code]

    import UIKit
    
    func secondsToTimerLabel(_ seconds : Int) -> String {
        let min = seconds / 60
        let sec = seconds % 60
        return String(format: "%02d : %02d", min, sec)
    }
    
    class NextViewController: UIViewController {
    
        @IBOutlet weak var countdwonTimer: UILabel!
        @IBOutlet weak var executionTimer: UILabel!
        @IBOutlet weak var stopButton: UIButton!
        @IBOutlet weak var kyannseruButton: UIButton!
        @IBOutlet weak var twentyButton: UIButton!
        @IBOutlet weak var thirtyButton: UIButton!
        @IBOutlet weak var sixtyButton: UIButton!
        @IBOutlet weak var ninetyButton: UIButton!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            stopButton.layer.cornerRadius = 30.0
            kyannseruButton.layer.cornerRadius = 30.0
            twentyButton.layer.cornerRadius = 22.5
            thirtyButton.layer.cornerRadius = 22.5
            sixtyButton.layer.cornerRadius = 22.5
            ninetyButton.layer.cornerRadius = 22.5
    
            self.executionTimer.text = secondsToTimerLabel(TimerManager.shared.count)
    
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            TimerManager.shared.onCountDidSet = { count in
                self.executionTimer.text = secondsToTimerLabel(Int(count))
            }
    
        }
    
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
    
            TimerManager.shared.onCountDidSet = nil
    
        }
    
    
    
    
        @IBAction func stopButtonAction(_ sender: UIButton) {
    
           if TimerManager.shared.isRunning {
    
              if TimerManager.shared.timer?.isValid != true {  //######ここと
    
                TimerManager.shared.startCount()
                stopButton.setTitle("stop", for: .normal)
                twentyButton.isUserInteractionEnabled = false
                thirtyButton.isUserInteractionEnabled = false
                sixtyButton.isUserInteractionEnabled = false
                ninetyButton.isUserInteractionEnabled = false
    
                } else {
    
                TimerManager.shared.stop()
                stopButton.setTitle("start", for: .normal)
                twentyButton.isUserInteractionEnabled = true
                thirtyButton.isUserInteractionEnabled = true
                sixtyButton.isUserInteractionEnabled = true
                ninetyButton.isUserInteractionEnabled = true
    
                }  //#############################3
    
            } else {
    
                TimerManager.shared.startCount()
                stopButton.setTitle("stop", for: .normal)
                twentyButton.isUserInteractionEnabled = false
                thirtyButton.isUserInteractionEnabled = false
                sixtyButton.isUserInteractionEnabled = false
                ninetyButton.isUserInteractionEnabled = false
            }
    
    
    
       }
    
        @IBAction func cancelButtonAction(_ sender: UIButton) {
    
            TimerManager.shared.cancel()
    
            twentyButton.isUserInteractionEnabled = true
            thirtyButton.isUserInteractionEnabled = true
            sixtyButton.isUserInteractionEnabled = true
            ninetyButton.isUserInteractionEnabled = true
    
            TimerManager.shared.count = 0
            self.executionTimer.text = secondsToTimerLabel(0)
    
            stopButton.setTitle("start", for: .normal)
    
        }
    
        @IBAction func twentyButtonAction(_ sender: UIButton) {
            self.executionTimer.text = secondsToTimerLabel(1200)
            TimerManager.shared.nowNumber = 20
        }
    
        @IBAction func thertyButtonActiojn(_ sender: UIButton) {
            self.executionTimer.text = secondsToTimerLabel(1800)
            TimerManager.shared.nowNumber = 30
        }
    
        @IBAction func sixtyButtonAction(_ sender: UIButton) {
            self.executionTimer.text = secondsToTimerLabel(3600)
            TimerManager.shared.nowNumber = 60
        }
    
        @IBAction func ninetyButtonAction(_ sender: UIButton) {
            self.executionTimer.text = secondsToTimerLabel(5400)
            TimerManager.shared.nowNumber = 90
        }
    
    
    
    
    }
    
[/code]

[code]

    import UIKit
    
    
    class TimerManager {
        static var shared = TimerManager()
    
        let settingKey = "timer_value"
        let settingKeytwenty = "timer_twenty"
        let settingKeythirty = "timer_thirty"
        let settingKeysixty  = "timer_sixty"
        let settingKeyninety = "timer_ninety"
    
        var timer : Timer?
        var startDate : Date?
    
        var count = 0 {
            didSet {
            onCountDidSet?(Double(count))
            }
        }
        var onCountDidSet : ((_ count : Double) -> Void)? = nil
    
        var nowNumber : Int = 0
    
    
        init () {
            let settings = UserDefaults.standard
            settings.register(defaults: [settingKey : 216000])
            let settings20 = UserDefaults.standard
            settings20.register(defaults: [settingKeytwenty : 1200])
            let settings30 = UserDefaults.standard
            settings30.register(defaults: [settingKeythirty : 1800])
            let settings60 = UserDefaults.standard
            settings60.register(defaults: [settingKeysixty : 3600])
            let settings90 = UserDefaults.standard
            settings90.register(defaults: [settingKeyninety : 5400])
    
        }
    
    
        func startCount() {
            startDate = Date()
    
            if timer == nil {
    
                switch nowNumber {
    
                case 20 :
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in self.twntytimer(timer)
                    })
    
                case 30 :
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: {timer in self.thritytimer(timer)})
    
    
                case 60 :
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
                        self.sixtytimer(timer)})
    
                case 90 :
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
                        self.ninetytimer(timer)})
    
                default :
                    print("Invalid value \(nowNumber)")
                }
            }
        }
    
        func stop() {        //###これです
            timer?.invalidate()
        }
    
    
        func cancel() {
            timer?.invalidate()
            timer = nil
        }
    
    
        var isRunning : Bool {
            return timer != nil
        }
    
    
    
    
        func twntytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeytwenty)
    
            count = timeValue - Int(dateDifference)
    
         }
    
        func thritytimer (_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeythirty)
    
            count = timeValue - Int(dateDifference)
    
        }
    
        func sixtytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeysixty)
    
            count = timeValue - Int(dateDifference)
    
        }
    
        func ninetytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeyninety)
    
            count = timeValue - Int(dateDifference)
    
    
        }
    
    
    }
    
[/code]

[![画像の説明をここに入力](https://i.stack.imgur.com/JIfxq.png)](https://i.stack.imgur.com/JIfxq.png)  
[![画像の説明をここに入力](https://i.stack.imgur.com/Rcvbq.png)](https://i.stack.imgur.com/Rcvbq.png)


CC BY-SA 4.0
2019-06-16T03:42:07.467
55834
2019-06-17T12:15:42.393
2019-06-17T04:02:23.713
34541
34541
question
swift xcode
異なるファイル間での変数のやりとりについて


まずは、あなたの[過去のご質問](https://ja.stackoverflow.com/q/55641/13972)も踏まえて、現時点での「やってはいけない」をまとめておきましょう。

  * view controllerのインスタンスを`ViewController()`と言う構文でインスタンス化してはいけない

画面表示に関わっていない別インスタンスを作っていることになる。別インスタンスはインスタンスプロパティも全部別々に持っているので、たとえプロパティにアクセスできるようにしても、所望の中身は入っていない。

  * `TimerManager`以外から`Timer`を操作してはいけない

`Timer`のことは全て`TimerManager`に任せる。それでは機能が足りないなら`TimerManager`に機能を追加して、その機能を呼び出す。

  * `TimerManager`に画面の操作をさせない

そもそも画面遷移にかかわらず動作するタイマーが欲しくて`TimerManager`なんてクラスを作ったはず。`TimerManager`に特定の画面に依存するような処理を追加してはいけない。

* * *

以上の点を十分踏まえて、あなたのコードを見直していくとダメダメなところがいくつも見つかります。まずは、`TimerManager`から。

[code]

    class TimerManager { //###<- `TimerManager`を`UIViewController`のサブクラスにする意味は全くない
        static var shared = TimerManager()
    
        let settingKey = "timer_value"
        let settingKeytwenty = "timer_twenty"
        let settingKeythirty = "timer_thirty"
        let settingKeysixty  = "timer_sixty"
        let settingKeyninety = "timer_ninety"
    
        var timer : Timer?
        var startDate : Date?
    
        var count = 0 {
            didSet {
                onCountDidSet?(Double(count))
            }
        }
        var onCountDidSet : ((_ count : Double) -> Void)? = nil
    
        var nowNumber: Int = 0 //### <- `nowNumber`は`TimerManager`のプロパティにしてしまう
    
        //### 一般的なクラスの初期化は`init(...)`の中で行う
        init() {
            let settings = UserDefaults.standard
            settings.register(defaults: [settingKey : 216000])
            let settings20 = UserDefaults.standard
            settings20.register(defaults: [settingKeytwenty : 1200])
            let settings30 = UserDefaults.standard
            settings30.register(defaults: [settingKeythirty : 1800])
            let settings60 = UserDefaults.standard
            settings60.register(defaults: [settingKeysixty : 3600])
            let settings90 = UserDefaults.standard
            settings90.register(defaults: [settingKeyninety : 5400])
        }
    
        func startCount() {
            startDate = Date()
            if timer == nil {
                //### nowNumberで処理を分岐したい
                //### 一つの値から多分岐をするときの基本は`switch`
                switch nowNumber {
                case 20:
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {timer in
                        self.twntytimer(timer)
                    }
                case 30:
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {timer in self.thritytimer(timer)
                    }
                case 60:
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {timer in
                        self.sixtytimer(timer)
                    }
                case 90:
                    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {timer in
                        self.ninetytimer(timer)
                    }
                default:
                    print("Invalid value: \(nowNumber)")
                }
            }
        }
        //###
        func cancel() {
            timer?.invalidate()
            timer = nil
        }
        //###
        var isRunning: Bool {
            return timer != nil
        }
    
        func twntytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeytwenty)
    
            count = timeValue - Int(dateDifference)
    
            //### `TimerManager`から直接画面更新しようなんて思っちゃいけない
    //        labelUpDate(count)
        }
    
        func thritytimer (_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeythirty)
    
            count = timeValue - Int(dateDifference)
            //### `TimerManager`から直接画面更新しようなんて思っちゃいけない
    //        labelUpDate(count)
        }
    
        func sixtytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeysixty)
    
            count = timeValue - Int(dateDifference)
    
            //### `TimerManager`から直接画面更新しようなんて思っちゃいけない
    //        labelUpDate(count)
        }
    
        func ninetytimer(_ timer : Timer) {
    
            guard let startDate = startDate else {
                return
            }
            let now = Date()
            let dateDifference = now.timeIntervalSince(startDate)
    
            let sitting = UserDefaults.standard
            let timeValue = sitting.integer(forKey: settingKeyninety)
    
            count = timeValue - Int(dateDifference)
    
            //### `TimerManager`から直接画面更新しようなんて思っちゃいけない
    //        labelUpDate(count)
        }
    
    
        //### `TimerManager`から直接画面更新しようなんて思っちゃいけない
    //    func labelUpDate (_ minutes : Int) {
    //        let s = minutes % 60
    //        let m = (minutes - s ) / 60
    //
    //        countString = String(format: "%02d : %02d", m, s)  //ここにNextViewControllerの　executionTimerのラベルを変更する処理を加えたいができない。。。
    //    }
    
    }
    
[/code]

と言うワケでいくつか補足を。

  * `TimerManager`を`UIViewController`のサブクラスにする意味は全くない。そんなことをしても他画面の`UILabel`が更新できるようにはならない。

  * 今回の質問内容のそもそもの発端である`nowNumber`と言う変数は、`Timer`処理に深く関わるものなのに、画面側の`NextViewController`のプロパティにしてしまっているのがそもそも間違い。`TimerManager`は`Timer`処理の専門家なので、それに関する変数は`TimerManager`に持たせることにすれば、そもそも他クラスのインスタンスプロパティにアクセスするとかなんて気にせずに処理が書ける。

  * 逆に`TimerManager`に画面処理の機能を持たせてはいけない。画面処理の専門家はview controller。`TimerManager`は画面処理側に通知を送るだけにする。

他にも多分岐にはswitch文を使う、なんて修正も入っていますが、これは本質的なものではありませんが、使い方を覚えておいた方がいいですよ、と言うレベルです。

* * *

続いて、`NextViewController`の方を見てみましょう。

[code]

    //### 画面更新はview controllerの仕事だが、`ViewController`でも必要になるかもしれないので、グローバル関数として宣言しておく
    func secondsToTimeLabel(_ seconds: Int) -> String {
        let min = seconds/60
        let sec = seconds%60
        return String(format: "%02d : %02d", min, sec)
    }
    class NextViewController: UIViewController {
    
        @IBOutlet weak var countdwonTimer: UILabel!
        @IBOutlet weak var executionTimer: UILabel!
        @IBOutlet weak var stopButton: UIButton!
        @IBOutlet weak var kyannseruButton: UIButton!
        @IBOutlet weak var twentyButton: UIButton!
        @IBOutlet weak var thirtyButton: UIButton!
        @IBOutlet weak var sixtyButton: UIButton!
        @IBOutlet weak var ninetyButton: UIButton!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            stopButton.layer.cornerRadius = 30.0
            kyannseruButton.layer.cornerRadius = 30.0
            twentyButton.layer.cornerRadius = 22.5
            thirtyButton.layer.cornerRadius = 22.5
            sixtyButton.layer.cornerRadius = 22.5
            ninetyButton.layer.cornerRadius = 22.5
    
            //### `UILabel`を更新するのは`TimerManager`の仕事ではない
            self.countdwonTimer.text = secondsToTimeLabel(TimerManager.shared.count)
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            TimerManager.shared.onCountDidSet = { count in
                //### `UILabel`を更新するのは`TimerManager`の仕事ではない
                self.countdwonTimer.text = secondsToTimeLabel(Int(count))
            }
    
        }
    
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
    
            TimerManager.shared.onCountDidSet = nil
        }
    
        @IBAction func stopButtonAction(_ sender: UIButton) {
            //### とにかく`Timer`に関することは全部`TimerManager`に聞く
            if TimerManager.shared.isRunning {
                TimerManager.shared.cancel()
    
                stopButton.setTitle("start", for: .normal)
                twentyButton.isUserInteractionEnabled = true
                thirtyButton.isUserInteractionEnabled = true
                sixtyButton.isUserInteractionEnabled = true
                ninetyButton.isUserInteractionEnabled = true
            } else {
                stopButton.setTitle("stop", for: .normal)
                twentyButton.isUserInteractionEnabled = false
                thirtyButton.isUserInteractionEnabled = false
                sixtyButton.isUserInteractionEnabled = false
                ninetyButton.isUserInteractionEnabled = false
            }
        }
    
        @IBAction func cancelButtonAction(_ sender: UIButton) {
            //### `Timer`に関する操作は`TimerManager`に任せることにしたんだから、直接`Timer`を操作してはダメ
    //        if let nowTimer = timer {
    //            if nowTimer.isValid == true {
    //                nowTimer.invalidate()
    //            }
    //        }
            TimerManager.shared.cancel()
    
            twentyButton.isUserInteractionEnabled = true
            thirtyButton.isUserInteractionEnabled = true
            sixtyButton.isUserInteractionEnabled = true
            ninetyButton.isUserInteractionEnabled = true
    
            TimerManager.shared.nowNumber = 0 //###
            //### `UILabel`を更新するのは`TimerManager`の仕事ではない
            self.countdwonTimer.text = secondsToTimeLabel(0)
    
            stopButton.setTitle("start", for: .normal)
    
        }
    
        @IBAction func twentyButtonAction(_ sender: UIButton) {
            //### `UILabel`を更新するのは`TimerManager`の仕事ではない
            self.countdwonTimer.text = secondsToTimeLabel(1200)
            TimerManager.shared.nowNumber = 20 //###
        }
    
        @IBAction func thertyButtonActiojn(_ sender: UIButton) {
            //### `UILabel`を更新するのは`TimerManager`の仕事ではない
            self.countdwonTimer.text = secondsToTimeLabel(1800)
            TimerManager.shared.nowNumber = 30 //###
        }
    
        @IBAction func sixtyButtonAction(_ sender: UIButton) {
            //### `UILabel`を更新するのは`TimerManager`の仕事ではない
            self.countdwonTimer.text = secondsToTimeLabel(3600)
            TimerManager.shared.nowNumber = 60 //###
        }
    
        @IBAction func ninetyButtonAction(_ sender: UIButton) {
            //### `UILabel`を更新するのは`TimerManager`の仕事ではない
            self.countdwonTimer.text = secondsToTimeLabel(5400)
            TimerManager.shared.nowNumber = 90 //###
        }
    }
    
[/code]

  * `nowNumber`のように`Timer`処理に深く関わる変数は`TimerManager`側に移動する。

  * 決して自前の`Timer`変数を宣言しない。必要な機能が`TimerManager`にないなら、機能を追加してそれを使う。(`cancel()`, `isRunning`など。)

変数名だけ同じにしても、別の`Timer`インスタンスにアクセスすることになるので意味がない。

  * その代わり自画面の`UILabel`の更新は責任もって自分でやる。

* * *

「`ViewController`側のカウントダウンラベルが更新されない」と言う問題をなんとかしたいと言うことで現在のコードになってしまったようで、まだその点は解決できていません(ご自身で解決できない場合、別質問として下さい)が、上記のような修正で`nowNumber`を通じて渡したかった情報は`TimerManager`の方に渡るはずです。

「`ViewController`側のカウントダウンラベル」の問題は、本当は[直前のご質問](https://ja.stackoverflow.com/q/55739/13972)で解決したかったのでしょうが、[私の回答](https://ja.stackoverflow.com/a/55758/13972)は「`NextViewController`側のイベント処理の結果を`ViewController`側に伝える」ための一般的な方法なので、今回のように(特定のview
controllerではなく)`TimerManager`からの通知」に対応して画面更新する、と言った用途には不向きです。ご質問を書かれる際には、省略しすぎると「本当にやりたいこと」を解決するのには不向きな回答ばかりが付いてしまうことにもなりかねません。「本当は何をやりたいのか」をうまく盛り込むようにして下さい。

少し規模が大きくなってきたので、テストできていない部分が多々あります。気になることがあれば、随時おしらせください。(`TimerManager`の`startCount()`を呼んでいる部分が見当たりませんが、そのままにしてあります。)

* * *

いくつかのコメントに対する回答はこちらの追記にて答えさせていただきます。

**_`TimeManager`の`var count = 0 { didSet { onCountDidSet?(Double(count)) } }
var onCountDidSet : ((_ count : Double) -> Void)? =
nil`の処理なのですがこのような処理の仕方に名前などはありますでしょうか。_**

2つのパターンを混ぜて使っているところです。Swiftでストア型プロパティに`willSet`や`didSet`を付け加えて、プロパティの値が変更された時になんらかの処理をさせると言うやり方は、[Property
Observer](https://docs.swift.org/swift-
book/LanguageGuide/Properties.html#ID262)と呼ばれています。プロパティの観察者って意味ですね。

また、その`didSet`の中身ではクロージャーを呼び出しています。これはC言語の時代から一般的によくある手法で、「何かあった時にはこの関数を呼び出してくれ」と言う意味で関数(C言語なら関数ポインタ、Swiftならクロージャ)を渡しておくと言う手法です。昔からある手法なので、かっこいい名前は付いていませんが、古典的コールバックパターンとでも言っておけばいいでしょう。

* * *

**_１秒ごとに連続して画面がカウントダウンしてくれる処理_**

上記のコールバックパターンと`TimerManager`の動作が組み合わさって実現されます。

`TimerManager`の中では、(Appleの`Timer`を使って)1秒ごとに`count`の値が変化していくと言うところまでは、理解できているでしょうか。

上記した`Property
Observer`の働きによって、`TimerManager`の中で`count`の値を変更すると、コールバックとして`onCountDidSet`にセットされているクロージャーを呼び出しています。`NextViewController`が画面表示を担当している間(`viewWillAppear`が呼ばれてから、`viewDidDisappear`が呼ばれるまでの間)は、`onCountDidSet`には`NextViewController`のカウントダウン用ラベルの値を更新するクロージャがセットされていますから、`count`の値が変更されるたびに、`NextViewController`のカウントダウン用ラベルの値も更新されることになります。

従って、「`ViewController`が画面表示を担当している間は、`ViewController`のカウントダウン用ラベルの値を更新する」ような動作にしたいのであれば、適切なタイミングで`onCountDidSet`に「`ViewController`のカウントダウン用ラベルの値を更新する」ようなクロージャをセットしてやれば良い、と言うことになります。

* * *

**_stopしてまたstartすると初めからカウントされるようにしようとしたのですがカウントダウンが止まったまま動かない事態になってしまいました。どこがいけないのでしょうか。_**

これについては、このご質問の主題である「異なるファイル間での変数のやりとり」とは離れてしまっていますよね。最終的に「本当にやりたいこと」の一つではあるでしょうが、質問の主題が次から次へと追加されていくと言うのは、このサイトの趣旨から離れた使い方になってしまいます。

関連が強いので、二度手間になってしまう部分も多いですが、あらためて独立したご質問として下さい。

その際には、

  * 現在の最新のコード
  * アプリの起動から、期待した通りの動作にならない結果を得るための詳しい手順

などもきちんと記載されて、過去のあなたの質問を読まなくても、ご質問の意図が十分伝わるように工夫されると、より多くの方にあなたの問題の解法を考えてもらえることにつながります。

当サイトもうまく利用して、少しでも早くアプリが完成に近づくことを願っております。


CC BY-SA 4.0
2019-06-16T06:52:29.607
55839
2019-06-17T12:15:42.393
2019-06-17T12:15:42.393
13972
13972
55834
answer