2012-01-12 2 views
6

Tôi đang sử dụng RestKit để lấy các đối tượng từ dịch vụ RoR của mình và sử dụng CoreData để duy trì một số đối tượng (các đối tượng bảng tra cứu kiểu tĩnh). TasteTag là một trong những đối tượng được lưu giữ lâu dài:Các thực thể lõi dữ liệu lồng nhau được lưu trữ đã tải xuống NSObjectInaccessibleException

#ifdef RESTKIT_GENERATE_SEED_DB 
    NSString *seedDatabaseName = nil; 
    NSString *databaseName = RKDefaultSeedDatabaseFileName; 
#else 
    NSString *seedDatabaseName = RKDefaultSeedDatabaseFileName; 
    NSString *databaseName = @"Model.sqlite"; 
#endif 

RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:kServerURL]; 
manager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:databaseName usingSeedDatabaseName:seedDatabaseName managedObjectModel:nil delegate:self]; 

.. lots of fun object mapping .. 

RKManagedObjectMapping* tasteTagMapping = [RKManagedObjectMapping mappingForClass:[TasteTag class]]; 
[tasteTagMapping mapKeyPath:@"id" toAttribute:@"tasteTagID"]; 
[tasteTagMapping mapKeyPath:@"name" toAttribute:@"name"]; 
tasteTagMapping.primaryKeyAttribute = @"tasteTagID"; 
[[RKObjectManager sharedManager].mappingProvider setMapping:tasteTagMapping forKeyPath:@"taste_tags"]; 
[[RKObjectManager sharedManager].mappingProvider addObjectMapping:tasteTagMapping]; 

.. some more mapping .. 

Tôi có dữ liệu quay lại từ máy chủ RoR và nó được ánh xạ tới các đối tượng như mong đợi. Thực thể Core Data cũng dường như ánh xạ tốt sau RestKit được yêu cầu trở lại:

"<TasteTag: 0x6e87170> (entity: TasteTag; id: 0x6e85d60 <x-coredata://03E4A20A-21F2-4A2D-92B4-C4424893D559/TasteTag/p5> ; data: <fault>)" 

Vấn đề là khi tôi cố gắng truy cập vào các thuộc tính trên các đối tượng lỗi dường như không thể được hỏa hoạn. Lúc đầu, tôi chỉ kêu gọi các thuộc tính, mà luôn luôn trở lại như con số không (mặc dù phải kích hoạt lỗi):

for (TasteTag *tag in self.vintage.tasteTags) { 
    [tagNames addObject:tag.name]; //get error of trying to add nil to array 
} 

Sau khi xem xét lỗi bằng tay kích hoạt (http://www.mlsite.net/blog/?p=518) Tôi đã thử gọi [tag willAccessValueForKey:nil] mà kết quả trong:

Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x6e7b060 <x-coredata://03E4A20A-21F2-4A2D-92B4-C4424893D559/TasteTag/p5>'' 

Tra cứu thực thể trong .sqlite dựa trên khóa (TasteTag/p5) hiển thị bản đồ được ánh xạ tới khóa mà tôi mong đợi.

Các bài đăng khác liên quan đến RestKit khuyên bạn nên tắt bộ nhớ cache đối tượng (mà tôi không sử dụng) vì điều này thường do một thực thể bị xóa. Nhưng ở giai đoạn này tôi chỉ đọc, không xóa, và tôi không có bộ nhớ đệm tại chỗ.

Nếu tôi chỉ gọi [TasteTag allObjects] Tôi có thể nhận tất cả các đối tượng trở lại tốt và chúng tải mà không gặp sự cố. Nó chỉ là trong trường hợp khi họ bị lỗi có vẻ như.

+0

Hy vọng bạn tìm được giải pháp, tôi đang gặp phải sự cố gần giống. –

+0

@ryan nếu bạn tìm thấy bất cứ điều gì cho tôi biết, cho đến nay tôi đã không có may mắn – Parrots

+0

@ryan - có vẻ như nó có thể không được RestKit cụ thể. Câu hỏi tiếp theo ở đây: http://stackoverflow.com/questions/8856867/copying-objects-with-core-data-objects-in-them – Parrots

Trả lời

4

Ghi lại bản sửa lỗi của tôi (đọc: hack) theo đề xuất của Ryan.

Lỗi có vẻ như cách RestKit giả sử bạn sẽ sử dụng các đối tượng được trả về từ phương thức objectLoader:didLoadObjects: của chúng. Họ dường như giả định rằng tất cả sẽ được Core Data hỗ trợ (và theo dõi luồng tương tự như những gì Ryan nói đến - để nó đồng bộ với Core Data, sau đó truy vấn lại) hoặc bạn sẽ sử dụng tất cả các đối tượng không được Core Data hỗ trợ và giữ những kết quả đó xung quanh.

Trong trường hợp của tôi, tôi đã có kết hợp - một mảng gốc của các đối tượng không phải là Dữ liệu lõi được sao lưu, mỗi đối tượng này chứa một mảng các thực thể được Sao lưu dữ liệu lõi. Các đối tượng cấp cao nhất là các đối tượng mà tôi không ngại truy vấn máy chủ và không có lý do gì để duy trì cục bộ ngoài chế độ xem mà chúng được hiển thị. Có vẻ như một lần objectLoader:didLoadObjects: hoàn thành bối cảnh đối tượng được quản lý sao lưu các thực thể Core Data trong objects param được xử lý (theo giả định bạn sẽ truy vấn lại cho chúng), gây ra bất kỳ lời gọi nào trong tương lai cho các thực thể để kết quả là lỗi, mặc dù bạn không thể kích hoạt lỗi và tải dữ liệu (kết quả NSObjectInaccessibleException).

Tôi bị xung đột với một bản hack xấu xí - trong phạm vi objectLoader:didLoadObjects: Tôi truy cập vào một trong ngữ cảnh đối tượng được quản lý của thực thể Dữ liệu chính và sao chép nó vào thuộc tính trong chế độ xem (self.context = [tag managedObjectContext];). Điều này ngăn chặn ngữ cảnh được phát hành sau khi hoàn thành objectLoader:didLoadObjects:, cho phép tôi truy cập vào các đối tượng không có vấn đề sau trong chế độ xem.

Một giải pháp khác là phải truy vấn lại theo cách thủ công cho từng pháp nhân sử dụng ngữ cảnh mới và sao chép lại đối tượng trả về được lưu trữ. Người ta có thể làm điều này khi người ta đi để hiển thị chúng, hoặc có thể một số hậu xử lý trong objectLoader:didLoadObjects:, bằng cách sử dụng một bối cảnh mới. ID thực thể vẫn còn xung quanh đối tượng bị lỗi nên người dùng có thể sử dụng nó để truy vấn lại mà không có vấn đề ngay cả sau khi bối cảnh RestKit ban đầu biến mất.Nhưng có vẻ ngớ ngẩn khi phải truy vấn lại cho mọi thực thể trong đồ thị đối tượng như thế.

+0

Bạn có thể tắt tự động đồng bộ hóa và lưu trữ các đối tượng trong mô hình CD theo cách thủ công khi bạn muốn. Nhưng tôi cần một số tài liệu về điều này! Dù sao cũng cảm ơn bạn :) –

10

Tôi đã tìm thấy giải pháp phù hợp với mình (tôi không chắc chắn về mức độ áp dụng cho trường hợp của bạn, nhưng tôi sẽ thêm nó làm câu trả lời vì nó giải quyết vấn đề này (hoặc rất giống) cho tôi):

Một vài ngày trước, tôi chạy ví dụ RKTwitterCoreData và nhận thấy nó hoạt động hoàn hảo trong khi tôi, với mã rất đơn giản tại thời điểm này và làm gần như cùng một điều, không. Tôi nhận được lỗi chưa được thực hiện. Vì vậy, tôi quyết định sửa đổi tất cả các mã của tôi đối phó với RestKit để phản ánh cách ví dụ RKTwitterCoreData làm điều đó.

Tôi sẽ chia thành nhiều phần để thử và giúp bạn theo dõi dòng suy nghĩ của tôi vào thời điểm đó (vì tôi không nghĩ rằng các vấn đề của chúng tôi giống nhau).

Assumption thực hiện ban đầu của tôi

Kể từ RestKit có thể sao lưu các đối tượng Core Data, tôi cho rằng các đối tượng được quản lý có thể được sử dụng thay thế cho nhau. Ví dụ, tôi có thể sử dụng các đối tượng từ Dữ liệu cốt lõi theo cách chính xác giống như các đối tượng được lấy từ một dịch vụ web từ xa. Tôi thậm chí có thể kết hợp chúng với nhau để có được tất cả các dữ liệu.

I Was Wrong

tôi nhận thấy rằng RKTwitterCoreData của mã đã không dòng chảy theo cách này trong ít nhất. Một đoạn mã khá phù hợp với của họ, nhưng sự khác biệt lớn nhất là họ đã không đối xử với các đối tượng này như là hoán đổi cho nhau. Trong thực tế, họ không bao giờ sử dụng các đối tượng họ nhận được từ các cửa hàng dữ liệu từ xa.Thay vào đó, họ chỉ để cho rằng "rơi qua các vết nứt". Tôi chỉ có thể giả định rằng có nghĩa là họ được thêm vào kho dữ liệu của Core Data vì nó hoạt động cho họ và, bây giờ, đối với tôi.

Chi tiết

Ứng dụng của tôi làm việc sau khi sửa đổi mã của tôi để tận dụng luồng này. Tôi chỉ có thể phỏng đoán rằng các lỗi không thể thực hiện mà chúng ta đang thấy có liên quan đến việc sử dụng các đối tượng được Sao lưu dữ liệu lõi mà chúng tôi lấy lại từ dịch vụ web. Nếu thay vào đó bạn chỉ cần bỏ qua những người đó và sau đó làm một lấy, bạn sẽ nhận được tất cả mọi thứ trở lại (bao gồm cả các yêu cầu gần đây nhất) và bạn không nên nhận được bất kỳ lỗi unfulfillable.

Xây dựng, nếu bạn nhìn vào RKTwitterViewController bạn sẽ nhận thấy rằng dòng 45-61 xử lý tải của các đối tượng:

- (void)loadObjectsFromDataStore { 
    [_statuses release]; 
    NSFetchRequest* request = [RKTStatus fetchRequest]; 
    NSSortDescriptor* descriptor = [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO]; 
    [request setSortDescriptors:[NSArray arrayWithObject:descriptor]]; 
    _statuses = [[RKTStatus objectsWithFetchRequest:request] retain]; 
} 

- (void)loadData { 
    // Load the object model via RestKit  
    RKObjectManager* objectManager = [RKObjectManager sharedManager]; 
    [objectManager loadObjectsAtResourcePath:@"/status/user_timeline/RestKit" delegate:self block:^(RKObjectLoader* loader) { 
     // Twitter returns statuses as a naked array in JSON, so we instruct the loader 
     // to user the appropriate object mapping 
     loader.objectMapping = [objectManager.mappingProvider objectMappingForClass:[RKTStatus class]]; 
    }]; 
} 

Tất cả mọi thứ có vẻ bình thường (ít nhất là so với cách tôi đã làm bốc này ban đầu). Nhưng hãy nhìn vào các phương pháp objectLoader:didLoadObjects: đại biểu:

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { 
    [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"LastUpdatedAt"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
    NSLog(@"Loaded statuses: %@", objects); 
    [self loadObjectsFromDataStore]; 
    [_tableView reloadData]; 
} 

Mẫu thậm chí không chạm vào tham số objects! (Bên cạnh những NSLog tất nhiên ...)

Kết luận/tl; dr

Không sử dụng các đối tượng được quản lý bạn sẽ có được trở lại trong objectLoader:didLoadObjects: như thể họ đang ủng hộ hoàn toàn bởi Core Data. Thay vào đó, bỏ qua chúng và tìm nạp lại từ Core Data. Tất cả các đối tượng, bao gồm cả các đối tượng từ yêu cầu cuối cùng đều có. Nếu không, bạn sẽ nhận được lỗi không thể hoàn thành (ít nhất là tôi đã làm).

+0

Tôi đã đến cùng một kết luận trong quá trình gỡ lỗi. Họ dường như giả định rằng bạn sẽ cho phép nó được đồng bộ hóa với đĩa CD và sau đó truy vấn lại. Vấn đề tôi gặp phải là tôi không có kế hoạch để tất cả các đối tượng của mình được CD sao lưu (không quan tâm đến việc lưu trữ chúng sau này - chỉ hiển thị một khung nhìn này). Điều đó buộc tôi phải sử dụng các vật thể được trả về. Tôi đã sửa chữa xong (đọc: hack theo cách xấu xí) bằng cách giữ lại managedContext của NSManagedObject trong viewController. Làm điều đó cho phép tôi truy cập vào các đối tượng tốt trong cellForIndexPath. – Parrots

+0

Nó có thể là giá trị thời gian của bạn để thêm rằng như là một câu trả lời cho bất kỳ du khách không may khác của khía cạnh này của RestKit. Tôi rất ấn tượng với thư viện, nhưng tôi thấy nó khá lạ lùng khi cảnh báo này không được ghi lại tốt hơn. –

+0

Đồng ý về tài liệu. Tôi thực sự có thể sử dụng một số tài liệu cập nhật thay vì các tài liệu cũ hơn. Cảm ơn sự thấu hiểu ở đây. –