7

私はCore DataデータベースとRuby on Railsサーバーを持つiOSクライアントを含むディプロマプロジェクトに取り組んでいます。私は彼らの間の通信のためにRestKitを使用しています。現在、私は、全体のシステムが動作するようになって大きな問題を抱えている:私は、サーバーからオブジェクトへの応答をマップしようとして、私は次の例外取得:RKResponseMapperOperationでNSManagedObjectContextがnilであるためRestKitがクラッシュする

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 

を私がロードしようとしていますサーバーからの連絡先のリスト(配列)。これは、コアデータに「ユーザー」として保存する必要があります。

私はこのビデオで見たように、データモデルクラスに私のすべてのコアデータコードを構成しました:http://nsscreencast.com/episodes/11-core-data-basics。ここでは、次のとおりです。

ヘッダファイル:

#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 

実装ファイル:

#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 

UserクラスのXcodeで自動生成された、非常に簡単です。

ヘッダファイル:

#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 

実装ファイル:

#import "User.h" 

@implementation User 

@dynamic email; 
@dynamic firstName; 
@dynamic lastName; 
@dynamic userID; 

@end 

だけで、データ・モデル・クラスのように、私は私が通信に使用サーバ・マネージャクラスあります

ヘッダーをファイル:

#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 

と実装ファイル:

#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 

私がフェッチ結果コントローラを使用するように正しく設定されている連絡先のテーブルビューを開くときに(DBのうち、正常引っ張っエンティティ)、私は危険なリフレッシュを持っていますあなただけの上で読んだメソッドを呼び出しボタン、:ここで

- (void)downloadContacts { 
    [[AppServer sharedInstance] getContactsForCurrentUser]; 
} 

応答のフォーマットです:

[ 
    { 
     "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" 
} 
] 

そして例外コンソールの前に、次の状態:

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 

全体の例外がスローされる前に、失敗したRestKitライブラリの行は、されています

NSAssert(self.managedObjectContext, @"Unable to perform mapping: No `managedObjectContext` assigned. (Mapping response.URL = %@)", self.response.URL); 

私はそれをAppServerのinitServerメソッドに戻しました。m個のファイル、その、方法が戻る前に、RKObjectManagerクラスプロパティは、このようなものです:私は、デバッグしているように、私は、問題はサーバ側または通信のではないことをトレースしてきましたhttp://imgur.com/LM5ZU9m

アプリケーション - JSONが受信され、配列にデシリアライズされたことがわかりますが、それがコアデータに保存されるはずの次のメソッドに渡された瞬間、管理されたオブジェクトコンテキストのNSAssertのためにアプリケーション全体がkaboomになります。

ご協力いただきありがとうございます。

答えて

4

数日のデバッグ後、私は最終的に何が問題になったのかを知りました。ローカルの永続ストアへのパスを設定し、管理オブジェクトストアの管理対象オブジェクトコンテキストを生成する必要がありました。 https://github.com/RestKit/RestKit/issues/1221#issuecomment-13327693

私はちょうど私のサーバーのinitメソッドで数行追加しました:アプリケーションを取得するには、この機能RKApplicationDataDirectory()を使用して

NSError *error = nil; 
NSString *pathToPSC = [[AppDataModel sharedDataModel] pathToLocalStore]; 

_objectManager.managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[[AppDataModel sharedDataModel] managedObjectModel]]; 
[_objectManager.managedObjectStore addSQLitePersistentStoreAtPath:pathToPSC fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; 

if (error != nil) { 
    NSLog(@"\nSerious object store error!\n"); 
    return; 
} else { 
    [_objectManager.managedObjectStore createManagedObjectContexts]; 
} 
2

私はそれを行うために管理し、私は解決策を見つけたのはここ

ですデータベースパスを設定します。

// Initialize HTTPClient 
NSURL *baseURL = [NSURL URLWithString:@"http://myapiaddress.com"]; 
AFHTTPClient* client = [[AFHTTPClient alloc] initWithBaseURL:baseURL]; 
//we want to work with JSON-Data 
[client setDefaultHeader:@"Accept" value:RKMIMETypeJSON]; 

// Initialize RestKit 
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client]; 
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"NameOfMyCoreDataModel" ofType:@"momd"]]; 

//Iniitalize CoreData with RestKit 
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy]; 
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; 
NSError *error = nil; 

NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"nameOfDB.sqlite"]; 

objectManager.managedObjectStore = managedObjectStore; 

[objectManager.managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; 

[objectManager.managedObjectStore createManagedObjectContexts]; 
関連する問題