主题:核心数据,无法从VC检索/设置为我的属性。最常见的错误?
通过这个网站搜索,但无法完全得到我需要的答案(虽然有很多很好的提示),所以我想我发布这个问题,希望它能解决我几周来的问题!是的,非常令人沮丧,你可能知道这种感觉!所以任何帮助都会很棒 - 谢谢! :-)
卵景:
iOS 5.1 项目。让核心数据正常工作(在 main.h/NSLog 中测试),但我在从其他视图控制器检索和设置实体属性(数据)时遇到问题。Xcode 从其他视图控制器识别我在 AppDelegate 中找到的单行"AppContent",但不能识别实体名称及其属性。
关于这一点最常见的错误是什么?
我有一种感觉,我只是错过了在正确的位置导入一些文件等......
更多细节;
仅供参考:我正在尝试使用 Matt Campell 推荐的方法,该方法在 AppDelegate 中创建一个单一实例,可以在整个应用程序中使用,以使用来自任何视图控制器的 managedObjectContext,并检索数据并将其保存到核心数据及其实体及其各自的属性。这是通过将以下两个文件导入应用程序来完成的;
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模型编辑器创建);
比赛.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
比赛.m
#import "Contest.h"
#import "Player.h"
@implementation Contest
@dynamic name;
@dynamic players;
@end
玩家.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
玩家.m
#import "Player.h"
#import "Contest.h"
@implementation Player
@dynamic name;
@dynamic contests;
@end
这是一个视图控制器
试图在此处获取核心数据实体及其属性,但 Xcode 看到了 appContent 但无法识别它,并且在构建时出现错误"找不到属性播放器"......
比赛玩家VC.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
contestPlayerVC.m不显示孔文件,因为问题出在方法视图中DidLoad...
#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);
}
...
有什么提示或建议吗?谢谢! :-)
顺便说一句:很抱歉这篇文章很长,我不确定如何很好地描述我的问题,让任何人都能理解它。如果你读了所有内容 - 我印象深刻,如果你帮我解决这个问题,我会很高兴。可能是我完全错过的一些基本的东西。谢谢的;-)
@user1578933 好的,让我们备份一下,想想每个部分负责什么:
- 比赛
- 是负责与比赛相关的所有内容的根(第一个)对象,包括玩家的姓名和名单 玩家
- 对玩家的一切负责,包括玩家的名字
- AppContent 负责管理对象图(检索对象图以便您可以使用它并记住用户添加和删除的内容)
- contestPlayerVC负责呈现内容(来自AppContent)
在您的应用中,一切都从竞赛开始。 在您的 AppContent 实现中,您有生成该属性 rootObject 的代码,这是首次创建 Contest 对象的位置。
注意:您将其定义为id,因为您将此代码直接复制到我们的程序中,但是您也可以将rootObject定义为类型Contest,如下所示:
-(Contest *) rootObject;
这是您进入对象图的入口点。 这个想法是,您将访问 AppContent(使用单例模式),然后检索 Contest 对象。 比赛对象将具有 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];
}
这实质上就是将此内容添加到视图控制器的方式;对于表视图控制器,您将使用索引路径行属性来找出哪个播放器进入哪个表视图单元格(请参阅 cellForRowAtIndexPath)。
@user1578933 - 在阅读了这篇文章以及您在移动应用程序掌握研究所上留下的帖子后,您似乎缺少对对象图以及所有这些对象关系的一般组织方式的一些理解。 我最近在这里添加了一些关于如何使用和思考Objective-C对象图的其他内容。 另外,我会再次仔细查看有关Objective-C,表视图和核心数据的部分。
您的错误,无法在self.content
上找到player
属性,是因为您的 AppContent 类没有声明该名称的任何属性。让我们一次浏览一行代码:
self.content = [AppContent sharedContent];
现在self.content
是 AppContent 类型的对象,因此以后对 self.content.something
的任何调用都将查找在该类上声明的可见方法或属性(通常在"AppContent.h"中)。
self.playerNameField.text = self.content.player.name;
我们在这里查找 AppContent 对象中名为 player
的属性,该属性的标头如下:
#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
其中没有一个名为 player
的@property
- 您有一个 rootObject
属性,并且您导入了"Player.h"标头,但您从未声明您尝试访问的属性。您需要添加如下行:
@property(strong) Player * player;
并将其@synthesize
在"AppContent.m"文件中,或提供适当的访问器方法来支持该属性。