好吧,我是一个谓词菜鸟 . 他们对我来说太陌生了 .
关于应用:
我有一个处理游戏比赛的应用程序 . 有球员,签到和比赛的实体 . 这个想法是玩家被添加到应用程序,然后可以签入进行播放,并存储匹配结果 .
关系:
玩家< - >> CheckIns(每个玩家可以在不同日期进行多次签到)
-
来自:玩家实体
-
关系:playerCheckins
-
反向:checkedInPlayer
-
目的地:CheckIn实体
球员<< - >>比赛(每场比赛可以有两名球员,每次比赛时球员可以有多场比赛)
-
来自:玩家实体
-
关系:playerMatches
-
反向:matchPlayers
-
目的地:匹配实体
我有一个共享的集合视图,列出了应用程序中的所有玩家 . 当玩家登记时以及将它们添加到新的匹配条目时使用它 . 到目前为止,这一切都很好 .
我想做什么:
我希望玩家收集视图根据他们的登记状态过滤列出的玩家 . 例如,在签入新玩家时,玩家收藏视图应仅显示当天检查的玩家 . (CheckIns每个条目都有一个日期属性)此外,在向匹配项添加玩家时,集合视图应该只显示那天 have already 签到的玩家 .
我计划在玩家集合视图中添加NSString属性,当我以模态方式加载集合视图时,该视图使用谓词文本设置 . 这样,我可以根据我是否从我的匹配中调用集合视图并分别检入视图来更改谓词 .
这可能与我想做的事情有关吗?这些谓词字符串会是什么样的?
谢谢!
更新
我应该更清楚 . 我正在使用fetchedresultscontroller让玩家进入collectionview,所以我正在寻找在获取请求中使用的谓词...
添加代码......
我的CollectionViewController:
PlayersCollectionViewController.h
#import "CoreCollectionViewController.h"
#import "Player.h"
@protocol PlayersCollectionViewControllerDelegate;
@interface PlayersCollectionViewController : CoreCollectionViewController <NSFetchedResultsControllerDelegate>
@property (nonatomic, assign) id <PlayersCollectionViewControllerDelegate> delegate;
@property (nonatomic, strong) NSString *titleText;
@property (nonatomic, strong) NSString *predicate;
- (IBAction)cancel:(UIBarButtonItem *)sender;
- (IBAction)done:(UIBarButtonItem *)sender;
@end
@protocol PlayersCollectionViewControllerDelegate <NSObject>
@optional
-(void)ViewController:(UIViewController *)sender
didSelectPlayer:(Player *)selectedPlayer;
@optional
-(void)ViewController:(UIViewController *)sender
didSelectPlayer1:(Player *)selectedPlayer1;
@optional
-(void)ViewController:(UIViewController *)sender
didSelectPlayer2:(Player *)selectedPlayer2;
@end
......和实施:
#import "PlayersCollectionViewController.h"
#import "AppDelegate.h"
#import "PlayerCollectionViewCell.h"
@interface PlayersCollectionViewController ()
@property(nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
@end
@implementation PlayersCollectionViewController
@synthesize titleText, predicate;
static NSString * const reuseIdentifier = @"Cell";
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(NSManagedObjectContext*)managedObjectContext{
return [(AppDelegate*)[[UIApplication sharedApplication]delegate]managedObjectContext];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = NO;
// Register cell classes
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
// Do any additional setup after loading the view.
NSError *error = nil;
if (![[self fetchedResultsController]performFetch:&error]) {
NSLog(@"Error: %@", error);
abort();
}
}
-(void)viewWillAppear:(BOOL)animated
{
[self setTitle:titleText];
[self.collectionView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return [[self.fetchedResultsController sections]count];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [[self.fetchedResultsController fetchedObjects]count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PlayerCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PlayerCollCell" forIndexPath:indexPath];
Player *player = [self.fetchedResultsController objectAtIndexPath:indexPath];
// Configure the cell
if (player.playerImage) {
cell.playerImageView.image = [UIImage imageWithContentsOfFile:player.playerImageSmall];
}
[cell.playerNameLabel setText:player.firstName];
return cell;
}
-(BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
PlayerCollectionViewCell *selectedPlayerCell = (PlayerCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
[collectionView dequeueReusableCellWithReuseIdentifier:@"PlayerCollCell" forIndexPath:indexPath];
selectedPlayerCell.backgroundColor = [UIColor lightGrayColor];
Player *selectedPlayer = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSLog(@"Selected player %@", selectedPlayer.firstName);
if ([self.title isEqualToString:@"Select Player 1"]) {
[self.delegate ViewController:self didSelectPlayer1:selectedPlayer];
} else if ([self.title isEqualToString:@"Select Player 2"]) {
[self.delegate ViewController:self didSelectPlayer2:selectedPlayer];
} else if ([self.title isEqualToString:@"Select Player"]) {
[self.delegate ViewController:self didSelectPlayer:selectedPlayer];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - ViewController methods
- (IBAction)cancel:(UIBarButtonItem *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)done:(UIBarButtonItem *)sender { //not sure if this method and UI are needed...
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - Fetched Results Controller Section
-(NSFetchedResultsController*) fetchedResultsController
{
if (_fetchedResultsController !=nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchedRequest = [[NSFetchRequest alloc]init];
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity =[NSEntityDescription entityForName:@"Player" inManagedObjectContext:context];
[fetchedRequest setEntity:entity];
NSSortDescriptor *lastNameSortDescriptor = [[NSSortDescriptor alloc]initWithKey:@"lastName" ascending:YES];
NSSortDescriptor *firsttNameSortDescriptor = [[NSSortDescriptor alloc]initWithKey:@"firstName" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:lastNameSortDescriptor, firsttNameSortDescriptor, nil];
fetchedRequest.sortDescriptors = sortDescriptors;
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchedRequest
managedObjectContext:context
sectionNameKeyPath:nil
cacheName:nil];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
#pragma mark - Fetched Results Controller Delegates
/*
-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.collectionView beginUpdates];
}
-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.collectionView endUpdates];
}
*/
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UICollectionView *collectionView = self.collectionView;
switch (type) {
case NSFetchedResultsChangeInsert:
[collectionView insertItemsAtIndexPaths:[NSArray arrayWithObjects:newIndexPath, nil]];
break;
case NSFetchedResultsChangeDelete: [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]];
break;
case NSFetchedResultsChangeUpdate: {
PlayerCollectionViewCell *selectedPlayerCell = (PlayerCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
//selectedPlayerCell.backgroundColor = [UIColor lightGrayColor];
Player *selectedPlayer = [self.fetchedResultsController objectAtIndexPath:indexPath];
if (selectedPlayer.playerImage) {
selectedPlayerCell.playerImageView.image = [UIImage imageWithContentsOfFile:selectedPlayer.playerImageSmall];
}
[selectedPlayerCell.playerNameLabel setText:selectedPlayer.firstName];
}
break;
case NSFetchedResultsChangeMove: [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]];
[collectionView insertItemsAtIndexPaths:[NSArray arrayWithObjects:newIndexPath, nil]];
break;
}
}
@end
2 回答
离开视图控制器并取出结果控制器片刻 . 您的谓词属于模型层,而不属于Controller或View层 . NSFetchRequest或NSFetchedResultsController的谓词没什么特别之处 . 它仍然只是一个NSPredicate .
为什么在Model层?您基于“当天检查”的过滤问题与视图或显示给用户的内容无关 . 这纯粹是一个数据问题 . 所以在Model层解决它(奖励:现在很容易为这个fetch编写一个单元测试) .
如果你作弊一点并使用你对数据的了解,你可以更容易 . 使播放器< - >> CheckIn关系成为有序的(侧注:核心数据中的实体名称是单数,就像类名一样,尽管多对多关系是复数) . 现在它是's easy to get a player'最近的签到:它是
thePlayer.checkins[0]
,签到时间是[thePlayer.checkins[0] timeOfEvent]
. 只需确保将CheckIn
添加到Player
时,将其放在索引0处 .但是,通过对数据模型进行非规范化,可以使其变得更加容易 . 保持从
Player
到CheckIn
的多对多关系 . 但是在Player
,timeOfLastCheckIn
上添加一个属性 . 每当添加CheckIn时,请确保更新timeOfLastCheckIn
; "say it once"表示您应该在方法中包装这对步骤,并始终调用该方法来添加CheckIn .现在到Xcode Data Modeler . 使用替换变量在
Player
上创建新的获取请求 . 在下拉列表中选择Expression,然后输入timeOfLastCheckIn > $fromdate
. 在Player
(+playersCheckingInAfterDate:context:
)上编写一个方法来执行该获取请求,接受两个参数NSManagedObjectContext
和NSDate
,并返回Players
数组 . 您将使用fetchRequestFromTemplateWithName:substitutionVariables:
来实例化获取请求,将对应于本地午夜的NSDate替换为$fromdate
. 如果您愿意,可以添加一个包装器方法来计算当地午夜的时间并将其传递给+playersCheckingInAfterDate:context:
. 您可以在类似的方法/获取模板集中将>
切换为<
,以查找今天尚未登记的玩家 .我不确定您的签到状态是如何运作的 . 假设它是BOOL,请执行以下操作: