2017-05-03 15 views
5

私は私の迅速なアプリケーションで2つのビューを持っています。私は以下のようにセグを実行しています。Swift Timer.scheduledTimer()が機能しません

ViewController.swift -----------------> GameViewController.swift

ViewController.swiftからもGameViewController.swiftに渡さGameViewController値のアレイをロード

タイマーは、私はタイマーを初期化し、それを介してメソッドを呼び出そうとしましたが、それは動作しませんGameViewController.swift

に初期化する必要があります。

以下は私のコードスニペットです。

ViewController.swift

func signIn(difficultyLvl:String){ 
    let username = usernameTxt.text 
    let password = passwordTxt.text 

    let url = URL(string: "http://192.168.1.106/speed/scoreBoardController.php?username="+username!+"&password="+password!+"&action=SIGNIN") 

    let task = URLSession.shared.dataTask(with: url!) {(data, response, error) in 
     let isPassed = String(data: data!, encoding:.utf8)?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 

     var gameViewControllerParams = [Int: [String: String]]() 
     gameViewControllerParams[0] = ["userId" : isPassed!] 
     gameViewControllerParams[1] = ["difficultyLvl" : difficultyLvl] 

     if(isPassed != "null"){ 
      self.performSegue(withIdentifier: "gotoGame", sender: gameViewControllerParams) 
     } 
    } 

    task.resume() 
} 

GameViewController.swift

class GameViewController: UIViewController { 

    var gameViewControllerParams = [Int: [String: String]]() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let _ = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(self.setCalculationLs), userInfo:nil,repeats: true) 
    } 

    func setCalculationLs(){ 
     print("Timing") 
    } 

} 
+0

タイマーにターゲットオブジェクトを設定することが問題です。どんなsuggetions。ありがとう –

+0

'GameViewController'に配列を送るのではなく、' prepare(for:sender:) 'で配列を送ります。 'sender'パラメータは' self 'でなければなりません – paper1111

+0

問題は何になりますか? GameViewControllerがロードされていますか? viewDidLoad()は呼び出されていますか?配列の受け渡しはタイマーの問題にどのように関連していますか? - 一般的に、タイマーコードは機能するはずです。 –

答えて

10

タイマーは実行ループを作成するか、手動で既存の実行時にそれをスケジュール関与手のいくつかの早業なし(バックグラウンドキュー上では動作しません。ループ)。とにかく、メインキュー以外からのUIアップデートは決して開始しないでください。

あなたが(バックグラウンドキュー上で実行されます)URLSession完了閉鎖からperformSegueを呼び出しているので、そう、それは実際には、あまりにも、バックグラウンドキューからviewDidLoadを実行しています。したがって、タイマーのスケジューリングに失敗しています。これを回避するには、手動でメインキューにperformSegueコードを派遣する必要があります:あなたは、いくつかのコードがメインキュー上で実行しているかどうか、これまでわからない場合

let task = URLSession.shared.dataTask(with: url!) { data, response, error in 
    ... 

    if isPassed != "null" { 
     DispatchQueue.main.async { 
      self.performSegue(withIdentifier: "gotoGame", sender: ...) 
     } 
    } 
} 

は、the documentationを参照してください。あなたが誤ってバックグラウンドキューからコードを起動してしまった場合、それは(デバッグビルドで)アプリを停止します

dispatchPrecondition(condition: .onQueue(.main)) 

その方法:それとも、ディスパッチ前提条件を使用することができます。


あなたの現在の問題に関係のない

が、余談として、タイマーおよびビューコントローラ間の強い参照サイクルを回避するためには、あなたが一般的にするとき、あなたがそれをinvalidateことができるようにタイマーへの参照を維持したいですビューが消えます(例えば、viewDidAppearにタイマーを作成し、viewDidDisappearで削除します)。

class GameViewController: UIViewController { 

    var timer: Timer? 

    override func viewDidAppear(_ animated: Bool) { 
     super.viewDidAppear(animated) 

     timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(setCalculationLs), userInfo: nil, repeats: true) 
    } 

    override func viewDidDisappear(_ animated: Bool) { 
     super.viewDidDisappear(animated) 

     timer?.invalidate() 
    } 

    func setCalculationLs() { 
     print("Tick") 
    } 
} 

またはiOS 10で、あなたはweakselfへの参照、およびdeinitinvalidateとブロックベースのバリアントを使用することができます:

class GameViewController: UIViewController { 

    var timer: Timer? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in 
      self?.setCalculationLs() 
     } 
    } 

    deinit { 
     timer?.invalidate() 
    } 

    func setCalculationLs() { 
     print("Tick") 
    } 

} 
そうでなければ、それは例えば、却下された後 GameViewControllerを保持終わることができ
+0

ああ!出来た。あなたの親切なサポートに感謝します。これは私のような新しい迅速な学習者にとって非常に役に立ちます。また、メイン・キュー以外からUI更新を開始しないように、アプリケーション・ロジックを変更しようとします。再度ありがとう –

+0

ロブ、あなたは[弱い自己]メソッドまたはviewDidLoad/viewDidDisappearメソッドを好むですか?ありがとう。 –

+0

私は '' [weak self] 'パターンが好きですが、古いiOSバージョンをサポートしているので古いAPIを使わなければならないことがあります。私の例が 'viewDidLoad' /' viewDidDisappear'の間に、古いAPIに悩まされているならば、 'viewDidAppear'と' viewDidDisappear'を提案するでしょう。 'viewDidDisappear'呼び出しとバランスをとることができます。特に、他のView Controllerをモーダルに 'present'している場合)。上記のviewDidLoadを使用したのは、OPが元の質問でタイマーを作成していた場所であるためです。 – Rob

関連する問題