【问题标题】:UIPageViewController's DataSource delegates getting called 2 times continuously for a single swipeUIPageViewController 的 DataSource 代表单次滑动连续调用 2 次
【发布时间】:2014-07-28 15:00:25
【问题描述】:

这可能看起来像以前提出的问题 (PageViewController delegate functions called twice),但问题是我无法将该解决方案应用于我的问题。

您可能会注意到,我正在开发一个日历应用程序并使用 UIPageViewController 来管理我的年度日历显示。如您所见,我正在使用 UIPageViewControllerTransitionStylePageCurl 并且当用户卷曲页面(向前/向后)时,他们各自的委托被调用两次,这使我根据执行的委托增加或减少 2 年。现在我需要找出导致此问题的原因并阻止它执行两次。

我知道在这些委托中返回一个 viewController 很重要,它提供了我的下一页或上一页,因此我只是刷新 viewController 的视图,以便我可以使用新数据呈现视图。我还尝试了另一个名为 willTransitionToViewControllers 的委托,但不会让我到任何地方,因为 willTransitionToViewControllers 只会在之后执行 viewControllerAfterViewController 和 viewControllerBeforeViewController。

有人帮我理解和解决这个问题。

 - (void)addCalendarViews
{
    CGRect frame = CGRectMake(0., 0., self.view.frame.size.width, self.view.frame.size.height);

    pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
                                                           navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
                                                                    options:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:UIPageViewControllerSpineLocationNone] forKey:UIPageViewControllerOptionSpineLocationKey]];
    pageViewController.doubleSided = YES;
    pageViewController.delegate = self;
    pageViewController.dataSource = self;

    YearCalendarViewController *yearController = [[YearCalendarViewController alloc] init];


    NSArray *viewControllers = [NSArray arrayWithObject:yearController];

    [self.pageViewController setViewControllers:viewControllers
                                  direction:UIPageViewControllerNavigationDirectionReverse
                                   animated:YES
                                 completion:nil];

    [self addChildViewController:pageViewController];
    [self.view addSubview:pageViewController.view];

    [pageViewController didMoveToParentViewController:self];

     CGRect pageViewRect = yearController.view.bounds;
     self.pageViewController.view.frame = pageViewRect;


     viewCalendarMonth = [[SGMonthCalendarView alloc] initWithFrame:frame];
     [self.view addSubview:viewCalendarMonth];

     arrayCalendars = @[pageViewController.view, viewCalendarMonth];
}




 -(UIViewController*)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
 {
     NSDate *currentDate = [[SGSharedDate sharedManager] currentDate]; 
     NSDateComponents *currentDateComp = [NSDate returnDateComponentsForDate:currentDate];
     self.nextDate = [NSDate dateWithYear:currentDateComp.year+1 month:currentDateComp.month day:currentDateComp.day];
    [[SGSharedDate sharedManager] setCurrentDate:nextDate];


   {
      //I m reloading viewController's view here to display the new set of data for the increamented date.
   }
    NSLog(@"After Dates====>%@", nextDate);
    return viewController;
 }



 -(UIViewController*)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
 {
     NSDate *currentDate = [[SGSharedDate sharedManager] currentDate]; 
     NSDateComponents *currentDateComp = [NSDate returnDateComponentsForDate:currentDate];
     nextDate = [NSDate dateWithYear:currentDateComp.year-1 month:currentDateComp.month day:currentDateComp.day];
     [[SGSharedDate sharedManager] setCurrentDate:nextDate];


     {
      //I m reloading viewController's view here to display the new set of data for the decremented date.
   }
     NSLog(@"Before Dates====>%@", nextDate);
     return viewController;
}

【问题讨论】:

  • 你在哪里定义nextDateComp?你的意思是写currentDateComp
  • 抱歉,这是我编辑此问题时的排版错误。我会立即编辑它。

标签: ios ipad


【解决方案1】:

UIPageController 倾向于向前(和向后)缓存,因此当您从视图控制器 N 向前滑动时,N+1 会加载但 N+2 也会静默加载,因此如果您滑动两次,您的内容已经加载.

但是由于您在委托方法中有一个不可见的副作用(递增日期),因此您会受到此影响。

我的建议是从你的委托中删除约会的副作用,并以某种方式将日期代码绑定到呈现的视图控制器(委托或属性),然后捕获 pageController 的 didFinishAnimating 方法。

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    if (completed) {

        if ([[self.pageViewController.viewControllers firstObject] isKindOfClass:[MyCalenderViewController class]]) {

            currentDate = [self workOutCurrentDateForVC:[self.pageViewController.viewControllers firstObject]];

        }

    }

}

副作用是代码异味。尽量避免。

编辑

我刚刚注意到您正在回收视图控制器并使用新的日期点重新加载它。不要这样做。您需要将视图控制器视为书的单页。所以生成一个新的并将其设置为当月...

举个例子……

@interface YearViewController : UIViewController 

@property NSDate *focusedYear;

-(instancetype)initWithYear:(NSDate)adate;

@end

@implementation YearViewController

-(instancetype)initWithYear:(NSDate)adate {
     self = [super initWithNibName:nil bundle:nil];
     if(self) {
         self.focusedYear = adate;
         ....
     } 
}

@end

因此,在页面控制器委托中,您只需根据前一个页面的日期(以及您分页的方向)提供一个新的“页面”

-(UIViewController*)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
 {
     YearViewController *yvc = (YearViewController *)viewController;

     NSDate *currentDate = yvc.focusedYear; 
     NSDateComponents *currentDateComp = [NSDate returnDateComponentsForDate:currentDate];
     NSDate *nextDate = [NSDate dateWithYear:currentDateComp.year+1 month:currentDateComp.month day:currentDateComp.day];

     YearViewController *freshYVC = [[YearViewController alloc] initWithDate:nextDate];

    return freshYVC;
 }

关于副作用的评论仍然有效。

【讨论】:

  • 感谢您的建议。
  • 感谢您提供避免回收视图控制器的提示。因此遇到了疯狂的问题。现在我只是创建新的,就像你在你的例子中展示的那样。这有什么副作用吗?我用它来刷“日期”,所以它有点“无休止”。出于性能考虑,我首先想重用视图控制器。
  • @DanielStorch 取决于您的代码,但只要您的页面在某个时候被释放,那就是一个好的开始。您可以通过在 dealloc (OC) 或 deinit (Swift) 方法中放置 NSLog 来快速检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-07
  • 2022-12-03
  • 1970-01-01
相关资源
最近更新 更多