在今日窗口小部件扩展中经常“无法加载”

时间:2015-01-28 14:55:39

标签: ios objective-c ios-app-extension

我正在为我的应用制作今日小部件。我的小部件包含一个包含10个单元格的UITableView。 (每个单元格的高度为50pt。)功能很简单。如果我触摸单元格上的按钮,则从sqlite重新加载DB并在单元格上显示它们。除了iPhone6 +之外,它在模拟器和iPhone 4s,5,5s,6上运行良好。我确实删除了小部件并再次添加了10次,但这对我没有帮助。我确实检查过记忆和僵尸。但是在约10M下稳定并且没有泄漏。我怎样才能解决我的问题?

4 个答案:

答案 0 :(得分:18)

好的,伙计们,你不喜欢我之前的回答。我会重试。

考虑以下条件:

+-------------------+
| Table View        |
|+-----------------+|
|| Cell            ||
||+---------------+||
||| UILabel       |||
||+---------------+||
|+-----------------+|
+-------------------+

首先,表的逻辑宽度为:

  • 320pt on iPhone 5(Portrait)
  • 414pt on iPhone 6 +

内容比例因子是:

  • 0.5 for iPhone 5
  • 0.33 for iPhone 6 +

1pt的实际像素乘以1pt:

  • for iPhone 5,(1 / 0.5)^ 2 = 4
  • for iPhone 6+(1 / 0.33)^ 2 = 9

那么,如果UILabel适合整个设备宽度并且它的高度为44(Apple的HIG的最小可插入高度),那么实际的像素是:

  • 320 * 44 * 4 = iPhone 5的设备像素为5620
  • 414 * 44 * 9 = iPhone 6 +的设备像素为163,944

因此,iPhone6 +需要比iPhone5大3倍的缓冲区来绘制UILabel。

但是,当窗口小部件的内存使用量超过10MB时,将发生内存错误(通过无数次实验估算)。同样的限制适用于两种设备。 Apple未记录此限制。

请记住,在开发iOS8扩展程序时,您只能使用1%的设备内存,因为它可以防止查看后台应用程序。这是支持照片编辑扩展的应用程序很少的主要原因。

无论如何,因此,需要UI的扩展程序在iPhone 6+上容易崩溃,因为每个UI元素所需的内存量取决于大小和内容规模。

自定义绘图会导致同样的问题,因为它需要绘制缓冲区以优化动画和渲染。 iPhone6 +上缓冲区的分辨率和大小要大得多。

此外,Notification Center本身也存在漏洞(泄漏),即使只是Hello World小部件(随Xcode模板提供),每次显示和隐藏都会增加内存消耗。当它最终达到10MB时,它将崩溃并将被重新加载。这就是小部件有时会闪烁的原因。如果某个小部件连续崩溃3次,iOS会永久禁用小部件并显示“无法加载”。

那么,对于像这样严苛的条件我们能解决这个问题,我为这个问题制定了一些规则。

  1. 请勿使用实现[drawRect:]的自定义视图,除非它的尺寸非常小。
  2. 尽可能减少视图(具有自己的内容,尤其是标签)。
  3. 请勿使用背景图片。
  4. 点击空白区域以选择单元格

    这是Widget相关内存错误的常见问题,所以我也在写这个:

    窗口小部件层次结构中的所有视图都倾向于具有透明背景(UIClearColor),这意味着使单元格可以进行处理非常困难。因为用户触摸空白区域时不会发生小部件的整个命中测试。 (只有在至少没有透明的一个超级视图时才能应用自定义命中测试)有一些解决方案:

    1. 让UILabel的宽度适合Cell:DONT,它可以在iPhone6 +或更宽的高分辨率设备上消耗更多的内存。
    2. 在自定义单元格上实现空[drawRect:]。不,这是轻松实现透明控制的简单解决方案,但它需要绘图缓冲区。请记住,每个设备的缓冲区大小都不同。
    3. 我可以使其无需额外内存消耗的唯一解决方案是将小部件背景颜色设置为0.01 alpha的黑色。 (它使命中测试工作)

      +-------------------+
      | Table View        |- backgorund-color: (0, 0, 0, 0.01)
      |+-----------------+|
      || Cell            ||
      ||+---------+      ||
      ||| UILabel +------++- make it small as possible as you can
      ||+---------+      ||
      |+-----------------+|
      +-------------------+
      

      请记住,只有背景颜色的容器视图不会占用缓冲区内存。

答案 1 :(得分:3)

我喜欢jeeeyul answer's,但很多时候扩展程序崩溃(无法加载)只是因为 self.preferredContentSize 未正确设置。

我通过输入变量" currentHeight"来解决它。在TodayViewController类:

var currentHeight : CGFloat = 0.0
@IBOutlet var containerView: UIView! (the storyboard today extension viewcontroller view)

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        ... (load custom xib inside my containerView)
        self.currentHeight = containerView.frame.size.height
        self.preferredContentSize = CGSizeMake(self.view.frame.size.width,currentHeight)
    }

func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) {
        // Perform any setup necessary in order to update the view.

        // If an error is encountered, use NCUpdateResult.Failed
        // If there's no update required, use NCUpdateResult.NoData
        // If there's an update, use NCUpdateResult.NewData
        ... (do whatever you want in order to update)
        self.preferredContentSize = CGSizeMake(self.view.frame.size.width,currentHeight)
        completionHandler(NCUpdateResult.NewData)
        ...
    }

答案 2 :(得分:0)

编辑扩展方案, 选择运行操作, 在信息部分, 将“可执行文件”设置为“启动时询问”

这似乎可以解决问题,并且扩展程序每次都运行,不知道它是如何工作的,但这可以使工作顺利进行。

答案 3 :(得分:-1)

iPhone 6+非常大的屏幕,因此小部件的宽度也很大。 小部件的最大高度比iPhone5大得多。

结果,

由于它的分辨率,iPhone6 +上的小部件比iPhone5使用3到4倍的视频内存。有了一些动画,它会增加更多。

然而,由于在显示小部件时保持活动应用程序,iOS允许少量内存到小部件。 (未记录实际限制)。

在我的实验中,使用实现drawRect的自定义视图100%杀死iPhone6 +上的小部件,即使它什么都不做。 (空实施)

我认为这是错误。另一个我的推论是整个rect将被缓存以用于核心动画,它消耗内存。然后iOS杀了它。

真正的问题是iPhone6 +与iPhone5具有相同数量的RAM。

很简单:

  • iPhone6 +上的小部件需要更多内存。
  • 然而,小部件内存限制与iPhone5相同,实际上,它更糟糕,因为在后台活着的应用需要比iPhone 5更多的内存。以及其他小部件。

我确信这是Apple的硬件设计失败。

最令人伤心的是,iPhone6 +用户已经很多年了。 由于iPhone 6+用户,开发人员无法提供丰富的小部件。