在viewDidLoad之外启用横幅广告会导致旋转后布局不正确

3
我在使用一个iOS 8的应用时遇到了问题。我的应用需要从Web服务器获取信息以确定是否播放广告。这可能需要一段时间,因此,在viewDidLoad中的代码不会等待它,而是调用setCanDisplayBannerAds:NO。然后,一旦信息到达,就会在viewDidLoad之外调用setCanDisplayBannerAds:YES
我已经确定需要在viewDidLoad中调用setCanDisplayBannerAds:NO,否则setCanDisplayBannerAds:YES无法正确调用广告并生成大量内部异常。
问题在于一旦在viewdidLoad之外启用广告,布局就会出错。我在下面的两张图片中进行了说明。上面的是“before”,下面的是“after”,即在点击Show Ads之后。
请注意,在“before”图像中,Show AdsJust a Label都出现在它们各自的角落。在“after”图像中,横向方向不再正确。它保持纵向边界,Just a Label和横幅广告被裁剪掉。
我已向Apple提交了错误报告,并提供了一个可在DropBox上访问的示例项目,名称为ID19658866.zip。请随意下载并尝试。
如果有人能提供一些见解,以及可能的解决方案,而不必更改逻辑顺序,即在viewDidLoad完成之后再显示广告,那将不胜感激。
图片分别是“before *Show Ads* is tapped”和“after *Show Ads* is tapped”。
4个回答

3
将这两行代码放在viewdidLoad:中:
[self setCanDisplayBannerAds:YES];
[self setCanDisplayBannerAds:NO];

第一次调用正确设置广告,第二次立即确保它们不显示。稍后您可以调用[self setCanDisplayBannerAds:YES];,它将处理方向更改而无需问题。


2
说实话,Yimin Rong的答案可能有效,至少对于当前的SDK来说。但这感觉有点奇怪。它并没有真正解释为什么会有效。
查看setCanDisplayBannerAds:的文档,我们可以看到:

重要提示:这将通过在视图控制器上插入一个新的容器视图来修改视图层次结构。影响是视图控制器的视图属性将不再返回最初提供的视图,而将返回新的容器视图。要访问原始视图,请使用originalContentView属性。

所以它实际上替换了您的UIViewController的.view属性。请记住这一点。
当UIViewController显示在屏幕上时,它会被调整大小以适应整个屏幕(或者至少是它占用的容器)。因此,UIViewController的.view属性获得了一个自动调整大小掩码,即UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth,因此它的高度和宽度是灵活的,并且可以拉伸以适应容器。
当您在viewDidLoad中调用[self setCanDisplayBannerAds:YES];时,您的UIViewController的.view属性将被替换为一个新的UIView,并且由于它在viewDidLoad中,因此其autoresizingMask会被适当地设置。相反,在viewDidLoad中调用[self setCanDisplayBannerAds:NO];实际上什么也不做。
在您的示例应用程序中,当您在viewDidLoad之外调用[self setCanDisplayBannerAds:YES];时,我们可以看到autoresizingMask实际上没有被设置为拉伸。这就是问题所在:
- (IBAction)TouchUpInside:(id)sender {
    NSLog(@"Touch Up Inside");
    NSLog(@"Original View: %@", self.view);
    [self setCanDisplayBannerAds:YES];
    NSLog(@"New View: %@", self.view);
    NSLog(@"Content View: %@", self.originalContentView);
}

Output: 
2015-02-05 11:32:19.654 ID19658866[12404:3600041] Touch Up Inside
2015-02-05 11:32:19.655 ID19658866[12404:3600041] Original View: <UIView: 0x7f9c42717440; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f9c42717710>>
2015-02-05 11:32:19.666 ID19658866[12404:3600041] New View: <UIView: 0x7f9c42523fb0; frame = (0 0; 375 667); layer = <CALayer: 0x7f9c42524080>>
2015-02-05 11:32:19.666 ID19658866[12404:3600041] Content View: <UIView: 0x7f9c42717440; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f9c42717710>>

在输出的第三行中,“New View”没有包含“autoresize=W+H;”,这是关键点。我们还确认了在输出的第二行和第三行之间,self.view被一个新视图替换掉。为了解决这个问题,我们可以在调用“[self setCanDisplayBannerAds:YES];”后添加以下代码,确保新的self.view属性获得所需的autoresizingMask:
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

它会起作用,我们也会知道为什么。

或者,你知道的...只需在viewDidLoad中调用[self setCanDisplayBannerAds:YES];来替换self.view属性,这样它就会自动设置正确的autoresizingMask


谢谢。我认为有一个错别字,在一半的地方,段落开头是:“在您的示例应用程序中,当您调用…”,我认为应该是 [self setCanDisplayBannerAds:YES]; 而不是 NO - user2191247
啊,你说得对;已经修复了。问题在于使用 YES 调用它会改变视图层次结构,因此在 viewDidLoad 之外调用它不会像应该设置的那样设置 autoresizingMask - cjwirth
我注意到一件事情,如果在viewDidLoad中没有调用setCanDisplayBannerAds:,然后稍后启用广告,广告将不会显示,并且会生成许多与代理相关的异常,因此可能涉及更多内容而不仅仅是自动调整大小。 - user2191247
是的。有一个名为 _ADUIViewControllerAdController 的私有 API 类,它在您第一次调用 setCanDisplayBannerAds: 时实例化并连接到您的视图控制器(无论您是否传递 YESNO)。这仍然必须在显示之前调用(即在 viewDidLoad 中)。然后稍后,您可以再次使用 YES 调用它,一切都将正常工作。然而,拉伸的问题在于 autoresizingMask - cjwirth
保持你的示例项目不变,但是在 TouchUpInside: 中添加自动调整大小的代码行,而不要从 viewDidLoad 中删除 setCanDisplayBannerAds:YES,这样它就可以工作了。 - cjwirth
你的意思是在viewDidLoad中不去掉setCanDisplayBannerAds:NO吗? - user2191247

1

完全是猜测,但是当广告出现时,如果调用setNeedsLayout或setNeedsUpdateConstraints(假设您正在使用自动布局,我认为您正在使用),会发生什么?此外,请确保广告视图与其他视图之间的约束正确设置。这可能不是正确的答案,但我希望它能提供一些有关真正问题/解决方案的额外见解。


谢谢,我已经尝试过单独和组合使用setNeedsUpdateConstraintssetNeedsLayoutsetNeedsDisplay,但布局错误仍然存在。由于涉及iAds,希望能尽快得到苹果的回复。 - user2191247
是的,我很有信心这些不会是解决方案,但我希望你能看到一些可能会为真正的问题/解决方案带来额外启示的东西。无论你发现什么,我希望你能回来更新你的帖子,分享你最终学到的东西。谢谢伙计。 - BonanzaDriver
这可能应该是一条注释。将答案保留给真正的回答,而不是猜测来获取积分。 - jww

0
坦白说,Yimin Rong的solution是所有可用方案中最好的。然而,如果这是高级账户和标准账户类型的问题,最好的方法是将变量存储在本地,并让用户点击“恢复购买”按钮。这样,即使用户离线,您也可以显示广告(如果它们被本地存储),当他们上线时,您可以从广告商那里获得利润。祝您的应用程序好运!

谢谢。同意使用本地变量会更好,但不想太大幅度修改现有逻辑。这是第一次使用内置横幅广告的发布版。同时也同意荣一民的解决方案最为简洁,但我喜欢 cjwirth 提供的研究工作。 - user2191247

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接