2012-03-29 21 views
13

Tôi tự hỏi liệu có ai đó có thể giải thích lý do tại sao gửi lại hàng đợi chính và tạo lặp lại NSTimer Tôi phải thêm nó vào RUN LOOP vì nó quá cháy? Ngay cả khi sử dụng performselectorOnMainThread Tôi vẫn phải thêm nó vào một RUN LOOP để làm cho nó cháy.NSTimer yêu cầu tôi thêm nó vào một runloop

Dưới đây là một ví dụ về câu hỏi của tôi:

#define queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
#define mainqueue dispatch_get_main_queue() 

- (void)someMethodBeginCalled 
{ 
    dispatch_async(queue, ^{ 
     int x = 0; 
     dispatch_async(mainqueue, ^(void){ 
      if([_delegate respondsToSelector:@selector(complete:)]) 
       [_delegate complete:nil]; 
     }); 
    }); 
} 

- (void)compelete:(id)object 
{ 
    [self startTimer]; 

    //[self performSelectorOnMainThread:@selector(startTimer) withObject:nil waitUntilDone:NO]; 
} 

- (void)startTimer 
{ 
    NSTimer timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(callsomethingelse) userInfo:nil repeats:YES]; 

    //NSDefaultRunLoopMode 
    [[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes]; 
} 

EDIT: Tôi tin rằng tôi diễn đạt câu hỏi này rất kém. Tôi muốn biết lý do tại sao[[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes]; là cần thiết trong startTimer nếu tôi gọi someMethodBeginCalled. Nếu tôi không bao gồm dòng đó, bộ hẹn giờ không kích hoạt.

Nếu tôi gọi startTimer từ viewDidLoad ví dụ, tôi có thể xóa đường dây NSRunLoop và bộ hẹn giờ sẽ kích hoạt sau mỗi 60 giây.

Trả lời

12

Bạn luôn có thể sử dụng phương pháp này để thay thế:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(getBusLocation) userInfo:nil repeats:YES];

Điều này sẽ giúp bạn tiết kiệm một dòng, vì nó sẽ thêm nó vào vòng lặp chạy tự động.

+5

Đây là cách tiếp cận bình thường. Rất hiếm khi thêm bộ hẹn giờ vào một runloop theo cách thủ công. Tuy nhiên, bạn nên giữ bộ đếm thời gian trong một chiếc ngà để bạn có thể vô hiệu hóa nó khi cần thiết. –

+0

Có, nếu không, đối tượng mà cuộc gọi sẽ không bao giờ được deallocated nếu bạn có một bộ đếm thời gian lặp lại. – borrrden

+0

Tôi đã chỉnh sửa câu hỏi, về cơ bản tôi hỏi tại sao tôi không thể sử dụng chỉ dòng của bạn khi tôi khởi tạo nó từ dispatch_async trên hàng đợi chính. Không có đường NSRunLoop, bộ hẹn giờ sẽ không kích hoạt. – chicken

3

Bởi vì, như các docs nói:

Timers làm việc kết hợp với các vòng chạy. Để sử dụng bộ hẹn giờ hiệu quả, bạn nên biết các vòng chạy hoạt động như thế nào — xem NSRunLoop và Hướng dẫn lập trình luồng. Lưu ý đặc biệt là các vòng chạy giữ lại bộ hẹn giờ của chúng, vì vậy bạn có thể phát hành bộ hẹn giờ sau khi bạn thêm nó vào vòng lặp chạy .

Đây là quyết định thiết kế mà Apple đã thực hiện khi viết mã cho NSTimer (và tôi chắc rằng họ có lý do chính đáng để làm như vậy) và chúng tôi không thể làm gì để giải quyết nó. Có thực sự là gánh nặng?

+7

Để rõ ràng: NSTimers được triển khai như là một phần của vòng lặp chạy. Một trong các nguồn vòng lặp chạy là "có bất kỳ NSTimers đang chờ xử lý nào cần được kích hoạt." Một NSTimer chỉ là một số dữ liệu treo trên một runloop. Đây là một điều rất tốt, bởi vì nó có nghĩa là bộ tính giờ không yêu cầu luồng. –

18

Và dưới đây là cách để thêm một NSTimer đến một runloop:

NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
[runLoop addTimer:timer forMode:NSDefaultRunLoopMode]; 
+1

OP yêu cầu lý do thêm bộ hẹn giờ vào vòng lặp chạy thay vì cách thêm bộ hẹn giờ vào vòng lặp chạy . – chengsam

2

Giống như @sosborn nói, NSTimer s phụ thuộc vào NSRunLoop s, và kể từ khi hàng đợi GCD tạo chủ đề mà không phải chạy vòng, NSTimer doesn chơi tốt với GCD.

Check-out này StackOverflow câu hỏi khác về vấn đề này: Is it safe to schedule and invalidate NSTimers on a GCD serial queue?

Để giải quyết vấn đề đó, tôi thực hiện MSWeakTimer: https://github.com/mindsnacks/MSWeakTimer (và đã thực hiện kiểm tra bởi một kỹ sư libdispatch tại WWDC cuối cùng!)

+0

Tôi đoán bạn có nghĩa là _NSTimer không chơi tốt với ** hàng đợi GCD ** _, phải không? – 0xced

+0

Chính xác! Tôi đã sửa lỗi này. –

0

Thêm bộ đếm thời gian cho runloop không hoạt động trong trường hợp của tôi. Tôi đã phải tạo bộ đếm thời gian trên sợi chính. Tôi đã tạo chủ đề này trong một đại biểu MultipeerConnectivity.

dispatch_async(dispatch_get_main_queue(), ^{ 
     self.timer = [NSTimer scheduledTimerWithTimeInterval:self.interval invocation: self.invocation repeats:YES]; 
    }); 
0

phương pháp hẹn giờ sẽ không được gọi từ GCD hàng đợi tạo chủ đề mà không phải chạy vòng

dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{ [NSTimer scheduledTimerWithTimeInterval: 1 lặp đi lặp lại: YES block:^(NSTimer * _Bộ định giờ không dây) { NSLog (@ "Phương thức hẹn giờ từ hàng đợi chính GCD"); }];

});

Tuy nhiên khi được gửi đi trên hàng đợi chính, phương thức hẹn giờ sẽ được gọi vì nó sẽ được thêm vào chuỗi chính chạy vòng lặp.

dispatch_async (dispatch_get_main_queue(),^{ [NSTimer scheduledTimerWithTimeInterval: 1 lặp đi lặp lại: YES khối:^(NSTimer * _Nonnull timer) { NSLog (@ "phương pháp hẹn giờ từ hàng đợi chính GCD"); }];

});