更新iOS核心数据驱动应用程序集合视图中UIButton元素的最有效方法

更新iOS核心数据驱动应用程序集合视图中UIButton元素的最有效方法,ios,objective-c,uitableview,uicollectionview,nsfetchrequest,Ios,Objective C,Uitableview,Uicollectionview,Nsfetchrequest,我正处在一个十字路口,需要一些建议。我正在构建一种打孔卡系统,并通过核心数据保存打孔状态(参见下面的屏幕截图): 图像链接: 该应用程序的顶部基本上有一个“日期”集合视图。“父项”的表视图,每个都有自己的“reps”或“punchs”集合视图。当向左或向右滚动以关联到相应的日期时,集合视图彼此同步 我已经达到了这样的程度:当用户点击一个按钮/“punch”时,它会创建一个rep/punch管理的对象,将其附加到其父项(通过核心数据关系)上,设置相关的日期值,然后将其打开 这一切都很好,但是现在我

我正处在一个十字路口,需要一些建议。我正在构建一种打孔卡系统,并通过核心数据保存打孔状态(参见下面的屏幕截图):

图像链接:

该应用程序的顶部基本上有一个“日期”集合视图。“父项”的表视图,每个都有自己的“reps”或“punchs”集合视图。当向左或向右滚动以关联到相应的日期时,集合视图彼此同步

我已经达到了这样的程度:当用户点击一个按钮/“punch”时,它会创建一个rep/punch管理的对象,将其附加到其父项(通过核心数据关系)上,设置相关的日期值,然后将其打开

这一切都很好,但是现在我正在尝试找出更新托管Reps/Punchs对象的UIButton表示的最佳方法。我目前的理论是在加载UIButton时执行获取请求。这将在父项的“子”项(重复/打孔)中循环,并搜索匹配的日期。一旦找到具有匹配日期的项,它将相应地响应该对象,无论该对象处于打开还是关闭状态。在我看来,由于集合视图中的单元格已被释放,它一次最多只能执行大约35个获取请求,因为这是屏幕上可以容纳的所有单元格。然后,它将在加载新单元格后执行新请求。这将避免在加载视图后必须始终加载每个rep/punch对象

我的另一个想法是为永久单元格创建一个相关的rep/punch管理对象,并根据索引路径同步单元格,但是应用程序最终会有很多“死”对象,它们就在那里。这似乎是浪费和低效的

最后,我想到的第三个选项是如何为每个父项的子托管对象集创建一个字典,并使键成为它们的日期值。然后我可以简单地将字典键同步到相应单元格的日期值

我真诚地希望这不是一堆胡言乱语!我对iOS编程还不熟悉,在有限的范围内尽我最大的努力表达我的挑战。如果你有任何问题,请告诉我

有关守则:

@interface UpdateRepsViewController ()
@property (weak, nonatomic) IBOutlet UICollectionView *datesCV;
@property (weak, nonatomic) IBOutlet UITableView *habitsTableView;

@end

@implementation UpdateRepsViewController

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

- (void)viewDidLoad
{
    [super viewDidLoad];

    // scroll to last item in collection view (ie: today)
    NSInteger lastItem = [[Calculations updateRepsDateRangeDates] count]-1;
    NSIndexPath *lastIndexPath = [NSIndexPath indexPathForItem:lastItem inSection:0];
    [self.datesCV scrollToItemAtIndexPath:lastIndexPath atScrollPosition:UICollectionViewScrollPositionRight animated:YES];
    self.horScrollPos = self.datesCV.contentOffset.x;
    NSLog(@"%f", self.horScrollPos);

    // hides separator lines
    self.habitsTableView.separatorColor = [UIColor clearColor];

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        NSLog(@"Error : %@", error);
        abort();
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - managedObjectContext Reference
-(NSManagedObjectContext *)managedObjectContext {
    return [(AppDelegate *) [[UIApplication sharedApplication] delegate] managedObjectContext];
}

#pragma mark - Scroll Sync & Control

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView == self.datesCV) {
        for (UpdateRepsHabitCell *x in [self.habitsTableView visibleCells]) {
            x.repsCV.contentOffset = CGPointMake(scrollView.contentOffset.x, 0);
        }
    }
    if (scrollView.tag == 5) {
        for (UpdateRepsHabitCell *x in [self.habitsTableView visibleCells]) {
            x.repsCV.contentOffset = CGPointMake(scrollView.contentOffset.x, 0);
        }
        self.datesCV.contentOffset = CGPointMake(scrollView.contentOffset.x, 0);
    }
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    self.horScrollPos = scrollView.contentOffset.x;
    NSLog(@"%f", self.horScrollPos);
}

#pragma mark - CollectionViews Data Source

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    if (collectionView == self.datesCV) {
        return [[Calculations updateRepsDateRangeDates] count];
    }
    if (collectionView.tag == 5) {
        return [[Calculations updateRepsDateRangeDates] count];
    }
    else return 3;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    if (collectionView == self.datesCV) {
        UpdateRepsDateCell *cell = (UpdateRepsDateCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"DateCell" forIndexPath:indexPath];

        NSDateFormatter *df = [[NSDateFormatter alloc]init];
        [df setDateFormat:@"EEEEE\nM/d"];

        cell.date.text = [df stringFromDate:[Calculations updateRepsDateRangeDates][indexPath.row]];
        return cell;
    }
    if (collectionView.tag == 5) {
        RepButtonCell *cell = (RepButtonCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"RepCell" forIndexPath:indexPath];

        // get cell date
        NSDate *cellDate = [Calculations updateRepsDateRangeDates][indexPath.row];

        // get parent habit
        UpdateRepsRepCV * urcv = (UpdateRepsRepCV *)collectionView;
        Habit *habit = [self.fetchedResultsController objectAtIndexPath:urcv.habitIndexPath];

        // show relevant buttons
        if ([cellDate compare:habit.startDate] >= 0) {
            cell.repButton.hidden = NO;
        }
        else {
            cell.repButton.hidden = YES;
        }

        cell.repButton.habitIndexPath = urcv.habitIndexPath;
        cell.repButton.cellIndexPath = indexPath;

        return cell;
    }
    else {
        UICollectionViewCell *cell = [[UICollectionViewCell alloc]init];
        return cell;
    }
}

#pragma mark - Habits Table View Data Source

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    id <NSFetchedResultsSectionInfo> secInfo = [self.fetchedResultsController.sections objectAtIndex:section];
    return [secInfo numberOfObjects];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UpdateRepsHabitCell *cell = [tableView dequeueReusableCellWithIdentifier:@"HabitCell" forIndexPath:indexPath];

    Habit *habit = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.habitName.text = habit.name;

    cell.parentTableView = self.habitsTableView;

    cell.repsCV.habitIndexPath = indexPath;

    // set scroll
    cell.repsCV.contentOffset = CGPointMake(self.horScrollPos, 0);

    return cell;
}

#pragma mark - NSFetchedResultsController

-(NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Habit" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:@"sortOrder" ascending:YES];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];

    _fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];

    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

#pragma mark - NSFetchedResultsController Delegate Methods

-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.habitsTableView beginUpdates];
}

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.habitsTableView endUpdates];
}

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

    UITableView *tableView = self.habitsTableView;

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate: {
            Habit *changedHabit = [self.fetchedResultsController objectAtIndexPath:indexPath];
            UpdateRepsHabitCell *cell = (UpdateRepsHabitCell *)[tableView cellForRowAtIndexPath:indexPath];
            cell.habitName.text = changedHabit.name;
        }
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.habitsTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.habitsTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

#pragma mark - IBActions

- (IBAction)repPressed:(id)sender {

    // get parent habit
    RepButton *repButton = (RepButton *)sender;
    Habit *parentHabit = [self.fetchedResultsController objectAtIndexPath:repButton.habitIndexPath];

    // get date
    NSDate *repDate = [Calculations updateRepsDateRangeDates][repButton.cellIndexPath.row];


    Rep *rep = (Rep*)[NSEntityDescription insertNewObjectForEntityForName:@"Rep" inManagedObjectContext:self.managedObjectContext];
    rep.habit = parentHabit;
    rep.date = repDate;
    rep.completed = [NSNumber numberWithBool:YES];

    NSError *error;
    if ( ! [[self managedObjectContext]save:&error]) {
        NSLog(@"An error! %@", error);
    }
}
@interface UpdateRepsViewController()
@属性(弱、非原子)IBUICollectionView*datesCV;
@属性(弱、非原子)IBUITableView*habitsTableView;
@结束
@实现更新视图控制器
-(id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self=[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
如果(自我){
//自定义初始化
}
回归自我;
}
-(无效)viewDidLoad
{
[超级视图下载];
//滚动至收藏视图中的最后一项(即:今天)
NSInteger lastItem=[[Calculations updateRepsDateRangeDates]计数]-1;
NSIndexPath*lastIndexPath=[NSIndexPath indexPathForItem:lastItem不安全项:0];
[self.datesCV scrollToItemAtIndexPath:lastIndexPath atScrollPosition:UICollectionViewScrollPositionRight动画:是];
self.horcollpos=self.datesCV.contentOffset.x;
NSLog(@“%f”,self.horsollpos);
//隐藏分隔线
self.habitsTableView.separatorColor=[UIColor clearColor];
n错误*错误=nil;
如果(![self.fetchedResultsController性能检测:&错误]){
NSLog(@“错误:%@”,错误);
中止();
}
}
-(无效)未收到记忆警告
{
[超级记忆警告];
//处置所有可以重新创建的资源。
}
#pragma标记-managedObjectContext引用
-(NSManagedObjectContext*)managedObjectContext{
返回[(AppDelegate*)[[UIApplication sharedApplication]委托]managedObjectContext];
}
#pragma标记-滚动同步和控制
-(无效)scrollViewDidScroll:(UIScrollView*)scrollView{
if(scrollView==self.datesCV){
对于([self.habitsTableView visibleCells]中的UpdateRepsHabitCell*x){
x、 repsCV.contentOffset=CGPointMake(scrollView.contentOffset.x,0);
}
}
if(scrollView.tag==5){
对于([self.habitsTableView visibleCells]中的UpdateRepsHabitCell*x){
x、 repsCV.contentOffset=CGPointMake(scrollView.contentOffset.x,0);
}
self.datesCV.contentOffset=CGPointMake(scrollView.contentOffset.x,0);
}
}
-(无效)ScrollViewDiEndDecelling:(UIScrollView*)scrollView{
self.horcollpos=scrollView.contentOffset.x;
NSLog(@“%f”,self.horsollpos);
}
#pragma标记-CollectionViews数据源
-(NSInteger)collectionView:(UICollectionView*)collectionView项目编号截面:(NSInteger)截面{
if(collectionView==self.datesCV){
返回[[Calculations UpdateResdateRangeDates]计数];
}
if(collectionView.tag==5){
返回[[Calculations UpdateResdateRangeDates]计数];
}
否则返回3;
}
-(UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath{
if(collectionView==self.datesCV){
UpdateRepsDateCell*单元格=(UpdateRepsDateCell*)[collectionView dequeueReusableCellWithReuseIdentifier:@“DateCell”forIndexPath:indexPath];
NSDateFormatter*df=[[NSDateFormatter alloc]init];
[df setDateFormat:@“EEEEE\nM/d”];
cell.date.text=[df stringFromDate:[Calculations updateRepsDateRangeDates][indexPath.row]];
返回单元;
}
if(collectionView.tag==5){
RepButtonCell*单元格=(RepButtonCell*)[collectionView dequeueReusableCellWithReuseIdentifier:@“RepCell”forIndexPath:indexPath];
//获取手机日期
NSDate*cellDate=[Calculations updateRepsDateRangeDates][indexath.row];
//养成父母的习惯
UpdateRepsRepCV*urcv=(UpdateRepsRepCV*)集合视图;
习惯*习惯=[self.fetchedResultsCont