【问题标题】:On-Demand resource downloading without error on iOS, but not available在 iOS 上按需下载资源没有错误,但不可用
【发布时间】:2020-02-09 23:54:22
【问题描述】:

我们的应用每次都能在我们测试过的所有 iOS 设备上顺利运行(从 xcode/adhoc 生产/调试中全新安装或更新,我们都尝试过)。但它在应用审核中被拒绝,因为它似乎永远不会提供按需资源,即使资源的下载完成且没有错误。

我们正在访问相机回调阻塞区域中的资源。如果资源可用,我们继续使用它,否则我们只在下载完成后执行 beginAccessingResourcesWithCompletionHandler() 和免费回调块。问题是应用程序审阅者说它下载(有一个进度条),然后一遍又一遍地要求重新下载。为什么刚下载成功就不可用(注意没有错误)?

[request conditionallyBeginAccessingResourcesWithCompletionHandler:^(BOOL resourcesAvailable) {
if (resourcesAvailable)
{
    /* use the resource. */
    /* unblock the callback. done. */
}
else
{
    /* ask to download resource */
    [request beginAccessingResourcesWithCompletionHandler:^(NSError * _Nullable error) {
        if (error)
        {
            NSLog(@"%@", error);
            /* don't unblocked. return. will hang. */ 
        }
        /* unblock the callback. done. resource should be available next camera frame. */
    }];
} }];

这也不是存储空间不足的问题。我们已经涵盖并测试了这一点。此外, beginAccessingResourcesWithCompletionHandler() 返回没有错误。

【问题讨论】:

  • 这是真实代码的精简版。它遵循网络上的所有示例。你做一个有条件的开始,如果它失败了,你就做一个 beginAccess 下载。你是说 beginAccessingResourcesWithCompletionHandler() 只需要从主线程调用吗?为什么?我没有看到任何地方提到过。完成处理程序也返回没有错误。如果由于不在主线程中而导致下载出现问题,它不应该返回错误吗?
  • 我确实在列表 4-3 中看到他们在主线程上开始访问。 developer.apple.com/library/archive/documentation/…
  • 我正在向商店发送一个修订版,它将 beginAccessing 放在主线程块中。无法在测试设备上重现它很困难。如果解决了就会更新。
  • 哦,这只是一个非常大的代码库。我不能倾倒整个东西,它只是不可读。 OnDemand 资源实际上是内置在金属着色器中的神经网络的权重,当相机缓冲区回调开始时正在编译。在未完成对 OnDemand 资源的访问和网络编译之前,需要跳过相机缓冲区回调。如果网络尚未完成编译(第一步是下载所述 OnDemand 资源),只需退出相机回调即可完成此操作。这就是我阻止回调的意思。
  • 将 beginAccess 放在主线程调用中并不能解决问题。仍然在审核中被拒绝,因为在他们的设备上它仍然没有看到 resourcesAvailable,即使在第一次 beginAccess 完成后没有错误(它成功下载了资源)。

标签: ios app-store on-demand-resources


【解决方案1】:

我猜问题是没有注意大写字母in the documentation的警告:

一个 NSBundleResourceRequest 对象只能用于一个成功的资源请求。

您不能重复使用捆绑资源请求对象。它只有两个工作:下载资源(一次),以及将它们保存在适当的位置(通过持久化)。一旦你成功下载了一次资源,你只能用这个捆绑资源请求对象做两件事(你可以同时做这两件事):

  • 致电endAccessingResources

  • 将对象扔掉(或让它超出范围或随着应用程序的终止而死)。

如果您想在应用程序的同一次运行中再次查明您是否还有这些资源,则需要从新的捆绑资源请求重新开始。

但是,我会走得更远。正如我在 cmets 中所说,您似乎在滥用conditionallyBegin。无需在应用程序的同一运行期间两次询问您是否已经拥有这些资源,也无需致电conditionallyBegin 来查找,因为当您说beginAccessing正确的事情会发生:要么您将开始使用这些资源(如果它们存在),要么您将下载它们并开始使用它们(如果它们不存在)。使用conditionallyBegin 的唯一原因是,如果某些资源不存在,您的逻辑是否会不同

【讨论】:

  • 我在每次迭代中重新定义 NSBundleResourceRequest。我在 conditionallyBegin 和 beginAccess 调用之间重用了它(我理解你所说的 beginAccess 似乎只是必要的,但这是 Apple 特别建议的)。我对其进行了更改,为 beginAccess 调用定义了一个新的 resourceRequest。提交到存储并被拒绝,在他们的测试设备上仍然失败,成功完成下载,但下一次访问仍然认为它不可用。
  • 我没有想法,多么挑剔的 api。 Android 版本的这个是几个月前完成的。暂时只坚持使用 TestFlight,因为我们没有在任何设备上看到这一点,但无论审阅者使用的是什么。
【解决方案2】:

在提交 9 次后,此问题已为我们解决。但不幸的是,尚不清楚哪个更改对于解决它至关重要。此外,它也在 13.2.3 更新附近。 总的来说,我会确保这些(注意有很多不遵循这些的对 SO 进行投票的例子): 1) 所有 beginAccess 调用都在主线程上完成。 2) 不要在conditionallyBeginAcces 和beginAccess 之间重用resourceRequest。 (正如马特所指出的)。每次从标签名称重新定义它们。 3) 确保resourceRequest 的定义使得它们在整个过程完成之前不会超出范围。审阅者设备可能有一个后台守护程序,该守护程序会立即删除已释放的资源(由于超出范围)。 4) 如果在 dispatch_sync() 块内访问 odr,请确保没有触发并发 beginAccess 的路径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-12
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 2018-03-01
    • 2020-01-05
    相关资源
    最近更新 更多