5

Tôi có vòng lặp for mà tôi muốn thêm độ trễ giữa các lần lặp. Tôi đã thay đổi waitUntilDone thành YES và nhận được kết quả tương tự. mảng của tôi chỉ có hai con số trong đó và cả hai đều được gọi là chỉ sau năm giây thay vì:Mục tiêu C cho độ trễ vòng lặp

0s - không có gì 5s - Chặn gọi 10s- Khối gọi

for(NSNumber* transaction in gainsArray) { 

    double delayInSeconds = 5.0; 
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
    dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { 

     NSLog(@"Block"); 

     [self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:) 
     withObject:transaction waitUntilDone:NO]; 

    }); 
} 

2015-06-16 20:11:06.485 TestApp[97027:6251126] Block 
2015-06-16 20:11:06.485 TestApp[97027:6251127] Block 

Tôi đang sử dụng Cocos2d nếu có vấn đề

+0

Sử dụng một 'NSTimer' cũng giải pháp tốt. – zaph

+0

@zaph NSTimer không hoạt động tốt với cocos2d hoặc SpriteKit. Ưu tiên các phương thức 'schedule' được xây dựng cung cấp bởi CCNode và tất cả các lớp dẫn xuất của nó. – YvesLeBorg

Trả lời

4

Vòng lặp for sẽ gửi ngay sau cái kia để chúng về cơ bản sẽ trì hoãn cùng một lúc.
Thay vì thiết lập một sự chậm trễ tăng khác nhau cho mỗi:

double delayInSeconds = 0.0; 
for(NSNumber* transaction in gainsArray) 
{ 
    delayInSeconds += 5.0; 
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
    dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) 
        { 
         NSLog(@"Block"); 
         [self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:) 
               withObject:transaction 
              waitUntilDone:NO]; 

       }); 
} 
+1

Nó hoạt động hoàn hảo! Cảm ơn bạn! – Asdrubal

+0

Nó hoạt động như một phép thuật !! Upvoted .. – NSPratik

1

@zaph có một giải pháp khá tốt. Tôi nghĩ tôi sẽ thử từ một góc độ khác. Vì mục tiêu-C là Mục tiêu -C, tại sao không xác định một số loại đối tượng để thực hiện vòng lặp theo thời gian này? Gợi ý: điều này tồn tại. Chúng ta có thể sử dụng NSTimer và thuộc tính userInfo của nó để làm việc này. Tôi nghĩ rằng các giải pháp là loại thanh lịch, nếu không phải là một khó chịu hack.

// Somewhere in code.... to start the 'loop' 
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
                target:self 
                action:@selector(processNextTransaction:) 
               userInfo:@{ 
                  @"gains": [gainsArray mutableCopy] 
                  } 
               repeats:NO]; 

// What handles each 'iteration' of your 'loop' 
- (void)processNextTransaction:(NSTimer *)loopTimer { 
    NSMutableArray *gains = [loopTimer.userInfo objectForKey:@"gains"]; 
    if(gains && gains.count > 0) { 
     id transaction = [gains firstObject]; 
     [gains removeObjectAtIndex:0]; // NSMutableArray should really return the object we're removing, but it doesn't... 
     [self private_addTransactionToBankroll:transaction]; 
     NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
                  target:self 
                  action:@selector(processNextTransaction:) 
                 userInfo:@{ 
                    @"gains": gains 
                    } 
                 repeats:NO]; 
    } 
} 

Tôi sẽ kiểm tra xem NSTimer có được giữ lại bằng cách được thêm vào vòng lặp chạy hay không. Nếu đó không phải là trường hợp, bạn nên lưu trữ một tham chiếu đến nó như là một tài sản trên bất cứ lớp nào đang quản lý tất cả điều này.

Cũng cần lưu ý rằng vì NSTimers được cài đặt trên vòng lặp chính theo mặc định, bạn không cần phải lo lắng về tất cả các công cụ GCD. Sau đó, một lần nữa, nếu công việc này là công việc khá khó khăn, bạn có thể muốn -processNextTransaction: để giảm tải công việc của nó lên một hàng đợi GCD khác và sau đó trở lại hàng đợi chính để khởi tạo thể hiện NSTimer.

Đảm bảo sử dụng phương thức -scheduledTimer...; timer... phương pháp lớp học trên NSTimer không cài đặt nó trên bất kỳ vòng lặp, và các đối tượng chỉ ngồi trong không gian làm gì. Đừng làm repeats:YES, điều đó sẽ bi thảm, vì bạn muốn có bộ hẹn giờ gắn liền với vòng lặp chạy willy-nilly, không có tham chiếu nào trỏ đến chúng để biết cách hoặc nơi dừng chúng. Đây thường là một điều xấu.

Để tránh EXC_BAD_ACCESS ngoại lệ, không bao giờ dealloc đối tượng có phương thức NSTimer sẽ gọi, nếu bộ hẹn giờ đó chưa kích hoạt. Bạn có thể muốn lưu trữ NSTimer đang chờ xử lý trong một thuộc tính trên lớp của bạn để bạn có thể xử lý loại điều này. Nếu đó là một ViewController mà là quản lý tất cả điều này (mà nó thường là), sau đó tôi sẽ sử dụng mã sau đây để làm sạch bộ đếm thời gian trên -viewWillDisappear. (Điều này giả định rằng bạn đang thiết lập một bộ đếm thời gian mới cho một số @property, self.timer)

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 
    if(self.timer) { 
     [self.timer invalidate]; // -invalidate removes it from the run loop. 
     self.timer = nil; // Stop pointing at it so ARC destroys it. 
    } 
} 
+0

Cảm ơn bạn đã dành thời gian để cung cấp một giải pháp khác và giải thích rõ. Tôi đánh giá cao nó. – Asdrubal

+1

Tất nhiên! Trả lời các câu hỏi chuyên sâu là một cách hay để tôi đảm bảo rằng tôi luôn mạnh mẽ, vì vậy tôi xem đó là một chiến thắng. – josefdlange

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