菜鸟教程小白 发表于 2022-12-12 10:39:39

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


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

<h2>关于应用:</h2>

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

<h2>关系:</h2>

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

<ul>
<li>来自:玩家实体</li>
<li>关系:playerCheckins</li>
<li>逆向:checkedInPlayer</li>
<li>目的地:CheckIn 实体</li>
</ul>

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

<ul>
<li>来自:玩家实体</li>
<li>关系:playerMatches</li>
<li>逆向:matchPlayers</li>
<li>目标:匹配实体</li>
</ul>

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

<h2>我想做什么:</h2>

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

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

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

<p>谢谢!</p>

<h2>更新</h2>

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

<h2>添加代码...</h2>

<p>我的 CollectionViewController:</p>

<pre><code>PlayersCollectionViewController.h
#import &#34;CoreCollectionViewController.h&#34;
#import &#34;Player.h&#34;

@protocol PlayersCollectionViewControllerDelegate;


@interface PlayersCollectionViewController : CoreCollectionViewController &lt;NSFetchedResultsControllerDelegate&gt;

@property (nonatomic, assign) id &lt;PlayersCollectionViewControllerDelegate&gt; delegate;
@property (nonatomic, strong) NSString *titleText;
@property (nonatomic, strong) NSString *predicate;

- (IBAction)cancel:(UIBarButtonItem *)sender;
- (IBAction)done:(UIBarButtonItem *)sender;

@end

@protocol PlayersCollectionViewControllerDelegate &lt;NSObject&gt;

@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
</code></pre>

<p>...以及实现:</p>

<pre><code>#import &#34;PlayersCollectionViewController.h&#34;
#import &#34;AppDelegate.h&#34;
#import &#34;PlayerCollectionViewCell.h&#34;

@interface PlayersCollectionViewController ()
@property(nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
@end

@implementation PlayersCollectionViewController
@synthesize titleText, predicate;

static NSString * const reuseIdentifier = @&#34;Cell&#34;;

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = ;
    if (self) {
      // Custom initialization
    }
    return self;
}

-(NSManagedObjectContext*)managedObjectContext{
    return [(AppDelegate*)[delegate]managedObjectContext];
}

- (void)viewDidLoad
{
    ;

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = NO;

    // Register cell classes
    forCellWithReuseIdentifier:reuseIdentifier];

    // Do any additional setup after loading the view.
    NSError *error = nil;
    if (![performFetch:&amp;error]) {
      NSLog(@&#34;Error: %@&#34;, error);
      abort();
    }
}

-(void)viewWillAppear:(BOOL)animated
{
    ;
    ;
}

- (void)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 .
    // Pass the selected object to the new view controller.
}
*/

#pragma mark &lt;UICollectionViewDataSource&gt;

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return [count];
}


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return [count];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{

    PlayerCollectionViewCell *cell = ;
    Player *player = ;

    // Configure the cell

    if (player.playerImage) {
      cell.playerImageView.image = ;
    }

    ;

    return cell;
}

-(BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{

    PlayerCollectionViewCell *selectedPlayerCell = (PlayerCollectionViewCell*);

    ;

    selectedPlayerCell.backgroundColor = ;

    Player *selectedPlayer = ;

    NSLog(@&#34;Selected player %@&#34;, selectedPlayer.firstName);

    if () {
      ;
    } else if () {
      ;
    } else if () {
      ;
    }

    ;
}

#pragma mark - ViewController methods
- (IBAction)cancel:(UIBarButtonItem *)sender {
    ;
}

- (IBAction)done:(UIBarButtonItem *)sender { //not sure if this method and UI are needed...
    ;
}


#pragma mark - Fetched Results Controller Section
-(NSFetchedResultsController*) fetchedResultsController
{
    if (_fetchedResultsController !=nil) {
      return _fetchedResultsController;
    }

    NSFetchRequest *fetchedRequest = [init];

    NSManagedObjectContext *context = ;

    NSEntityDescription *entity =;

    ;

    NSSortDescriptor *lastNameSortDescriptor = [initWithKey:@&#34;lastName&#34; ascending:YES];
    NSSortDescriptor *firsttNameSortDescriptor = [initWithKey:@&#34;firstName&#34; ascending:YES];

    NSArray *sortDescriptors = [ initWithObjects:lastNameSortDescriptor, firsttNameSortDescriptor, nil];

    fetchedRequest.sortDescriptors = sortDescriptors;


    _fetchedResultsController = [ initWithFetchRequest:fetchedRequest
                                                                  managedObjectContext:context
                                                                      sectionNameKeyPath:nil
                                                                               cacheName:nil];

    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;

}

#pragma mark - Fetched Results Controller Delegates
/*
-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
;
}

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
;
}
*/

-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    UICollectionView *collectionView = self.collectionView;

    switch (type) {
      case NSFetchedResultsChangeInsert:
            ];
            break;

      case NSFetchedResultsChangeDelete: ];
            break;

      case NSFetchedResultsChangeUpdate: {
            PlayerCollectionViewCell *selectedPlayerCell = (PlayerCollectionViewCell*);

            //selectedPlayerCell.backgroundColor = ;

            Player *selectedPlayer = ;

            if (selectedPlayer.playerImage) {
                selectedPlayerCell.playerImageView.image = ;
            }

            ;

      }
            break;

      case NSFetchedResultsChangeMove: ];
            ];
            break;

    }

}

@end
</code></pre></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>暂时离开您的 ViewController 并获取结果 Controller 。您的谓词属于模型层,而不是 Controller 或 View 层。 NSFetchRequest 或 NSFetchedResultsController 的谓词没有什么特别之处。它仍然只是一个 NSPredicate。</p>

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

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

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

<p>现在到 Xcode 数据建模器。使用替换变量在 <code>Player</code> 上创建一个新的获取请求。在下拉列表中选择表达式并输入 <code>timeOfLastCheckIn > $fromdate</code>。在 <code>Player</code> (<code>+playersCheckingInAfterDate:context:</code>) 上编写一个方法来执行该获取请求,接受两个参数,<code>NSManagedObjectContext</code> 和一个 <code> NSDate</code>,并返回一个 <code>Players</code> 数组。您将使用 <code>fetchRequestFromTemplateWithName:substitutionVariables:</code> 来实例化提取请求,用对应于本地午夜的 NSDate 替换 <code>$fromdate</code>。如果您愿意,可以添加一个包装器方法来计算本地午夜的时间并将其传递给 <code>+playersCheckingInAfterDate:context:</code>。您可以在类似的一组方法/获取模板中将 <code>></code> 切换为 <code><</code> 以查找今天没有签到的玩家。</p></p>
                                   
                                                <p style="font-size: 20px;">关于iOS Core Data Predicate 用于根据相关数据进行过滤,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/24564551/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/24564551/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: iOS Core Data Predicate 用于根据相关数据进行过滤