Tôi đang làm việc trên dự án bằng tốt nghiệp, bao gồm một khách hàng iOS với cơ sở dữ liệu Core Data và máy chủ Ruby on Rails. Tôi đang sử dụng RestKit để giao tiếp giữa chúng. Hiện nay tôi đang gặp một vấn đề lớn nhận được toàn bộ hệ thống để làm việc: khi tôi cố gắng để ánh xạ một phản ứng với các đối tượng từ các máy chủ, tôi nhận được ngoại lệ sau:RestKit bị treo vì NSManagedObjectContext là không trong RKResponseMapperOperation
2013-02-08 22:40:43.947 App[66735:5903] *** Assertion failure in -[RKManagedObjectResponseMapperOperation performMappingWithObject:error:], ~/Repositories/App/RestKit/Code/Network/RKResponseMapperOperation.m:358
2013-02-08 23:04:30.562 App[66735:5903] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unable to perform mapping: No `managedObjectContext` assigned. (Mapping response.URL = http://localhost:3000/contacts?auth_token=s78UFMq8mCQrr12GZcyx)'
*** First throw call stack:
(0x1de9012 0x1c0ee7e 0x1de8e78 0x16a4f35 0x8f56e 0x8d520 0x1647d23 0x1647a34 0x16d4301 0x23a253f 0x23b4014 0x23a52e8 0x23a5450 0x90ac6e12 0x90aaecca)
libc++abi.dylib: terminate called throwing an exception
Tôi đang cố gắng để tải một danh sách (một mảng) các địa chỉ liên hệ từ máy chủ, sẽ được lưu dưới dạng "Người dùng" trong Dữ liệu chính.
Tôi đã cấu trúc tất cả mã Dữ liệu cốt lõi của mình trong một lớp Lớp mô hình dữ liệu, như tôi đã thấy trong video này: http://nsscreencast.com/episodes/11-core-data-basics. Ở đây là:
header file:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface AppDataModel : NSObject
+ (id)sharedDataModel;
@property (nonatomic, readonly) NSManagedObjectContext *mainContext;
@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSString *)modelName;
- (NSString *)pathToModel;
- (NSString *)storeFilename;
- (NSString *)pathToLocalStore;
@end
tập tin thực hiện:
#import "AppDataModel.h"
@interface AppDataModel()
- (NSString *)documentsDirectory;
@end
@implementation AppDataModel
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
@synthesize mainContext = _mainContext;
+ (id)sharedDataModel {
static AppDataModel *__instance = nil;
if (__instance == nil) {
__instance = [[AppDataModel alloc] init];
}
return __instance;
}
- (NSString *)modelName {
return @"AppModels";
}
- (NSString *)pathToModel {
return [[NSBundle mainBundle] pathForResource:[self modelName]
ofType:@"momd"];
}
- (NSString *)storeFilename {
return [[self modelName] stringByAppendingPathExtension:@"sqlite"];
}
- (NSString *)pathToLocalStore {
return [[self documentsDirectory] stringByAppendingPathComponent:[self storeFilename]];
}
- (NSString *)documentsDirectory {
NSString *documentsDirectory = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
return documentsDirectory;
}
- (NSManagedObjectContext *)mainContext {
if (_mainContext == nil) {
_mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
_mainContext.persistentStoreCoordinator = [self persistentStoreCoordinator];
}
return _mainContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel == nil) {
NSURL *storeURL = [NSURL fileURLWithPath:[self pathToModel]];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:storeURL];
}
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator == nil) {
NSLog(@"SQLITE STORE PATH: %@", [self pathToLocalStore]);
NSURL *storeURL = [NSURL fileURLWithPath:[self pathToLocalStore]];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *e = nil;
if (![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&e]) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:e forKey:NSUnderlyingErrorKey];
NSString *reason = @"Could not create persistent store.";
NSException *exc = [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:userInfo];
@throw exc;
}
_persistentStoreCoordinator = psc;
}
return _persistentStoreCoordinator;
}
@end
Các tài lớp là khá đơn giản, tự động tạo ra với Xcode.
tập tin tiêu đề: tập tin
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface User : NSManagedObject
@property (nonatomic, retain) NSString * email;
@property (nonatomic, retain) NSString * firstName;
@property (nonatomic, retain) NSString * lastName;
@property (nonatomic, retain) NSNumber * userID;
@end
Thực hiện:
#import "User.h"
@implementation User
@dynamic email;
@dynamic firstName;
@dynamic lastName;
@dynamic userID;
@end
Cũng giống như các lớp mô hình dữ liệu, tôi có một máy chủ quản lý lớp mà tôi sử dụng để liên lạc:
Tiêu đề file:
#import <Foundation/Foundation.h>
#import <RestKit/RestKit.h>
#import "AppServerProtocol.h"
#import "AppDataModel.h"
@interface AppServer : NSObject <AppServerDelegate>
+ (id)sharedInstance;
@property (strong, nonatomic) RKObjectManager *objectManager;
@property (strong, nonatomic) RKEntityMapping *userMapping;
@end
Và thực hiện file:
#import "AppServer.h"
#import "User.h"
#import "Device.h"
#import "Ping.h"
#import "AppAppDelegate.h"
@interface AppServer()
@property BOOL initialized;
@end
@implementation AppServer
+ (id)sharedInstance {
static AppServer *__instance = nil;
if (__instance == nil) {
__instance = [[AppServer alloc] init];
__instance.initialized = NO;
}
if (![__instance initialized]) {
[__instance initServer];
}
return __instance;
}
- (void)initServer {
// initialize RestKit
NSURL *baseURL = [NSURL URLWithString:@"http://localhost:3000"];
_objectManager = [RKObjectManager managerWithBaseURL:baseURL];
// enable activity indicator spinner
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
// initialize managed object store
_objectManager.managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[[AppDataModel sharedDataModel] managedObjectModel]];
_userMapping = [RKEntityMapping mappingForEntityForName:@"User" inManagedObjectStore:_objectManager.managedObjectStore];
[_userMapping addAttributeMappingsFromDictionary:@{
@"email" : @"email",
@"firstName" : @"first_name",
@"lastName" : @"last_name"
}];
[_userMapping setIdentificationAttributes: @[@"userID"]];
RKResponseDescriptor *contactsResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:_userMapping pathPattern:@"/contacts" keyPath:nil statusCodes:nil];
[_objectManager addResponseDescriptor:contactsResponseDescriptor];
_initialized = YES;
}
// contacts
- (void)getContactsForCurrentUser {
NSString *authToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppAuthenticationToken"];
[_objectManager getObjectsAtPath:@"/contacts" parameters:@{@"auth_token": authToken} success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(@"Load collection of contacts: %@", mappingResult.array);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(@"Operation failed with error: %@", error);
}];
}
@end
Vì vậy, khi Tôi mở Danh bạ Bảng View, mà được thiết lập một cách chính xác để sử dụng một kết quả lấy điều khiển (thành công kéo các đối tượng ra khỏi DB), tôi có một làm mới nguy hiểm nút, trong đó kêu gọi phương pháp bạn vừa đọc ở trên:
- (void)downloadContacts {
[[AppServer sharedInstance] getContactsForCurrentUser];
}
Dưới đây là định dạng của phản ứng:
[
{
"created_at":"2013-01-11T14:03:57Z",
"email":"[email protected]",
"first_name":"John",
"id":2,
"last_name":"Doe",
"updated_at":"2013-02-07T10:57:16Z"
},
{
"created_at":"2013-01-11T14:03:57Z",
"email":"[email protected]",
"first_name":"Jane",
"id":3,
"last_name":"Doe",
"updated_at":"2013-02-07T10:57:16Z"
}
]
Và trước khi trừ console tiểu bang sau đây:
2013-02-08 22:40:36.892 App[66735:c07] I restkit:RKLog.m:34 RestKit logging initialized...
2013-02-08 22:40:36.994 App[66735:c07] SQLITE STORE PATH: ~/Library/Application Support/iPhone Simulator/6.0/Applications/D735548F-DF42-4E13-A7EF-53DF0C5D8F3B/Documents/AppModels.sqlite
2013-02-08 22:40:37.001 App[66735:c07] Context is ready!
2013-02-08 22:40:43.920 App[66735:c07] I restkit.network:RKHTTPRequestOperation.m:154 GET 'http://localhost:3000/contacts?auth_token=s78UFMq8mCQrr12GZcyx'
2013-02-08 22:40:43.945 App[66735:c07] I restkit.network:RKHTTPRequestOperation.m:181
Dòng của thư viện RestKit, thất bại trước khi toàn bộ ngoại lệ được ném là:
NSAssert(self.managedObjectContext, @"Unable to perform mapping: No `managedObjectContext` assigned. (Mapping response.URL = %@)", self.response.URL);
Tôi đã theo đó trở lại phương pháp initServer trong AppServer.m tập tin, trong đó, trước khi trở về phương pháp, các thuộc tính của lớp RKObjectManager là như thế này: http://imgur.com/LM5ZU9m
Như tôi đã sửa lỗi, tôi đã truy rằng vấn đề không phải là với phía máy chủ hoặc các thông tin liên lạc của ứng dụng - tôi có thể thấy JSON đã nhận và deserialized thành một mảng, nhưng thời điểm nó được chuyển đến phương thức tiếp theo được cho là lưu nó vào Core Data, toàn bộ ứng dụng đi kaboom vì NSAssert của bối cảnh đối tượng được quản lý.
Bất kỳ trợ giúp nào được đánh giá cao!