11

Tôi đang tạo một ứng dụng trò chuyện nhỏ. Trong ứng dụng của tôi, tôi đang sử dụng NSFetchedResultsController. Có 2 tableViews, 1 cho sảnh và 1 cho phòng chat. Vấn đề là bất cứ khi nào tôi bước vào một phòng chat, tôi phải đợi NSFetchedResultsController thực hiện tìm nạp và tải tất cả dữ liệu trước khi tôi có thể bắt đầu gõ bất cứ điều gì. Tôi đã tự hỏi nếu nó có thể phôi lấy trong nền hoặc bằng cách nào đó cho phép người dùng bắt đầu gõ trước khi các tin nhắn mới nhất được nạp.Thực hiện tìm nạp mà không bị đóng băng Giao diện người dùng

Vì vậy, nếu tôi đặt một phần trong phương pháp viewDidLoad, giao diện người dùng của tôi chỉ bị đóng băng cho đến khi tất cả các dữ liệu được nạp:

NSError *_error; 
if (![self.fetchedResultsController performFetch:&_error]) { 
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]); 
} 

và nếu tôi đặt rằng đoạn mã vào một phương pháp riêng biệt và sau đó gọi phương pháp đó trong viewDidLoad trong nền

[self performSelectorInBackground:@selector(fetchIt) withObject:nil]; 

tableView chỉ là không cập nhật, vì vậy tôi phải quay trở lại để tableView đầu tiên và sau đó trở lại để có được bất kỳ kết quả.

Cảm ơn bạn.

Bất kỳ trợ giúp sẽ được đánh giá

cập nhật

tôi đã làm thử một vài cách khác để làm điều đó.

Cách 1:

-(void)reloadTheTable 
{ 
    [self.tableView reloadData]; 
} 

-(void)fetchIt 
{ 
    NSError *_error; 
    if (![self.fetchedResultsController performFetch:&_error]) { 
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]); 
    } 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; 
    [self performSelectorOnMainThread:@selector(reloadTheTable) withObject:nil waitUntilDone:NO]; 
    [pool release]; 
} 

- (void)viewDidLoad { 
    //some code 
    [self performSelectorInBackground:@selector(fetchIt) withObject:nil]; 
    //some other code 
} 

kết quả: tableView không hiển thị bất kỳ dữ liệu, cần phải mở lại mà điều khiển xem

Way 2:

- (void)viewDidLoad { 
    //some code 
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 
    NSError *_error; 
    if (![self.fetchedResultsController performFetch:&_error]) { 
     NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]); 
    } 
    }); 
    //some other code 
} 

kết quả: cập nhật tableView , nhưng giao diện người dùng bị đóng băng

Cách 3:

-(void)fetchIt 
{ 
    NSError *_error; 
    if (![self.fetchedResultsController performFetch:&_error]) { 
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]); 
    } 
} 

- (void)viewDidLoad { 
    //some code 
    [self performSelectorOnMainThread:@selector(fetchIt) withObject:nil waitUntilDone:NO]; 
    //some other code 
} 

kết quả: Giao diện người dùng bị đóng băng, cập nhật chế độ xem bảng.

Khi tôi đọc ở đâu đó, mọi thứ phải làm gì đó với giao diện người dùng phải được thực hiện trên một chuỗi chính. Nhưng tôi vẫn không thể tìm ra cách để làm điều đó mà không đóng băng tableView.

Cảm ơn bạn đã đọc.

Any help is appreciated

+1

Tôi nghĩ bạn đang tìm [THIS] này (http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html). – Kjuly

+0

@Kjuly cảm ơn, nhưng nó vẫn là kinda không phản hồi. Sử dụng dispatch_async (dispatch_get_main_queue(),^{...}); – Novarg

+0

Không sử dụng 'dispatch_get_main_queue' điều này sẽ chặn ứng dụng của bạn, hoặc khi giao diện người dùng chạy trong chuỗi chính, bạn cần tìm nạp dữ liệu trong các chuỗi khác. – Kjuly

Trả lời

13

Tôi không chắc liệu điều này sẽ làm việc hay không, nhưng bạn có thể có một thử:

- (void)methodThatloadYourData { 
    NSError *_error; 
    if (![self.fetchedResultsController performFetch:&_error]) { 
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]); 
    } 
} 

- (void)viewDidLoad { 
    //some code 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), 
       ^{ 
        [self performSelector:@selector(methodThatloadYourData)]; 
        dispatch_async(dispatch_get_main_queue(), 
            ^{ 
             [self.tableView reloadData]; 
            }); 
       }); 

    //some other code 
} 
+0

vừa qua Tôi đã sử dụng vấn đề này cho vấn đề tương tự.Nó hoạt động như mong đợi ngoại trừ khi bảng nạp lại nó là BLAM, tất cả các bản ghi xuất hiện cùng một lúc một cách đột ngột. Tôi nghĩ tôi đã nao núng lần đầu tiên tôi thấy điều này khiến tôi ngạc nhiên đến thế. Bất cứ ai có thể nghĩ ra một cách để làm cho họ chảy một chút hữu cơ hơn vào vị trí mà không sợ người sử dụng? –

+1

@DeanDavids bạn có thể tạo phương thức (ví dụ: 'reloadDataAnimated: (BOOL) hoạt ảnh') với hoạt ảnh mờ dần và đặt' [self.tableView reloadData]; 'vào phương thức này. Sau đó, sử dụng 'dispatch_async (dispatch_get_main_queue(),^{[self reloadDataAnimated: YES];});' Tôi chưa thử, chỉ là một gợi ý. :) – Kjuly

+0

Đã bỏ phiếu. Đây là câu trả lời cũ nhưng điều này hoàn toàn sai. Điều này sẽ trở lại trong các vấn đề luồng với NSManagedObjectContext. Bật Nhật ký đa luồng và bạn sẽ nhận được CoreData' + [NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__] :. –

1

Khi lấy được thực hiện trong fetchIt phương pháp, gọi phương thức reloadData trong UITableView.Để tham khảo nhiều hơn, hãy xem tài liệu của Apple trên UITableView

Edit:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    [self.tableView reloadData]; 
} 

cho biết thêm, hãy truy cập Apple documentation

+0

cảm ơn câu trả lời, nhưng nó vẫn không hiển thị bất cứ điều gì – Novarg

+0

Bạn có thể vui lòng cho tôi biết nơi bạn đang tải lại bảng không? – Ilanchezhian

+0

Tôi đặt nó vào dòng cuối cùng của phương thức "fetchIt". Toàn bộ phương thức trông giống như sau: - (void) fetchIt { NSError * _error; \t nếu (! [Self.fetchedResultsController performFetch: & _ error]) { \t \t NSLog (@ "Lỗi chưa được giải quyết% @,% @", _error, [_error userInfo]); \t} [self.tableView reloadData]; } – Novarg

1

Công văn yêu cầu lấy của bạn vào một chủ đề mới:

dispatch_queue_t coreDataThread = dispatch_queue_create("com.YourApp.YourThreadName", DISPATCH_QUEUE_SERIAL); 

    dispatch_async(YourThreadName, ^{ 

Your Fetch Request 

    }); 

    dispatch_release(YourThreadName); 
+0

cảm ơn câu trả lời, nhưng tableView không tải lại trừ khi tôi mở lại bộ điều khiển xem – Novarg

1

Đặt yêu cầu tìm nạp số fetchBatchSize để bạn không thực sự tìm nạp tất cả dữ liệu cùng một lúc. Bạn có thể chỉ cần đủ hồ sơ để lấp đầy màn hình, cộng thêm một số chi tiết nữa để giữ cho cuộn đầu tiên được đáp ứng. Nếu dữ liệu được đề cập là, ví dụ: các tin nhắn trò chuyện, tôi nghĩ rằng việc giới hạn tìm nạp trong 50 hoặc 100 thư gần đây nhất sẽ làm tăng tốc độ đáng kể.

+0

cảm ơn câu trả lời, nhưng nó đã chỉ tìm nạp 50 – Novarg

0

Trước hết, chỉ số thuộc tính thực thể của bạn đúng cách để các truy vấn chạy nhanh hơn, đặc biệt là nếu phân loại. Sau đó xem xét tối ưu hóa yêu cầu tìm nạp của bạn, bằng cách đặt kích thước lô, giới hạn dữ liệu ở mức tối thiểu cần thiết. Sử dụng trình gỡ lỗi SQL để kiểm tra truy vấn và thậm chí kiểm tra các truy vấn sẽ tự động xử lý lại tệp sqlite bằng cách sử dụng một ứng dụng như Base. Nếu bạn cố gắng sử dụng đa luồng không cần thiết cho một ứng dụng đơn giản như vậy, nó sẽ chỉ làm cho vấn đề tồi tệ hơn.

FYI trong mã của bạn, viewDidLoad đã có trên chuỗi chính. Nếu bạn đang cố gắng trì hoãn tìm nạp cho đến sau khi khung nhìn được tải thì bạn có thể sử dụng performSelector afterDelay: 0.

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