在 UIPageViewController 中访问已创建的视图控制器

Posted

技术标签:

【中文标题】在 UIPageViewController 中访问已创建的视图控制器【英文标题】:Access already created view controllers in a UIPageViewController 【发布时间】:2014-02-22 22:28:40 【问题描述】:

我正在使用UIPageViewController 来显示图像,我会异步下载图像并在它们准备好后将它们放入图库(但您仍然可以转到图库中图像所在的页面会)。

我的问题是,当图像加载时,我需要为它对应的视图控制器提供它。现在,我将它添加到NSCache 实例中,当调用UIPageViewController 的数据源方法viewControllerAfterViewController: 时,我检查正在请求的视图控制器的图像是否已经下载(在缓存中)如果是,我在特定的视图控制器上调用initWithImage:,传递下载的图像。

我的问题是何时调用 viewControllerAfterViewController: 并且图像尚未下载。现在我只加载没有图像的视图控制器,当调用 imageDidFinishDownloading: 委托方法时,我尝试为视图控制器提供图像。

然而,似乎即使UIPageViewController 请求下一个视图控制器,前一个视图控制器也会显示(即:当我到达第 3 页时,它请求第 4 页的视图控制器)我不能访问我交出的这个请求的视图控制器

如果我访问pageViewController.viewControllersNSArray 的计数从不超过 1。所以即使它看起来应该有 2(当前显示的视图控制器和下一个它请求的),它只有一个,当前可见的视图控制器。

问题是我需要另一个。图片下载完成,我真的只有两个选择。

    把它交给我的NSCache,这样当视图控制器的init方法被调用时,它就会被移交。 如果它已经inited,把它交给已经被inited 的视图控制器。

但是 1 并不总是有效,因为有时在还没有图像(它还没有完成下载)时调用 init 方法,所以我们有时会依赖 2,但 pageViewController.viewControllers 只持有当前可见的视图控制器。

所以基本上第三种情况是视图控制器已经inited 没有图像,并且图像完成下载并且我想将它分配给该视图控制器,但我目前在它之前的那个,并且我对 UIPageViewController 中视图控制器的唯一引用是在当前可见的视图控制器上。

如何处理 3?我需要为视图控制器分配一些东西但我找不到任何方法来访问该视图控制器

【问题讨论】:

如何关联控制器和缓存中的图像? @JoshCaswell 抱歉,乔希,我还没在家,想通过手机以外的其他方式给你一个体面的答案。为了回答您的问题,每个创建的视图控制器都在子类中被赋予了一个 index 属性和一个相应的值,该值也用作 NSCache 中图像的键。当我创建控制器时,我会检查缓存中是否有视图控制器索引的对象,如果没有,我会在没有图像的情况下创建它。这能回答你的问题吗? 我明白了。而且您无法使用索引,因为页面视图控制器的数组似乎没有完整的视图控制器列表。说得通。我现在自己不在键盘上,但我会尝试调查一下。 文档说视图控制器数组是“视图控制器数组包含当前正在显示的内容视图控制器。”页面控制器不一定保持跟踪的 VC 的观点对你来说是屏幕外的。您必须自己在数据源或其他地方管理它们。似乎您也可以只使用 VC 键入图像,这就是我问这个问题的原因。所以据我所知,你的标题问题的答案是“你不能”。你需要修改你的设计,这就是为什么 Timonthy Moose 提出了类似 futures 的建议。 【参考方案1】:

我会使用来自PMConcurrency 的未来之类的东西来做到这一点。未来只是一个承诺在图像可用时立即返回的对象。因此,通过将未来交给您的视图控制器而不是图像,您无需担心图像何时到达。

您的视图控制器的初始化程序如下所示:

- initWithImageFuture:(PMFuture *)future

    if (self = [super init]) 
        [[future onMainThread] onComplete:^(id result, NSError *error) 
            if (!error) 
                _image = result;
            
        ];
    
    return self;

通过向未来添加onComplete 块,视图控制器将在图像可用时立即接收(如果图像已经下载,则立即接收)。 Futures 默认在后台运行,因此您可以使用 onMainThread 让结果在主线程上返回。

因此,与其用图像填充缓存,不如用图像期货填充它。有几种方法可以创建期货,但基于区块的方法非常简单:

PMFuture *imageFuture = [PMFuture futureWithBlock:^id
    UIImage *image = ...; // Your image fetching code here
    return image;        
];

[myCache setObject:imageFuture forKey:myImageKey];

【讨论】:

感谢您提供的信息,但这并不能回答我的问题。 @dougsmith 我认为通过回调访问您的视图控制器将有资格作为答案。 为了解释 Tim 所说的内容,您可以完全在自己内部管理在尚未显示的控制器上填充 UIImageViews 的所有细节。您需要做的就是设置一些机制来使用块回调或 PMFutures 下载图像,然后使用该回调机制设置图像属性。如果这样做,则无需从 UIPageViewController 访问对下一个视图控制器的引用。【参考方案2】:

我有类似的功能,但我将图像加载到显示图像的视图控制器中(VC 交给 UIPageViewController)。在您的上下文中,我想我已经获得了 VC 的图像 ID 信息和 NSCache 对象。当然,这不是您想要做的事情,只是需要考虑的事情。

最初我尝试像您一样处理父级中的图像加载。我记得,我保留了一个指向目标视图控制器的弱指针。当图像到达时,如果 VC 还活着,我可以设置 UIImageView 属性。

【讨论】:

我发现 UIPageViewController 很快就会杀死视图控制器,所以我很犹豫在任何视图控制器中做任何需要时间的事情。

以上是关于在 UIPageViewController 中访问已创建的视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

UIPageViewController 背景在 Objective C iOS 中从不透明

获取 UIPageViewController 的滚动位置

在故事板中使用 UIPageViewController

如何在 UIPageViewController 和孩子之间正确传递对象

使用 UIPageViewController 在多个视图控制器之间滑动

带有 Peeking 的 UIPageViewController