7

Tôi đang cố gắng triển khai đồng hồ bấm giờ dựa trên mô hình MVC.Mẫu quan sát cho đồng hồ bấm giờ

Đồng hồ bấm giờ sử dụng NSTimer với công cụ chọn -(void) tick được gọi là mọi thời gian chờ.

Tôi đã cố gắng làm cho đồng hồ bấm giờ làm mô hình cho khả năng sử dụng lại nhưng tôi đã gặp phải một số vấn đề về thiết kế liên quan đến cách cập nhật bộ điều khiển chế độ xem cho mỗi lần đánh dấu.

Trước tiên, tôi đã tạo giao thức bằng phương thức đánh dấu và đặt chế độ xem cho người đại diện của nó. Trình điều khiển chế độ xem sau đó cập nhật các chế độ xem dựa trên thuộc tính của bộ tính giờ tại mỗi dấu kiểm. elapsedTime là một NSTimeInterval chỉ đọc.

Nó hoạt động, nhưng tôi nghĩ nó có thể là thiết kế tồi. Tôi là một người mới bắt đầu với Objective-C/Cocoa Touch. Tôi có nên sử dụng một cái gì đó như KVO? Hoặc là có một giải pháp thanh lịch hơn cho mô hình để thông báo cho bộ điều khiển xem mà elapsedTime đã thay đổi?

+1

Câu hỏi hay nhất! Chào mừng bạn đến với SO! –

+0

Chính xác mối quan hệ giữa bộ hẹn giờ và bộ điều khiển xem là gì? Đồng hồ có thuộc sở hữu của VC không? –

+0

Cảm ơn bạn :) Timer được sở hữu bởi VC, vâng. Tôi đã thực hiện một IntervalTimer mà kế thừa từ Timer và sau đó VC sở hữu IntervalTimer thay vào đó - IntervalTimer thực sự là một trong những cho tôi một chút rắc rối. – Jach0

Trả lời

0

Gần đây, tôi đã sử dụng các khối thay vì đồng bằng cũ @selector 's. Nó tạo ra tốt hơn và mã và giữ logic trên cùng một vị trí.

Không có khối tự nhiên hỗ trợ trong NSTimer, nhưng tôi đã sử dụng một loại từ https://gist.github.com/250662/d4f99aa9bde841107622c5a239e0fc6fa37cb179

Nếu không có bộ chọn lại, bạn giữ mã trong một chỗ:

__block int seconds = 0; 
    NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:1 
               repeats:YES 
               usingBlock:^(NSTimer *timer) { 

               seconds++; 
               // Update UI 

               if (seconds>=60*60*2) { 
                [timer invalidate]; 
               } 




}]; 
5

Các bộ đếm thời gian là một cách tốt để đảm bảo rằng bạn cập nhật định kỳ giao diện người dùng của mình, nhưng không sử dụng nó để theo dõi thời gian. NSTimer can drift và mọi lỗi nhỏ có thể tích lũy nếu bạn sử dụng bộ hẹn giờ để tích lũy giây.

Thay vào đó, hãy sử dụng NSTimer để kích hoạt một phương thức cập nhật giao diện người dùng của bạn, nhưng nhận được thời gian thực bằng cách sử dụng NSDate. NSDate sẽ cho bạn độ phân giải mili giây; nếu bạn thực sự cần tốt hơn thế, hãy xem xét this suggestion to use Mach's timing functions. Vì vậy, sử dụng NSDate, mã của bạn có thể là một cái gì đó như thế này:

- (IBAction)startStopwatch:(id)sender 
{ 
    self.startTime = [NSDate date]; 
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 
                target:self 
               selector:@selector(tick:) 
               userInfo:repeats:YES]; 
} 

- (void)tick:(NSTimer*)theTimer 
{ 
    self.elapsedTime = [self.startTime timeIntervalSinceNow]; 
    [self updateDisplay]; 
} 

- (IBAction)stopStopwatch:(id)sender 
{ 
    [self.timer invalidate]; 
    self.timer = nil; 
    self.elapsedTime = [self.startTime timeIntervalSinceNow]; 
    [self updateDisplay]; 
} 

Mã của bạn có thể là một chút phức tạp hơn nếu bạn cho phép khởi động lại, vv, nhưng điều quan trọng ở đây là bạn không sử dụng NSTimer để đo tổng thời gian trôi qua.

Bạn sẽ tìm thấy thông tin hữu ích bổ sung trong this SO thread.

2

Tôi khuyên bạn nên chống lại KVO cho vấn đề này. Nó giới thiệu rất nhiều phức tạp (và một số gotchas gây phiền nhiễu) cho lợi ích nhỏ ở đây. KVO là quan trọng trong trường hợp bạn cần đảm bảo hoàn toàn chi phí tối thiểu. Apple sử dụng nó rất nhiều trong các trường hợp cho các đối tượng có hiệu suất cao, thấp như các lớp. Đây là giải pháp thường có sẵn duy nhất cung cấp zero-overhead khi không có người quan sát. Hầu hết thời gian, bạn không cần điều đó. Xử lý KVO một cách chính xác có thể khó khăn, và các lỗi nó có thể tạo ra là gây phiền nhiễu để theo dõi.

Không có gì sai với cách tiếp cận đại biểu của bạn. Đúng là MVC. Điều duy nhất bạn cần phải thực sự lo lắng là NSTimer không đưa ra lời hứa mạnh mẽ về thời điểm nó được gọi. Bộ hẹn giờ lặp lại thậm chí được phép bỏ qua trong một số trường hợp. Để tránh vấn đề đó, bạn thường muốn tính toán elapsedTime dựa trên thời gian hiện tại thay vì bằng cách tăng nó. Nếu bộ đếm thời gian có thể tạm dừng, thì bạn cần giữ một bộ tích lũy và ngày "tôi đã bắt đầu lần cuối".

Nếu bạn cần bộ hẹn giờ có độ chính xác cao hơn hoặc chi phí thấp hơn, bạn có thể xem dispatch_source_set_timer(), nhưng đối với đồng hồ bấm giờ đơn giản, NSTimer là một lựa chọn tuyệt vời cho một dự án đơn giản.

+0

Tôi biết vấn đề với bộ đếm thời gian bỏ qua và sử dụng tăng dần. Tôi đang sử dụng NSDate và trong setElapsedTime tôi so sánh NSDates (+ một offset khi tạm dừng được sử dụng) – Jach0

+0

Tôi đang cố gắng thực hiện một bộ đếm thời gian đếm ngược kế thừa từ đồng hồ bấm giờ và có một số thuộc tính bổ sung bao gồm workInterval và restInterval, nhưng các nhãn trong ViewController của tôi được cập nhật một chút lẻ. Tôi nghĩ rằng nó có thể có một cái gì đó để làm với các cuộc gọi tuần tự giữa tick của ViewController, đánh dấu Timers và IntervalTimers đánh dấu. – Jach0

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