2017-05-03 16 views
5

Tôi có hai chế độ xem trong ứng dụng nhanh chóng của mình. Tôi đang thực hiện một segue như dưới đây.Swift Timer.scheduledTimer() không hoạt động

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

Khi tải GameViewController một mảng giá trị cũng truyền cho GameViewController.swift từ ViewController.swift

Bạn phải khởi chạy bộ hẹn giờ trong GameViewController.swift

Tôi đã cố gắng khởi tạo bộ hẹn giờ và gọi phương thức qua bộ hẹn giờ nhưng không hoạt động.

Sau đây là các đoạn mã của tôi.

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

Tôi cảm thấy đó là vấn đề với việc đặt đối tượng đích trong bộ hẹn giờ. Bất kỳ suggetions. Cảm ơn –

+0

Bạn không gửi mảng tới 'GameViewController', làm điều đó trong' chuẩn bị (cho: người gửi:) '. tham số 'sender' phải là' self' – paper1111

+0

Chính xác thì vấn đề là gì? GameViewController có được tải không? ViewDidLoad() có được gọi không? Làm thế nào là mảng đi qua liên quan đến vấn đề hẹn giờ? - Nói chung, mã hẹn giờ của bạn sẽ hoạt động. –

Trả lời

10

Timers không làm việc trên hàng đợi nền (không có một số trò ảo thuật của bàn tay liên quan đến việc tạo ra các vòng lặp chạy hoặc bằng tay lịch nó trên một chạy hiện vòng lặp). Tuy nhiên, bạn không bao giờ nên bắt đầu bất kỳ cập nhật giao diện người dùng nào từ bất kỳ thứ gì khác ngoài hàng đợi chính. Vì vậy, kể từ khi bạn đang gọi performSegue từ một đóng cửa hoàn thành URLSession (chạy trên hàng đợi nền), nó thực sự đang chạy viewDidLoad từ hàng đợi nền, quá. Do đó, nỗ lực lên lịch hẹn giờ không thành công. Để làm được việc này, bạn phải tự cử mã performSegue vào hàng đợi chính:

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

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

Nếu bạn đã từng không chắc chắn cho dù một số mã đang chạy trên hàng đợi chính hay không, hãy tham khảo the documentation. Hoặc bạn có thể sử dụng điều kiện tiên quyết của công văn:

dispatchPrecondition(condition: .onQueue(.main)) 

Bằng cách đó, bạn sẽ vô tình gọi ứng dụng nếu bạn vô tình gọi mã từ hàng đợi nền.


Không liên quan đến vấn đề hiện tại của bạn, nhưng như một sang một bên, để tránh một chu kỳ tài liệu tham khảo chặt chẽ giữa các bộ đếm thời gian và bộ điều khiển xem, bạn thường muốn giữ một tham chiếu đến bộ đếm thời gian để bạn có thể invalidate nó khi chế độ xem biến mất (ví dụ: tạo bộ hẹn giờ trong viewDidAppear và xóa nó trong viewDidDisappear). Nếu không, bạn có thể kết thúc giữ lại GameViewController sau khi nó đã bị sa thải, ví dụ:

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") 
    } 
} 

Hoặc trong iOS 10, bạn có thể sử dụng các biến thể dựa trên khối với weak tham chiếu đến self, và invalidate trong deinit:

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") 
    } 

} 
+0

Ồ! nó đã làm việc. Cảm ơn bạn rất nhiều vì đã ủng hộ bạn. Điều này sẽ rất hữu ích cho những người học nhanh như tôi. Và tôi cũng sẽ cố gắng thay đổi logic ứng dụng của mình để không bắt đầu cập nhật giao diện người dùng từ bất kỳ thứ gì khác ngoài hàng đợi chính. Cảm ơn một lần nữa –

+0

Rob, bạn có thích phương pháp [yếu tự] hoặc phương thức viewDidLoad/viewDidDisappear không? Cảm ơn. –

+0

Tôi thích mẫu 'tự yếu hơn ', nhưng đôi khi bạn phải sử dụng API cũ vì bạn đang hỗ trợ các phiên bản iOS cũ. Và nếu bạn đang mắc kẹt với API cũ đó, về mặt kỹ thuật, trong khi ví dụ của tôi là 'viewDidLoad' /' viewDidDisappear', tôi có thể đề nghị 'viewDidAppear' và' viewDidDisappear' (vì chúng sẽ luôn được cân bằng, trong khi 'viewDidLoad' có thể không được cân bằng với các cuộc gọi 'viewDidDisappear', đáng chú ý nếu bạn' hiện tại 'một bộ điều khiển xem khác một cách bình thường). Tôi chỉ sử dụng 'viewDidLoad' ở trên vì đó là nơi OP tạo bộ đếm thời gian của anh ấy trong câu hỏi gốc. – Rob

Các vấn đề liên quan