• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

iOS Core Data Predicate 用于根据相关数据进行过滤

[复制链接]
菜鸟教程小白 发表于 2022-12-12 10:39:39 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

好吧,我是一个谓词菜鸟。他们对我来说只是陌生的。

关于应用:

我有一个处理游戏比赛的应用。有玩家、签到和比赛的实体。 这个想法是将玩家添加到应用程序中,然后可以签到进行比赛,并存储比赛结果。

关系:

玩家<->>签到(每个玩家可以在不同日期多次签到)

  • 来自:玩家实体
  • 关系:playerCheckins
  • 逆向:checkedInPlayer
  • 目的地:CheckIn 实体

球员<<->>比赛(每场比赛可以有两名球员,球员可以在每次比赛中进行多场比赛)

  • 来自:玩家实体
  • 关系:playerMatches
  • 逆向:matchPlayers
  • 目标:匹配实体

我有一个共享 Collection View ,其中列出了应用程序中的所有玩家。它在玩家签到以及将他们添加到新的比赛条目时使用。到目前为止,这一切都很好。

我想做什么:

我希望玩家收藏 View 根据他们的签到状态过滤列出的玩家。例如,当 checkin 新玩家时,玩家 Collection View 应仅显示当天尚未 checkin 的玩家。 (CheckIns 对每个条目都有一个 date 属性)此外,在将球员添加到比赛时, Collection View 应该只显示当天已经签到的球员。

当我以模态方式加载 Collection View 时,我计划将一个 NSString 属性添加到使用谓词文本设置的玩家 Collection View 中。这样,我可以根据我是否从匹配项中调用 Collection View 并分别 checkin View 来更改谓词。

这可能与我正在尝试做的事情有关吗?这些谓词字符串会是什么样子?

谢谢!

更新

我应该更清楚。我正在使用 fetchedresultscontroller 让玩家进入 collectionview,所以我正在寻找要在 fetch 请求中使用的谓词...

添加代码...

我的 CollectionViewController:

PlayersCollectionViewController.h
#import "CoreCollectionViewController.h"
#import "layer.h"

@protocol PlayersCollectionViewControllerDelegate;


@interface PlayersCollectionViewController : CoreCollectionViewController <NSFetchedResultsControllerDelegate>

@property (nonatomic, assign) id <layersCollectionViewControllerDelegate> delegate;
@property (nonatomic, strong) NSString *titleText;
@property (nonatomic, strong) NSString *predicate;

- (IBAction)cancelUIBarButtonItem *)sender;
- (IBAction)doneUIBarButtonItem *)sender;

@end

@protocol PlayersCollectionViewControllerDelegate <NSObject>

@optional
-(void)ViewControllerUIViewController *)sender
     didSelectPlayerPlayer *)selectedPlayer;

@optional
-(void)ViewControllerUIViewController *)sender
      didSelectPlayer1Player *)selectedPlayer1;

@optional
-(void)ViewControllerUIViewController *)sender
      didSelectPlayer2Player *)selectedPlayer2;

@end

...以及实现:

#import "layersCollectionViewController.h"
#import "AppDelegate.h"
#import "layerCollectionViewCell.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)initWithNibNameNSString *)nibNameOrNil bundleNSBundle *)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"layerCollCell" 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"layerCollCell" 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"layer" 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



Best Answer-推荐答案


暂时离开您的 View Controller 并获取结果 Controller 。您的谓词属于模型层,而不是 Controller 或 View 层。 NSFetchRequest 或 NSFetchedResultsController 的谓词没有什么特别之处。它仍然只是一个 NSPredicate。

为什么要在模型层这样做?您基于“当天签到”的过滤问题与 View 或向用户显示的内容无关。这纯粹是一个数据问题。所以在模型层解决它(奖励:现在很容易为此获取编写单元测试)。

如果你稍微作弊并使用你对数据的了解,你可以让这更容易。使 Player<->>CheckIn 关系成为一个有序的关系(旁注:Core Data 中的实体名称是单数的,就像类名一样,尽管一对多关系是复数的)。现在很容易获得玩家最近的签到:它是thePlayer.checkins[0],签到时间是[thePlayer.checkins[0] timeOfEvent]。只需确保将 CheckIn 添加到 Player 时,将其放在索引 0 处。

不过,您可以通过对数据模型进行一些非规范化来简化它。保持 PlayerCheckIn 的一对多关系。但是在 Player 上添加一个属性,timeOfLastCheckIn。确保在添加 CheckIn 时更新 timeOfLastCheckIn; “说一次”意味着您应该将这对步骤包装在一个方法中,并始终调用该方法来添加 CheckIn。

现在到 Xcode 数据建模器。使用替换变量在 Player 上创建一个新的获取请求。在下拉列表中选择表达式并输入 timeOfLastCheckIn > $fromdate。在 Player (+playersCheckingInAfterDate:context:) 上编写一个方法来执行该获取请求,接受两个参数,NSManagedObjectContext 和一个 NSDate,并返回一个 Players 数组。您将使用 fetchRequestFromTemplateWithName:substitutionVariables: 来实例化提取请求,用对应于本地午夜的 NSDate 替换 $fromdate。如果您愿意,可以添加一个包装器方法来计算本地午夜的时间并将其传递给 +playersCheckingInAfterDate:context:。您可以在类似的一组方法/获取模板中将 > 切换为 < 以查找今天没有签到的玩家。

关于iOS Core Data Predicate 用于根据相关数据进行过滤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24564551/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap