核心数据一对多关系和表视图

iam*_*isg 1 core-data objective-c ios

好吧,我已经在这个问题上打了一段时间,现在已经过了一个星期,我只是不知道自己哪里出错了.非常感谢您的帮助!!

这是应用程序的想法.我有两个以核心数据为模型的实体.大亨实体与Speech有一对多的关系,因此每个大亨都能够有多个演讲.在Tycoon实体中,这种关系的标题是"TycoonToSpeech",而在言语实体中,与Tycoon的关系标题为"SpeechToTycoon"(这不是一对多的关系).

问题1:我认为我已经在appdelegate.m文件中正确创建了我的关系,但我不确定.以下是我的appdelegate中用于生成内容的代码.我应该用NSMutableSets做更多的事吗???

NSManagedObjectContext *context = [self managedObjectContext];


NSEntityDescription *tycoonEntity = [NSEntityDescription entityForName:@"Tycoon" inManagedObjectContext:context];

NSManagedObject *steve = [NSEntityDescription insertNewObjectForEntityForName:[tycoonEntity name] inManagedObjectContext:context];

[steve setValue:@"Steve Jobs" forKey:@"Name"];
int orgId = [steve hash];
[steve setValue:[NSNumber numberWithInt:orgId] forKey:@"Id"];

NSManagedObject *warren = [NSEntityDescription insertNewObjectForEntityForName:[tycoonEntity name] inManagedObjectContext:context];
[warren setValue:@"Warren Buffet" forKey:@"Name"];
int orgId2 = [warren hash];
[warren setValue:[NSNumber numberWithInt:orgId2] forKey:@"Id"];


NSEntityDescription *speechEntity = [NSEntityDescription entityForName:@"Speech" inManagedObjectContext:context];
NSManagedObject *stanford = [NSEntityDescription insertNewObjectForEntityForName:[speechEntity name] inManagedObjectContext:context];
[stanford setValue:[NSNumber numberWithInt:[stanford hash]] forKey:@"speechId"];
[stanford setValue:@"Stanford" forKey:@"speechName"];

NSManagedObject *wwdc = [NSEntityDescription insertNewObjectForEntityForName:[speechEntity name] inManagedObjectContext:context];
[wwdc setValue:[NSNumber numberWithInt:[wwdc hash]] forKey:@"speechId"];
[wwdc setValue:@"WWDC" forKey:@"speechName"];

NSManagedObject *shareHolder = [NSEntityDescription insertNewObjectForEntityForName:[speechEntity name] inManagedObjectContext:context];
[shareHolder setValue:[NSNumber numberWithInt:[shareHolder hash]] forKey:@"speechId"];
[shareHolder setValue:@"Shareholder's Meeting" forKey:@"speechName"];

NSManagedObject *columbia = [NSEntityDescription insertNewObjectForEntityForName:[speechEntity name] inManagedObjectContext:context];
[columbia setValue:[NSNumber numberWithInt:[columbia hash]] forKey:@"speechId"];
[columbia setValue:@"Columbia" forKey:@"speechName"];


NSMutableSet *jobsSpeeches = [steve mutableSetValueForKey:@"TycoonToSpeech"];
[jobsSpeeches addObject:stanford];
[jobsSpeeches addObject:wwdc];


NSMutableSet *warrenSpeeches = [warren mutableSetValueForKey:@"TycoonToSpeech"];
[warrenSpeeches addObject:shareHolder];
[warrenSpeeches addObject:columbia];
Run Code Online (Sandbox Code Playgroud)

问题2:主要且非常烦人的问题,我不知道如何在我的根视图控制器中使用didSelectRowAtIndexPath工作,这样当我在表格视图中点击"史蒂夫·乔布斯"时,它只显示他的演讲,当我点击在沃伦自助餐上,它只会提出他的演讲.为了做到这一点,我把头撞在了墙上.目前,当我点击史蒂夫乔布斯或沃伦巴菲特时,它会带我到一个新的桌面视图,显示'史蒂夫乔布斯'和'沃伦巴菲特',所以基本上与原始的表视图完全相同!这是我的didSelectRowAtIndexPath代码.

    // Create a new table view of this very same class.
    RootViewController *rootViewController = [[RootViewController alloc]
                                              initWithStyle:UITableViewStylePlain];

    // Pass the managed object context
    rootViewController.context = self.context;
    NSPredicate *predicate = nil;
    // Get the object the user selected from the array
    NSManagedObject *selectedObject = [entityArray objectAtIndex:indexPath.row];


    rootViewController.entityName = @"Speeches";

    // Create a query predicate to find all child objects of the selected object. 
    predicate = [NSPredicate predicateWithFormat:@"SpeechToTycoon == %@", selectedObject];


    [rootViewController setEntitySearchPredicate:predicate];

    //Push the new table view on the stack
    [self.navigationController pushViewController:rootViewController animated:YES];
    [rootViewController release];
Run Code Online (Sandbox Code Playgroud)

这里新编辑**

好的,这是我的SpeechViewController.m文件中的主要代码.numberOfRowsInSection方法似乎正在工作,但真正的问题是cellForRowAtIndexPath是问题所在.我知道我可能做的事非常愚蠢,但我不知道它是什么.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSArray *speeches = (NSArray *)tycoon.TycoonToSpeech;
// Configure the cell...
cell.textLabel.text = [[speeches objectAtIndex:indexPath.row] retain];
return cell;
Run Code Online (Sandbox Code Playgroud)

}

新的语音视图控制器到语言点视图控制器

我在app委托中添加了这个,以便将对象添加到我的语言点实体.

NSEntityDescription *langPointEntity = [NSEntityDescription entityForName:@"LanguagePoints" inManagedObjectContext:context];

NSManagedObject *pointOne = [NSEntityDescription insertNewObjectForEntityForName:[langPointEntity name] inManagedObjectContext:context];
[pointOne setValue:[NSNumber numberWithInt:[pointOne hash]] forKey:@"LangId"];
[pointOne setValue:@"Drop out" forKey:@"LangPoint"];
[pointOne setValue:stanford forKey:@"LanguagePointsToSpeech"];
Run Code Online (Sandbox Code Playgroud)

然后在我的speechViewController.m文件中创建了一个名为speechInfo的NSArray,然后这是我的didSelectRowAtIndexPath方法.

LangPointsViewController *langPointsView = [[LangPointsViewController alloc] initWithNibName:@"LangPointsViewController" bundle:[NSBundle mainBundle]];
Speech *speech = [speechInfo objectAtIndex:indexPath.row];
langPointsView.speech = speech;
[self.navigationController pushViewController:langPointsView animated:YES];
[langPointsView release];
Run Code Online (Sandbox Code Playgroud)

我认为这是出错的地方,我不认为我正确地得到了这个对象,因为我在LangPointsViewController上的speech.Name上做了一个NSLog,它出现了null,好像我为大亨做了一个NSLog. SpeechViewController中的名称会打印我单击的人名.NSArray是不正确的吗?

Mar*_*rra 9

问题#1

首先你的关系名称不好.它们应该以小写字母开头,它们应该简单地描述关系另一方面的内容.你已经知道你在哪里.所以,他们的名字tycoonspeeches分别.其次,由于关系是双向的,您可以更轻松地构建数据,请参阅以下内容:

NSManagedObjectContext *context = [self managedObjectContext];

NSManagedObject *steve = [NSEntityDescription insertNewObjectForEntityForName:@"Tycoon" inManagedObjectContext:context];

[steve setValue:@"Steve Jobs" forKey:@"Name"];
int orgId = [steve hash];
[steve setValue:[NSNumber numberWithInt:orgId] forKey:@"Id"];

NSManagedObject *warren = [NSEntityDescription insertNewObjectForEntityForName:[tycoonEntity name] inManagedObjectContext:context];
[warren setValue:@"Warren Buffet" forKey:@"Name"];
int orgId2 = [warren hash];
[warren setValue:[NSNumber numberWithInt:orgId2] forKey:@"Id"];

NSManagedObject *stanford = [NSEntityDescription insertNewObjectForEntityForName:@"Speech" inManagedObjectContext:context];
[stanford setValue:[NSNumber numberWithInt:[stanford hash]] forKey:@"speechId"];
[stanford setValue:@"Stanford" forKey:@"speechName"];
[stanford setValue:warren forKey:@"tycoon"];

NSManagedObject *wwdc = [NSEntityDescription insertNewObjectForEntityForName:[speechEntity name] inManagedObjectContext:context];
[wwdc setValue:[NSNumber numberWithInt:[wwdc hash]] forKey:@"speechId"];
[wwdc setValue:@"WWDC" forKey:@"speechName"];
[wwdc setValue:warren forKey:@"tycoon"];

NSManagedObject *shareHolder = [NSEntityDescription insertNewObjectForEntityForName:[speechEntity name] inManagedObjectContext:context];
[shareHolder setValue:[NSNumber numberWithInt:[shareHolder hash]] forKey:@"speechId"];
[shareHolder setValue:@"Shareholder's Meeting" forKey:@"speechName"];
[shareHolder setValue:warren forKey:@"tycoon"];

NSManagedObject *columbia = [NSEntityDescription insertNewObjectForEntityForName:[speechEntity name] inManagedObjectContext:context];
[columbia setValue:[NSNumber numberWithInt:[columbia hash]] forKey:@"speechId"];
[columbia setValue:@"Columbia" forKey:@"speechName"];
[columbia setValue:warren forKey:@"tycoon"];
Run Code Online (Sandbox Code Playgroud)

请注意,我从Speech侧面设置关系.核心数据将处理另一方.

问题#2

如果不查看整个根视图控制器,很难说你做错了什么.但是,我不会重复使用视图控制器来显示两种不同类型的对象.这是糟糕的形式,导致代码残酷.

相反,我会创建第二个"主"视图控制器,旨在处理语音.然后你可以传入大亨,你的SpeechViewController可以运行从关系派生的数组,或者它可以在内部构建其获取的结果控制器.即使更有价值的是能够自定义其单元格,标题等以适合它正在显示的数据.

问题#3

首先评论您添加的新代码:

SpeechViewController *speechView = [[SpeechViewController alloc] initWithNibName:@"SpeechViewController" bundle:[NSBundle mainBundle]];
Tycoon *tycoons = (Tycoon *)[fetchedResultsController objectAtIndexPath:indexPath];
speechView.tycoons = tycoons;
[self.navigationController pushViewController:speechView animated:YES];
Run Code Online (Sandbox Code Playgroud)

ZERO理由赶出去的-[NSFetchedResultsController objectAtIndexPath:].任何返回的方法id都可以分配给任何指针.

转换是编译器的谎言,应该不惜一切代价避免.

现在,把它放在一边,你的代码很好.我会将该物业命名为"大亨"而不是"大亨",因为您正在传递一个大亨实体.

SpeechViewController侧面,您现在可以访问与该Tycoon实体相关联的演讲,并根据您的选择显示它们.

你看到的问题是什么?

问题#4

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    NSSet *speechesSet = [[self tycoon] valueForKey:@"TycoonToSpeech"];
    // Sort the speeches
    NSSortDescriptor *nameSort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortedSpeeches = [speechesSet sortedArrayUsingDescriptors:[NSArray arrayWithObject:nameSort]];
    // Configure the cell...
    id speech = [sortedSpeeches objectAtIndex:[indexPath row]];
    [[cell textLabel] setText:[speech valueForKey:@"name"]];

    return cell;
}
Run Code Online (Sandbox Code Playgroud)

好的,从顶部开始.首先,关系将返回NSSet不是a NSArray.关系的结果是无序的.因此,我们将结果作为a抓取NSSet,然后对它们进行排序.我猜想你的Speech实体有一个名字属性.

一旦我们对它们进行了排序,我们就可以抓住该行的项目.这将返回一个Speech实体.我指定了它,id因为无论如何我们将使用KVC.

最后,我使用KVC nameSpeech实体获取属性并将其分配给textLabel单元格.

至于你-tableView: numberOfRowsInSection:,那个更简单:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[[self tycoon] valueForKey:@"TycoonToSpeech"] count];
}
Run Code Online (Sandbox Code Playgroud)

因为您只有一个部分,所以您只需要返回演讲次数.

我之前提到过你的属性名称需要一些工作.因为Tycoon它只是一个对象而且只是该对象的TycoonToSpeech一个属性,所以应该真正调用该属性,speeches因为它不比对象上的任何其他属性更特殊.属性名称在代码中流动得更好,使代码更容易使用.此外,Objective-C命名约定要求属性aka属性以小写字母开头.