1

件名:コアデータ、VCからプロパティを取得/設定できません。最も一般的な間違い?

このサイトを検索しましたが、必要な回答を得ることができませんでした(ただし、多くの良いヒントがあります)。この質問を投稿して、数週間前から抱えていた問題が解決することを願っています。はい、非常にイライラします、あなたはおそらくその気持ちを知っています!だからどんな助けも素晴らしいでしょう-ありがとう!:-)

Oveview:

iOS5.1プロジェクト。Core Dataが機能するようになりました(main.h/NSLogでテスト済み)が、他のView Controllerからエンティティプロパティ(データ)を取得および設定するのに問題があります。Xcodeは、AppDelegateで見つかった単一の「AppContent」を他のView Controllerから認識しますが、エンティティ名とそのプロパティは認識しません。

これに関して最も一般的な間違いは何ですか?

正しい場所にファイルをインポートするのを忘れたような気がします...

いくつかの詳細;

参考:Matt Campellが推奨する方法を使用しようとしています。この方法では、AppDelegateにシングルトンを作成し、アプリ全体で使用して、任意のView ControllerからmanagedObjectContextを操作し、データを取得してCoreDataに保存できます。エンティティとそのそれぞれのプロパティ。これは、次の2つのファイルをアプリにインポートすることで実行されます。

appContent.h

#import <Foundation/Foundation.h>
#import "Contest.h"  // Root Entity in CD model
#import "Player.h"

@interface AppContent : NSObject

+(AppContent *)sharedContent;

@property(strong, readonly) id rootObject;

-(void)save;
-(void)rollback;

@end

appContent.m

#import "AppContent.h"
#import <CoreData/CoreData.h>

@interface AppContent()

-(NSURL *)dataStoreURL;
@property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext;

@end

@implementation AppContent
NSManagedObjectModel *_managedObjectModel;
NSPersistentStoreCoordinator *_persistentStoreCoordinator;
NSManagedObjectContext *_managedObjectContext;
id _rootObject;

static AppContent *singletonInstance = nil;

+ (AppContent *)sharedContent{
    @synchronized(self){
        if (singletonInstance == nil)
            singletonInstance = [[self alloc] init];

        return(singletonInstance);
    }
}


- (NSURL *)dataStoreURL {

    NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

    return [NSURL fileURLWithPath:[docDir stringByAppendingPathComponent:@"DataStore.sql"]];
}

- (NSManagedObjectModel *)managedObjectModel {
    if (_managedObjectModel) {
        return _managedObjectModel;
    }
    _managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];    
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                               configuration:nil
                                                         URL:[self dataStoreURL]
                                                     options:nil
                                                       error:&error]) {
        NSLog(@"Unresolved Core Data error with persistentStoreCoordinator: %@, %@", error, [error userInfo]);
    }    

    return _persistentStoreCoordinator;
}

- (NSManagedObjectContext *)managedObjectContext {
    if (_managedObjectContext) {
        return _managedObjectContext;
    }

    if ([self persistentStoreCoordinator]) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
    }

    return _managedObjectContext;
}

-(id)rootObject{
    if(_rootObject)
        return _rootObject;

// #warning Replace [CHANGE] with your root object entity name
    NSString *entityName = @"Contest";
    NSManagedObjectContext *context = [self managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
                                          inManagedObjectContext:context];
    request.entity = entity;
    NSArray *listOfObjects = [context executeFetchRequest:request
                                                error:nil];
    if([listOfObjects count] == 1){
        _rootObject = [listOfObjects lastObject];
        return _rootObject;
    }
    _rootObject = [NSEntityDescription insertNewObjectForEntityForName:entityName
                                            inManagedObjectContext:context];

    // Adding some testdata (only first time...)
    // Contest
    Contest *c = _rootObject;
    c.name = @"Big Game 1";

    // Players
    Player *p1 = (Player *) [NSEntityDescription insertNewObjectForEntityForName:@"Player"
                                                          inManagedObjectContext:context];
    p1.name = @"Player One";
    [c addPlayersObject:p1];

    Player *p2 = (Player *) [NSEntityDescription insertNewObjectForEntityForName:@"Player"
                                                              inManagedObjectContext:context];
    p2.name = @"Player Two";
    [c addPlayersObject:p2];

    [self save];

    return _rootObject;
}

-(void)save{
    NSError *error = nil;
    NSManagedObjectContext *context = [self managedObjectContext];
    if([context hasChanges])
        [context save:&error];
    if(error)
        NSLog(@"Warning: Error saving to data store.  %@", error);
}

-(void)rollback{
    NSManagedObjectContext *context = [self managedObjectContext];
    if([context hasChanges])
        [context rollback];
}

@end

モデルファイル(CDモデルエディタで作成)は次のとおりです。

Contest.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Player;

@interface Contest : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSSet *players;
@end

@interface Contest (CoreDataGeneratedAccessors)

- (void)addPlayersObject:(Player *)value;
- (void)removePlayersObject:(Player *)value;
- (void)addPlayers:(NSSet *)values;
- (void)removePlayers:(NSSet *)values;

@end

Contest.m

#import "Contest.h"
#import "Player.h"

@implementation Contest

@dynamic name;
@dynamic players;

@end

Player.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Contest;

@interface Player : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) Contest *contests;

@end

Player.m

#import "Player.h"
#import "Contest.h"


@implementation Player

@dynamic name;
@dynamic contests;

@end

これがビューコントローラです

ここでコアデータエンティティとそのプロパティを取得しようとしていますが、XcodeはappContentを参照していますが、それを認識せず、ビルド時に「プロパティプレーヤーが見つかりません」というエラーが表示されます...

コンテストPlayerVC.h

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import "AppContent.h"


@interface contestPlayerVC : UIViewController

@property (strong, nonatomic) IBOutlet UITextField *playerNameField;
@property (strong, nonatomic) IBOutlet UITextField *playerMailField;
@property (strong, nonatomic) IBOutlet UIButton *playerSaveButton;

@property (weak, nonatomic) AppContent *content;

// Test
// @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;


- (IBAction)playerChooseImage:(UIButton *)sender;

- (IBAction)dismissModal:(UIButton *)sender;

- (IBAction)hideKeyboard:(id)sender;

- (IBAction)playerSave:(UIButton *)sender;

@end

コンテストPlayerVC.m 問題がメソッドviewDidLoadにあるため、ホールファイルが表示されません...

#import "contestPlayerVC.h"

@interface contestPlayerVC ()

@end

@implementation contestPlayerVC
@synthesize playerNameField, playerMailField, playerSaveButton, content;

- (void)viewDidLoad {

    [super viewDidLoad];
    // Do any additional setup after loading the view.

    // Call 1 - seems to work ok
    self.content = [AppContent sharedContent];

////// Call 2 - gives error, can't find property "player" - WHY?
    // Trying to set textfield to CD Entity "Player" and it's property "name"
    self.playerNameField.text = self.content.player.name;

    NSLog(@"Player is: %@", self.content.player.name);

    // Call 3 - works ok
    NSLog(@"Content is: %@", self.content.description);

}
...

ヒントや提案はありますか?ありがとう!:-)

ところで:長い投稿について申し訳ありませんが、他の人がそれを理解するのに十分なほど私の問題を説明する方法についてはわかりません。あなたがそれをすべて読んだら-私は感銘を受けました、そしてあなたが私がこれを解決するのを手伝ってくれるなら私は本当に幸せです。おそらく私が完全に見逃したいくつかの基本的なこと。ありがとう ;-)

4

2 に答える 2

2

playerでプロパティを見つけることができないというエラーはself.content、AppContentクラスがその名前のプロパティを宣言していないためです。コードを一度に1行ずつ見ていきましょう。

self.content = [AppContent sharedContent];

Nowself.contentはAppContent型のオブジェクトであるため、今後の呼び出しでself.content.somethingは、そのクラス(通常は「AppContent.h」)で宣言された表示可能なメソッドまたはプロパティが検索されます。

self.playerNameField.text = self.content.player.name;

ここではplayer、AppContentオブジェクトで名前が付けられたプロパティを探しています。このプロパティのヘッダーは次のとおりです。

#import <Foundation/Foundation.h>
#import "Contest.h"  // Root Entity in CD model
#import "Player.h"

@interface AppContent : NSObject

+(AppContent *)sharedContent;

@property(strong, readonly) id rootObject;

-(void)save;
-(void)rollback;

@end

@property名前付きの場所はどこにもありplayerません。rootObjectプロパティがあり、「Player.h」ヘッダーをインポートしますが、アクセスしようとしているプロパティを宣言することはありません。次のような行を追加する必要があります。

@property(strong) Player * player;

@synthesize「AppContent.m」ファイルに含めるか、そのプロパティをバックアップするための適切なアクセサメソッドを提供します。

于 2012-08-07T16:38:49.373 に答える
2

@ user1578933わかりました。少しバックアップして、各部分の原因について考えてみましょう。

  • コンテストは、プレイヤーの名前やリストなど、コンテストに関連するすべての責任を負うルート(最初の)オブジェクトです。
  • プレイヤーは、プレイヤーの名前を含むプレイヤーに関するすべての責任を負います
  • AppContentは、オブジェクトグラフの管理を担当します(オブジェクトグラフを取得して使用できるようにし、ユーザーが追加および削除したものを記憶します)。
  • ConcertPlayerVCは、(AppContentからの)コンテンツの提示を担当します。

アプリでは、すべてがコンテストで始まります。AppContentの実装には、そのプロパティrootObjectを生成するコードがありこれがContestオブジェクトが初めて作成される場所です。

このコードをプログラムに直接コピーしているため、 idとして定義されていますが、 rootObjectを次のようにタイプContestとして定義することもできます。

-(Contest *) rootObject;

これは、オブジェクトグラフへのエントリポイントです。(シングルトンパターンを使用して)AppContentにアクセスしてから、コンテストオブジェクトを取得するという考え方です。コンテストオブジェクトには、コレクション内の各プレーヤーへの参照を含むNSSetオブジェクトコレクションが含まれます。

ビューコントローラでこれを使用する方法の例を次に示します。

- (void)viewDidLoad {
    [super viewDidLoad];

    self.content = [AppContent sharedContent];

    //get reference to the root object contest
    Contest *theContest = (Contest *)self.content.rootObject;

    //get an array based reference to the players in theContest
    NSArray *players = [theContest.players allObjects];

    //Example of getting a reference to an individual player:
    Player *p1 = [players objectAtIndex:0];

}

これは基本的に、このコンテンツをViewControllerに追加する方法です。テーブルビューコントローラーの場合、インデックスパスの行プロパティを使用して、どのプレーヤーがどのテーブルビューセルに入るのかを調べます(cellForRowAtIndexPathを参照)。

@ user1578933-この投稿と、Mobile App Mastery Instituteに残した投稿を読んだ後、オブジェクトグラフと、これらすべてのオブジェクトの関係が一般的にどのように編成されているかについての理解が不足しているようです。最近、 Objective-Cオブジェクトグラフの使用方法と考え方に関するコンテンツをここに追加しました。また、Objective-C、テーブルビュー、コアデータのセクションをもう一度注意深く調べます。

于 2012-08-16T13:35:16.700 に答える