在Today Widget Extension中经常出现“Unable to load”

我为我的应用程序制作了一个Today小部件。 我的小部件包含10个单元格的UITableView。 (每个单元的高度是50pt。)function很简单。 如果我点击单元格上的button,从sqlite重新加载数据库,并显示在单元格中。 它在模拟器和iPhone 4s,5s,5s,6除了iPhone6 +都能很好地工作。 我删除了小部件,并再次添加了10次,但这对我没有帮助。 我没有检查内存和僵尸。 但是在〜10M下稳定下来,没有泄漏。 我该如何解决我的问题?

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

考虑以下情况:

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

UILabel

||+—————+|| |+—————–+| +——————-+

首先,表格的逻辑宽度是:

  • iPhone 5上的320pt(人像)
  • 在iPhone 6+上的414pt

内容比例因子是:

  • 0.5为iPhone 5
  • 0.33为iPhone 6+

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

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

那么如果一个UILabel适合整个设备的宽度并且它的高度是44(苹果公司的HIG的最小可放置高度),那么实际像素是:

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

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

但是,当小部件的内存使用量超过10MB时会发生内存错误(通过无数次实验估计)。 这两个设备都适用同样的限制。 苹果公司没有logging这个限制。

请记住,由于阻止了后台应用程序的使用,开发iOS8扩展程序时只能使用设备内存的1%。 这是有很less的应用程序支持照片编辑扩展的主要原因。

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

自定义绘图导致同样的问题,因为它需要缓冲区来绘制优化animation和渲染。 在iPhone6 +上,缓冲区的分辨率和尺寸要大得多。

另外,通知中心本身也有bug(漏洞),即使只是Hello World小部件(自带Xcode模板),每次显示和隐藏的内存消耗也会不断增加。 最终达到10MB时,会崩溃并重新加载。 这是小部件有时闪烁的原因。 如果某个小部件连续崩溃3次,iOS将永久禁用该小部件并显示“无法加载”。

那么,在这样严酷的条件下,我们该如何处理这个问题,我就这个问题做了一些规定。

  1. 除非是非常小的尺寸,否则不要使用实现[drawRect:]自定义视图。
  2. 使视图(有自己的内容,特别是标签)尽可能小。
  3. 不要使用背景图片。

点击空白区域以select单元格

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

小部件层次结构中的所有视图都倾向于具有透明背景( UIClearColor ),这意味着使得单元格可以轻易放置。 因为当用户触摸空白区域时,不会发生对小部件的整个命中testing。 (自定义命中testing只适用于至less没有透明的超级视图)有一些解决scheme:

  1. 使UILabel的宽度适合单元格:不要,它消耗更多的内存iPhone6 +或更宽和高分辨率的设备。
  2. 在自定义单元上实现空的[drawRect:] 。 不,这是轻松的透明控制解决scheme,但它需要绘图缓冲区。 记住每个设备的缓冲区大小会有所不同。

唯一的解决办法,我可以做到这一点,没有额外的内存消耗是设置小部件背景颜色为0.01阿尔法的黑色。 (它使命中testing工作)

 +-------------------+ | Table View |- backgorund-color: (0, 0, 0, 0.01) |+-----------------+| || Cell || ||+---------+ || 

UILabel +——++- make it small as possible as you can ||+———+ || |+—————–+| +——————-+

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

我喜欢jeeeyul答案 ,但很多时候扩展会崩溃( 无法加载 ),因为self.preferredContentSize设置不正确。

我已经通过在TodayViewController类中放置一个variables“currentHeight”来解决这个问题:

 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) ... } 

iPhone 6+的屏幕非常大,所以widget的宽度也很大。 而且widget的最大高度要比iPhone5大得多。

结果是,

由于分辨率的原因,iPhone6 +上的Widget比iPhone5多使用3〜4倍的video内存。 随着一些animation,它会增加更多。

但是,由于在显示小部件时保持活着的应用程序,iOS允许less量的内存部件。 (实际的限制没有logging)。

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

我认为这是错误。 另一个我的推论是,整个矩形将被caching用于核心animation,它会消耗内存。 那么iOS会杀死它。

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

这很简单:

  • Widget iPhone6 +需要更多的内存。
  • 然而,Widget的内存限制与iPhone5相同,实际上,因为在后台运行的应用程序需要更多的内存,所以比iPhone 5还要糟糕。

我可以肯定这是苹果的硬件devise失败。

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