2012-09-14 40 views
8

Sau khi đọc hàng chục câu hỏi tương tự, tôi muốn bắt đầu với câu lệnh sau: "Tôi đã thiết lập ủy nhiệm NSFetchedResultsController, nó không hoạt động." .NSFetchedResultsController không thấy chèn mới/xóa các giá trị đã tìm nạp sau khi cập nhật

Vì vậy, tôi có một TableViewController đơn giản có các ô được điền bằng NSFetchedResultsController. Dưới đây là đoạn code FRC init:

@property (strong, nonatomic) NSFetchedResultsController *frc; 

... 

- (NSFetchedResultsController *)frc 
{ 
    if (!_frc) 
    { 
     NSError *error = nil; 
     NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:e_product]; 
     request.sortDescriptors = [NSArray arrayWithObjects: 
           [NSSortDescriptor sortDescriptorWithKey:@"product_group.product_group_name" ascending:YES], 
           [NSSortDescriptor sortDescriptorWithKey:f_product_name ascending:YES], 
           nil]; 
     _frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[DTGGlobalSettings sharedInstance].moc sectionNameKeyPath:@"product_group.product_group_name" cacheName:nil]; 
     _frc.delegate = self; 
     [_frc performFetch:&error]; 
     if (error) 
     { 
      NSLog(@"Error while fetching products: %@!", error.userInfo); 
     } 
    } 

    return _frc; 
} 

Tôi cũng đã NSFetchedResultsController phương pháp đại biểu thực hiện với một số nhãn gỡ lỗi:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates. 
    NSLog(@"controllerWillChangeContent"); 
    [self.tableView beginUpdates]; 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 

    UITableView *tableView = self.tableView; 

switch(type) { 

    case NSFetchedResultsChangeInsert: 
     NSLog(@"didChangeObject - insert"); 
     [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     NSLog(@"didChangeObject - delete"); 
     [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeUpdate: 
     NSLog(@"didChangeObject - update"); 
     [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
     break; 

    case NSFetchedResultsChangeMove: 
     NSLog(@"didChangeObject - move"); 
     [tableView deleteRowsAtIndexPaths:[NSArray 
              arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     [tableView insertRowsAtIndexPaths:[NSArray 
              arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
} 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { 

switch(type) { 

    case NSFetchedResultsChangeInsert: 
     NSLog(@"didChangeSection - insert"); 
     [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     NSLog(@"didChangeSection - delete"); 
     [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
} 
} 


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
// The fetch controller has sent all current change notifications, so tell the table view to process all updates. 
NSLog(@"controllerDidChangeContent"); 
[self.tableView endUpdates]; 
} 

Trong Navigationbar của tôi, tôi có nút refresh, chức năng của nó là để cháy lên các danh mục sản phẩm phương pháp làm như sau: 1. Tìm nạp sản phẩm từ máy chủ MySQL từ xa 2. Nếu sản phẩm có ID không tồn tại - hãy tạo và điền tất cả các trường 3. Nếu tồn tại, tất cả các trường được cập nhật theo giá trị được tìm nạp

Sau hàng 2 và 3 cửa hàng được lưu. Tôi sử dụng một NSManagedObjectContext cho tất cả các hoạt động CoreData trên ứng dụng.

Khi tôi khởi động ứng dụng lần đầu tiên, TVC trống, vì chưa có sản phẩm nào được tìm nạp. Khi tôi nhấn Refresh, các sản phẩm mới được lấy và chèn vào ManagedObjectContext, nhưng NSManagedObjectContext không nhìn thấy/nghe thấy bất kỳ thay đổi nào: không có phương thức đại biểu nào được gọi, do đó không có hàng mới nào được thêm vào TVC. Khi tôi khởi động lại ứng dụng, các sản phẩm mới được đưa vào TVC mà không gặp vấn đề gì.

Nếu tôi nhấn nút làm mới một lần nữa khi có một số sản phẩm ở đó, sau khi trì hoãn ngắn, tất cả đều biến mất. Một số gỡ lỗi cho thấy rằng nếu xảy ra sau khi cập nhật các lĩnh vực của các thực thể (thực sự là các giá trị giống nhau) và lưu các cửa hàng. Phương pháp đại biểu thời gian này làm việc như một say mê và cho mỗi điều khiển thực thể được cập nhật và lưu: didChangeObject: atIndexPath: forChangeType: newIndexPath được gọi với forChangeType = NSFetchedResultsChangeDelete.

Câu hỏi # 1: tại sao NSFetchedResultsController không thấy thực thể được chèn mà không khởi động lại ứng dụng? Câu hỏi # 2: tại sao các nhãn NSFetchedResultsController đã tìm nạp các thực thể là "không tồn tại" (?) Và loại bỏ chúng khỏi TVC sau khi lưu trữ?

tôi sẽ đánh giá cao bất kỳ sự giúp đỡ và tư tưởng, là đấu tranh với vấn đề này cho cả tuần trước; (

UPD1 (đối với Jody): Dưới đây là một số chi tiết tôi sử dụng DTGGlobalSettings lớp tùy chỉnh để chia sẻ một số vars. . qua ứng dụng Đó là cách tôi init tài sản sharedInstance của nó:

+(DTGGlobalSettings *)sharedInstance 
{ 
    static DTGGlobalSettings *myInstance = nil; 

    if (nil == myInstance) 
    { 
     myInstance = [[[self class] alloc] init]; 
     // set values here 
     // try to acces MOC to init CoreData 
     [myInstance moc];   
     myInstance.baseURL = @"http://local.app/"; 
} 
return myInstance; 
} 

để init CoreData chồng tôi đã sử dụng một ví dụ từ tài liệu của Apple, bởi vì đối với một số lý do tôi không thấy hộp kiểm "sử dụng CoreData" khi tạo mới Tôi chắc chắn rằng tôi đã nhìn thấy nó trước đây trong Xc thơ ca ngợi, nhưng bây giờ tôi không; ((Xcode 4.4.1):

#pragma mark Core Data stack 

- (NSManagedObjectContext *) moc { 

if (_moc != nil) { 
    return _moc; 
} 
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
if (coordinator != nil) { 
    _moc = [[NSManagedObjectContext alloc] init]; 
    [_moc setPersistentStoreCoordinator: coordinator]; 
} 
return _moc; 
} 


- (NSManagedObjectModel *)managedObjectModel { 

if (_managedObjectModel != nil) { 
    return _managedObjectModel; 
} 
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];  
return _managedObjectModel; 
} 


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 

if (_persistentStoreCoordinator != nil) { 
    return _persistentStoreCoordinator; 
} 
NSURL *storeUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
storeUrl = [storeUrl URLByAppendingPathComponent:DOC_NAME]; 

NSError *error; 
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; 

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) { 
    NSLog(@"Error adding a store to the coordinator: %@, %@", error, error.userInfo); 
}   
return _persistentStoreCoordinator; 
} 

-(void)saveDataStore 
{ 
    NSError *error; 
    if (![self.moc save:&error]) NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
} 

Các 'moc' (ManagedObjectContext) tài sản của DTGGlobalSettings sau đó được sử dụng ở khắp mọi nơi trong ứng dụng mà tôi cần phải truy cập vào CoreData.

Đến phần thứ hai, hãy cập nhật cơ sở dữ liệu.Tôi đang nhận được một số thực thể mới ở định dạng JSON từ máy chủ web từ xa, đi qua từ điển kết quả và gọi phương thức createFromDictionary cho từng thực thể được tìm thấy trong kết quả yêu cầu. Đây là mã số:

+(Product *)createFromDictionary:(NSDictionary *)entityData inContext:(NSManagedObjectContext *)moc performUpdate:(BOOL)update 
{ 
Product *result; 
if (update) 
{ 
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:e_product]; 
    request.predicate = [NSPredicate predicateWithFormat:@"%K = %@", f_product_id, [entityData objectForKey:f_product_id]]; 
    result = [[DTGGlobalSettings sharedInstance].moc executeFetchRequest:request error:nil].lastObject; 
    if (!result) 
    { 
     NSLog(@"Error updating Product ID %@! Cannot fetch entity.", [entityData objectForKey:f_product_id]); 
     return nil; 
    } 
} else 
{ 
    result = [NSEntityDescription insertNewObjectForEntityForName:e_product inManagedObjectContext:[DTGGlobalSettings sharedInstance].moc]; 
} 

result.product_id = [[DTGGlobalSettings sharedInstance].numFormatter numberFromString:[entityData objectForKey:f_product_id]]; 
result.product_image = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[DTGGlobalSettings sharedInstance].baseURL stringByAppendingString:[entityData objectForKey:f_product_image]]]]; 
result.product_name = [entityData objectForKey:f_product_name]; 

return result; 
} 

Khi tôi hết các thực thể được phép, tôi gọi [[DTGGlobalSettings sharedInstance] saveDataStore] (xem bên trên). Tại thời điểm này, các hàng hiện có trong TVC (nếu có) sẽ biến mất. Trong trường hợp nếu tôi đã thêm một số thực thể mới, tại thời điểm lưu không có gì xảy ra, tức là TVC không cập nhật các hàng của nó.

+0

Bạn đã đăng sai mã. Các bit thú vị là cách bạn nhập dữ liệu vào cơ sở dữ liệu của mình và cách bạn thiết lập ngăn xếp dữ liệu lõi cho cả nhập và bộ điều khiển kết quả được tìm nạp. –

+0

Tôi đã thêm một số chi tiết bạn đã yêu cầu trong UPD1. Tôi hy vọng bây giờ nó rõ ràng hơn như thế nào tôi đã kết thúc với điều này ... – Arseniy

+0

bất kỳ suy nghĩ về việc cập nhật? – Arseniy

Trả lời

14

Thực ra, tôi cho rằng bài đăng trước khi chỉnh sửa đầu tiên của bạn có tất cả thông tin cần thiết. Tôi chỉ không đọc nó (Tôi không thích phải tiếp tục di chuyển phải đọc dòng mã dài và đôi khi chỉ không làm điều đó - xấu của tôi).

Sự cố của bạn dường như có liên quan đến các trình mô tả sắp xếp FRC của bạn.

FRC không xử lý tốt với việc giữ mô tả sắp xếp mối quan hệ được cập nhật rất tốt.

Một số người cho rằng nó được thiết kế như thế nào. Tôi cho rằng đó là một lỗi.

Xem bài đăng này Changing a managed object property doesn't trigger NSFetchedResultsController to update the table view để tôi lấy. Hy vọng rằng, bạn sẽ thấy những điểm tương đồng với trường hợp của bạn.

+0

Thật tuyệt vời! Tôi chỉ nhanh chóng loại bỏ các bộ mô tả sắp xếp và đường dẫn tên phần và nó đã hoạt động! Tôi sẽ không bao giờ đoán điều này hoạt động như thế này;) Cảm ơn! – Arseniy

+0

hiện sự cố này vẫn còn ở đó? –

+0

Có. https://insanitysauce.files.wordpress.com/2013/09/bsxgx3vciaax5g5.jpg –

1

tôi chỉ dành thời gian với cùng một vấn đề và phát hiện ra như sau: khi sectionNameKeyPath đã đề cập đến một lĩnh vực quan hệ mà có thể mất giá trị nil, bản cập nhật FRC sẽ không hoạt động khi chèn các đối tượng.

Điều này có thể liên quan đến cảnh báo trong bảng điều khiển Xcode nói rằng phần này sẽ được tạo cho các đối tượng có trường đó được đặt là nil. Tôi đoán rằng phần messes lên với FRC bên trong làm việc.

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