14

thể trùng lặp:
Grand Central Dispatch (GCD) vs. performSelector - need a better explanationThực hiện thay đổi giao diện người dùng trên chuỗi chính bằng dispatch_async hoặc performSelectorOnMainThread?

Để thực hiện "công cụ" về các chủ đề chính, tôi nên sử dụng dispatch_async hoặc performSelectorOnMainThread? Có cách nào ưu tiên, đúng hay sai, và/hoặc thực hành tốt nhất?

Ví dụ: Tôi đang thực hiện một số logic trong khối phương thức NSURLConnection sendAsynchronousRequest:urlRequest. Bởi vì tôi đang làm công cụ cho chế độ xem chính như trình bày một UIAlertView Tôi cần hiển thị số UIAlertView trên chuỗi chính. Để làm điều này tôi đang sử dụng đoạn mã sau.

[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 

    // code snipped out to keep this question short 

    if(![NSThread isMainThread]) 
    { 
     dispatch_async(dispatch_get_main_queue(), ^{ 
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Oops!" message:@"Some Message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
        [alertView show]; 
     }); 
    } 
}]; 

Trong cùng tuyên bố if(![NSThread isMainThread]) Tôi cũng gọi một số phương thức tùy chỉnh. Câu hỏi là, tôi có nên sử dụng phương pháp dispatch_async mà tôi đang sử dụng ở trên hay tốt hơn là sử dụng performSelectorOnMainThread thay thế? Ví dụ, mã đầy đủ dưới đây:

[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 

    // code snipped out to keep this question short 

    if(![NSThread isMainThread]) 
    { 
     dispatch_async(dispatch_get_main_queue(), ^{ 
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Oops!" message:@"Some Message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
        [alertView show]; 

      // call custom methods in dispatch_async? 
      [self hideLoginSpinner]; 
     }); 

     // or call them here using performSelectorOnMainThread??? 
     [self performSelectorOnMainThread:@selector(hideLoginSpinner) withObject:nil waitUntilDone:NO]; 
    } 
}]; 

FYI - Nếu tôi KHÔNG thực hiện các hành động trên, ông chủ đề chính tôi nhìn thấy một vài giây chậm trễ khi trình bày các UIAlertView và tôi nhận được thông báo sau trong debugger wait_fences: failed to receive reply: 10004003. Tôi đã học được rằng điều này là bởi vì bạn cần phải thực hiện thay đổi cho giao diện người dùng trên chủ đề chính ... Trong trường hợp ai đó đang tự hỏi tại sao tôi đang làm những gì tôi đang làm ...

+2

liên quan chặt chẽ: [Sự khác nhau giữa performSelectorOnMainThread: và dispatch_async() trên hàng đợi chính là gì?] (Http://stackoverflow.com/questions/9335434/) –

+2

Sự khác biệt rõ ràng nhất từ ​​POV của _writing_ mã là việc gửi một khối là linh hoạt hơn: đó là cách dễ dàng hơn để xử lý các đối số nguyên thủy, chẳng hạn. –

Trả lời

14

Như đã đề cập trong các liên kết do Josh Caswell cung cấp, cả hai đều gần như tương đương. Sự khác biệt đáng chú ý nhất là performSelectorOnMainThread sẽ chỉ thực thi ở chế độ vòng lặp chạy mặc định và sẽ đợi nếu vòng lặp chạy đang chạy trong chế độ theo dõi hoặc chế độ khác. Tuy nhiên, có một số khác biệt đáng kể cho việc viết và duy trì mã.

  1. dispatch_async có lợi thế lớn mà trình biên dịch thực hiện tất cả các kiểm tra thông thường của nó. Nếu bạn nhập sai phương thức trong performSelectorOnMainThread bạn không thành công vào thời gian chạy, thay vì thời gian biên dịch.
  2. dispatch_async giúp việc trả lại dữ liệu từ chủ đề chính dễ dàng hơn bằng cách sử dụng vòng loại __block.
  3. dispatch_async làm cho việc xử lý đối số nguyên thủy trở nên dễ dàng hơn nhiều vì bạn không phải quấn chúng trong một đối tượng. Tuy nhiên, điều này đi kèm với một cạm bẫy tiềm năng. Nếu bạn có một con trỏ đến một số dữ liệu, hãy nhớ rằng việc chụp khối không sao chép sâu dữ liệu. Mặt khác gói dữ liệu trong một đối tượng như bạn sẽ bị buộc phải làm cho performSelectorOnMainThread sao chép sâu (trừ khi bạn đặt các tùy chọn đặc biệt). Nếu không có một bản sao sâu, bạn có thể chạy vào các lỗi liên tục đang bực bội để gỡ lỗi. Vì vậy, điều này có nghĩa là bạn nên quấn những thứ như char * trong NSString trước khi gọi số dispatch_async.
+0

1. 'performSelectorOnMainThread' hiện hiển thị cảnh báo bộ chọn không khai báo. – ma11hew28

+0

Nếu bạn bật cảnh báo Bộ chọn không khai báo trong cài đặt Xcode, bạn sẽ nhận được kiểm tra thời gian xây dựng _some_ bất kỳ lúc nào @selector được sử dụng, bao gồm trong 'performSelectorOnMainThread'.Điều này giúp với lỗi chính tả, nhưng phải nhận thức được những hạn chế của cảnh báo này. Nó kiểm tra nếu bất kỳ bộ chọn phù hợp nào đã được khai báo chưa, không chỉ các bộ chọn đối tượng mà bạn đang gọi 'performSelectorOnMainThread' trên đó. Thứ hai, điều này thực thi một quy ước kiểu mã hóa rằng các phương thức và bộ chọn phải được khai báo trước khi được sử dụng. –

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