在 UIViewController 上加载数据:viewDidLoad 和 viewWillAppear - 啥是正确的逻辑?

Posted

技术标签:

【中文标题】在 UIViewController 上加载数据:viewDidLoad 和 viewWillAppear - 啥是正确的逻辑?【英文标题】:Loading data on a UIViewController: viewDidLoad and viewWillAppear - What is the proper logic?在 UIViewController 上加载数据:viewDidLoad 和 viewWillAppear - 什么是正确的逻辑? 【发布时间】:2011-06-28 15:07:12 【问题描述】:

我在第三个选项卡中有一个带有 UIScrollViewController 的 tabBarControllerView。我在 viewDidLoad 和 viewWillAppear 中加载基本相同的东西,来自核心数据的图片。我在想 viewWillAppear 是我可以用来更新 UIScrollView 中的视图。唯一的事情是当我将图片添加到核心数据时,没有显示正确的图片。

我想知道这是我的 viewWillAppear 逻辑还是我的上下文已关闭?我正在修复我的上下文,所以如果我的逻辑是合理的(减去 ManagedObjectContext),那将是很好听的 - 因为我可以回去处理上下文问题。

如果这是逻辑,那么如果您能指出我的缺陷,我将不胜感激:-)

头文件

#import <UIKit/UIKit.h>
#import "PhotoViewController.h"

@interface MyTabBarViewController  : UIViewController<UIScrollViewDelegate>


    IBOutlet UIPageControl *pageControl;
    IBOutlet UIScrollView *scroller;
    UIImage *image;
    CGFloat scrollWidth;
    int pageNumber;


@property (nonatomic,retain)IBOutlet UIPageControl *pageControl;
@property (nonatomic,retain)IBOutlet UIScrollView *scroller;

-(IBAction)clickPageControl:(id)sender;

@end

实现文件...相关sn-ps

- (void)viewDidLoad

    [super viewDidLoad];
    scroller.delegate=self;
    scroller.pagingEnabled=YES;
    scroller.directionalLockEnabled=YES;
    scroller.showsHorizontalScrollIndicator=NO;
    scroller.showsVerticalScrollIndicator=NO;
    scroller.contentSize=CGSizeMake(pageControl.numberOfPages*scroller.frame.size.width, scroller.frame.size.height);
    scrollWidth = 0;
    pageNumber = 0;
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *context = [(CoreDataProjAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
    request.entity = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:context];
    NSError *error = nil;
    NSArray *fetchCount = [context executeFetchRequest:request error:&error];
    int pageCount = [fetchCount count];
    for (int i=pageNumber; i<pageCount; i++)
    
        PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:@"PhotoViewController" bundle:nil];
        CGRect rect = scroller.frame;
        rect.size.height = scroller.frame.size.height;
        rect.size.width = scroller.frame.size.width;
        rect.origin.x = scroller.frame.origin.x + scrollWidth;
        rect.origin.y = scroller.frame.origin.y;
        pvc.view.frame  = rect;
        [pvc view];
        pvc.label.text = [NSString stringWithFormat:@"%d", pageNumber];
        pvc.label.textColor = [UIColor redColor];
        Photo *photo = [[Photo alloc] init];
        photo = [fetchCount objectAtIndex:i];
        UIImage *fetchedImage = [UIImage imageWithData:photo.photo];
        pvc.imageView.image = fetchedImage;
        [scroller addSubview:pvc.view];
        [pvc release];
        pageNumber++;
        scrollWidth += scroller.frame.size.width;
    
    pageControl.numberOfPages=pageCount;
    pageControl.currentPage=0;
    [self.view addSubview:scroller];
    [request release];


- (void) viewWillAppear:(BOOL)animated

    [super viewWillAppear:YES];
    scroller.delegate=self;
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *context = [(CoreDataProjAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
    request.entity = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:context];
    NSError *error = nil;
    NSArray *fetchCount = [context executeFetchRequest:request error:&error];
    int pageCount = [fetchCount count];
    scroller.contentSize=CGSizeMake(pageCount*scroller.frame.size.width, scroller.frame.size.height);
    for (int i=pageNumber; i<pageCount; i++)
    
        PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:@"PhotoViewController" bundle:nil];
        CGRect rect = scroller.frame;
        rect.size.height = scroller.frame.size.height;
        rect.size.width = scroller.frame.size.width;
        rect.origin.x = scroller.frame.origin.x + scrollWidth;
        rect.origin.y = scroller.frame.origin.y;
        pvc.view.frame  = rect;
        [pvc view];
        pvc.label.text = [NSString stringWithFormat:@"%d", pageNumber];
        pvc.label.textColor = [UIColor redColor];
        Photo *photo = [[Photo alloc] init];
        photo = [fetchCount objectAtIndex:i];
        UIImage *fetchedImage = [UIImage imageWithData:photo.photo];
        pvc.imageView.image = fetchedImage;
        [scroller addSubview:pvc.view];
        [pvc release];
        pageNumber++;
        scrollWidth += scroller.frame.size.width;
    
    pageControl.numberOfPages=pageCount;
    pageControl.currentPage=0;
    [self.view addSubview:scroller];
    [request release];

【问题讨论】:

【参考方案1】:

我不知道这是否是真正的原因,但我注意到的一件事是,在您的 for 循环中,您手动递增 pageNumber++,我不完全确定原因。如果您在循环中获取pageNumber 的任何内部引用(我只看到您正在设置标签文本的行)并将其替换为i,我相信这应该可以让您正确显示您的图像。简而言之,只需将pageNumber 从代码中删除(除非我明显忽略了某些内容),然后使用for (int i = 0; i &lt; pageCount; i++) 。如果仅此而已,这将使您可以更好地控制循环并消除每个循环增量期间的任何变化。至于使用哪种方法,最好实现viewWillAppear 中的代码,因为它可以让视图有更多的机会加载并在您显示图像时为您提供适当的尺寸。

编辑:如果您希望以特定顺序显示图像,您将无法通过从 managedObjectContext 获取对象来直接执行此操作,因为它将对象存储为 NSSet(未索引)。如果要按特定顺序显示图片,则需要使用排序描述符。因此,当您创建请求时,您需要遵循以下内容:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [(CoreDataProjAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
request.entity = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:context];
NSError *error = nil;
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:@"someAttributeToIndex" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sorter]];
NSArray *fetchCount = [context executeFetchRequest:request error:&error];

这样做应该可以让您实际指定要显示图像的顺序,按添加日期或整数索引(您必须将其作为属性添加到实体)

【讨论】:

我会试试你的建议。但是我选择不在循环中使用 i 的原因是因为如果核心数据中有 2 个对象要启动,然后在重新加载时有 5 个对象,那么我想在第 3 页 (5-2) 上启动循环。所以我的想法可能不正确,但这就是为什么我要使用页码,因为它应该是 3(或任何数字)。 不,那没用。感谢您的建议虽然 slev :-) 哦,我明白了。在这种情况下,我当然可以看到您的逻辑,即使用正确数量的图像保持页面有序。我不确定我是否真的看到图像关闭的任何原因。你是在viewDidLoadviewWillAppear 中调用代码吗?在第一次运行时,他们可能会撞到对方,从而歪曲了图片的去向。此外,您在设置 Photo 对象时可能会遇到内存泄漏。一旦你设置了新图像,我要么发布照片 *photo,要么代替 alloc/init,只需调用 Photo *photo = [fetchCount objectAtIndex:i] 再次感谢 Slev。我修复了内存泄漏 :-) 很高兴你指出了这一点。是的,我仍然不知道为什么这不起作用。我认为 ManagedObjectContext 与它有关。我会继续玩这个。 其实我只是想到了一些事情。虽然在输入之后,这对于评论来说太长了,所以我要编辑我原来的答案把它放在那里。我认为这可能是给您带来问题的原因

以上是关于在 UIViewController 上加载数据:viewDidLoad 和 viewWillAppear - 啥是正确的逻辑?的主要内容,如果未能解决你的问题,请参考以下文章

我应该在哪里从 UIViewController 中的 firebase 加载数据

如何在 NOT UIViewController 中从 Web 服务加载数据?

UIViewController - 加载缓慢

用tableview重新加载uiviewcontroller的table view subobject的数据

在 UIViewController 的主视图中加载自定义 UIView

如何重新加载 UIViewController 中包含的 tableView?