2012-03-05 30 views
13

Tôi đang cố hủy và sau đó phát hành bộ hẹn giờ bị tạm dừng nhưng khi tôi gọi 'dispatch_release' trên đó, tôi ngay lập tức nhận được EXC_BAD_INSTRUCTION.dispatch_source_cancel trên bộ hẹn giờ bị tạm dừng khiến EXC_BAD_INSTRUCTION

Đây có phải là tập hợp hành động hợp lệ để thực hiện hẹn giờ không?

tạo Hẹn giờ & treo:

@interface SomeClass: NSObject { } 
@property (nonatomic, assign) dispatch_source_t    timer; 
@end 

// Class implementation 
@implementation SomeClass 

@synthesize timer = _timer; 

- (void)startTimer 
{ 
    dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 
            0, 0, globalQ); 

    dispatch_time_t startWhen = dispatch_walltime(DISPATCH_TIME_NOW, NSEC_PER_SEC * 1); 
    dispatch_source_set_timer(_timer, startWhen, 1 * NSEC_PER_SEC, 5000ull); 

    dispatch_source_set_event_handler(_timer, ^{ 
     // Perform a task 

     // If a particular amount of time has elapsed, kill this timer 
     if (timeConstraintReached) 
     { 
      // Can I suspend this timer within it's own event handler block? 
      dispatch_suspend(_timer); 
     } 
    }); 

    dispatch_resume(_timer); 
} 

- (void)resetTimer 
{ 
    dispatch_suspend(_timer); 

    dispatch_source_cancel(_timer); 

    // dispatch_release causes 
    // 'EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 
    dispatch_release(_timer); 

    self.timer = nil;  
} 
@end 

Ngoài ra, tôi có thể gọi dispatch_suspend trong khối event_handler một nguồn hẹn giờ không?

Mọi trợ giúp sẽ được đánh giá cao.

Trả lời

24

Lý do nó bị treo là vì this code:

void 
_dispatch_source_xref_release(dispatch_source_t ds) 
{ 
    if (slowpath(DISPATCH_OBJECT_SUSPENDED(ds))) { 
     // Arguments for and against this assert are within 6705399 
     DISPATCH_CLIENT_CRASH("Release of a suspended object"); 
    } 
    _dispatch_wakeup(ds); 
    _dispatch_release(ds); 
} 

Vì vậy, bạn không thể phát hành một dispatch_source_t đã bị tạm dừng. Bạn có thể muốn chỉ không đình chỉ nó trong resetTimer Tôi đoán.

Mặc dù tôi không thể tìm thấy bất kỳ thứ gì trong tài liệu vì lý do tại sao họ viết nó như thế này (và nhận xét ám chỉ những ưu và nhược điểm trong một radar mà chúng ta sẽ không bao giờ thấy), tất cả những gì tôi có thể làm là tham khảo the docs where it says:

Bạn có thể tạm ngưng và tiếp tục phân phối các sự kiện nguồn công văn tạm thời sử dụng phương thức dispatch_suspend và dispatch_resume. Các phương thức này tăng và giảm số lượng tạm dừng cho đối tượng công văn của bạn. Do đó, bạn phải cân bằng mỗi cuộc gọi đến dispatch_suspend bằng cuộc gọi phù hợp để dispatch_resume trước sự kiện hồ sơ gửi lại.

Trong khi điều đó không cho biết bạn không thể giải phóng nguồn công văn đã bị tạm ngưng, điều đó có nghĩa là bạn phải cân bằng từng cuộc gọi để tôi giả định nó là gì đó. - mui xe phải là balanced before they can be released. Đó chỉ là phỏng đoán của tôi mặc dù :-).

Đối với "tôi có thể gọi dispatch_suspend trong khối event_handler của bộ hẹn giờ". Tôi chắc chắn bạn có thể, vâng, theo tài liệu cho dispatch_suspend:

Việc tạm ngưng xảy ra sau khi hoàn thành bất kỳ khối nào đang chạy tại thời điểm cuộc gọi.

+0

Tôi hiểu rồi. Bởi vì mỗi dispatch_suspend 'gia tăng số lượng đình chỉ của đối tượng', phải có một 'dispatch_resume' để cân bằng việc đình chỉ. –

+0

Có khả thi để hủy bỏ hoặc đình chỉ bộ đếm thời gian trong khối event_handler của nó hoặc điều đó có xảy ra bên ngoài khối không? –

+0

Đúng vậy. Xem câu trả lời cập nhật của tôi. Trong khi các tài liệu không thực sự nhà nước (mà tôi có thể tìm thấy) mà bạn không thể phát hành khi nó bị đình chỉ, tôi nghi ngờ nó có một số trạng thái nội bộ gây ra badness nếu bạn đã làm. – mattjgalloway

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