简体   繁体   English

iAd冻结Sprite Kit应用程序

[英]iAd freezes Sprite Kit app

I find that tapping on iAds can freeze the screen on any Sprite Kit game. 我发现点击iAd可以冻结任何Sprite Kit游戏的屏幕。 It's not just my specific project, since the stock Sprite Kit example project also freezes with iAd. 这不仅是我的特定项目,因为库存Sprite Kit示例项目也随iAd冻结。 This does not happen in the simulator though! 但是,这不会在模拟器中发生! I cannot decide whether if it's because the simulator runs iOS 8 and my actual testing device is on 7.1, or because of the fact that the simulator is just a simulator so it does things differently. 我无法确定是因为模拟器运行iOS 8且我的实际测试设备位于7.1上,还是因为模拟器仅仅是一个模拟器,所以它所做的事情有所不同。

So if you tap on the iAd then click on the link in the iAd to go to safari (or manually switch over to any app at this point), then switch back to the Sprite Kit app, the app is frozen. 因此,如果您点击iAd,然后单击iAd中的链接以进行野生动物园(或此时手动切换到任何应用),然后再切换回Sprite Kit应用,则该应用将被冻结。 The iAd banner is still live, and it loads ads just how it's supposed to. iAd标语仍然有效,并且按预期加载广告。 But the rest of the app is frozen. 但是该应用程序的其余部分已冻结。 Or to be specific, It still receives touches and stuff (I can see from NSLog s) but the rendering of the nodes is frozen. 更具体地说,它仍然可以接收触摸和填充(我可以从NSLog看到),但是节点的呈现被冻结了。 If you open up iAd again by tapping on it, and close the iAd, then the app resumes somehow and it works again just fine. 如果您通过点击再次打开iAd,然后关闭iAd,则该应用会以某种方式恢复运行,并且可以正常运行。

If you're curious, here are the ONLY modifications that I did to the stock Sprite Kit example project: 如果您好奇,这是我对Sprite Kit示例项目所做的唯一修改:

// in GameViewController.h
#import <iAd/iAd.h>

@interface GameViewController : UIViewController <ADBannerViewDelegate>
@end


// in GameViewController.m
@interface GameViewController() {
    ADBannerView*       iAdBanner;
    NSLayoutConstraint* centerAd;
}
@end

@implementation GameViewController
- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure iAd
    iAdBanner           = [[ADBannerView alloc] initWithFrame:CGRectZero];
    iAdBanner.alpha     = 0.0;
    iAdBanner.delegate  = self;
    centerAd            = [NSLayoutConstraint constraintWithItem:iAdBanner
                                                   attribute:NSLayoutAttributeCenterX
                                                   relatedBy:NSLayoutRelationEqual
                                                      toItem:self.view
                                                   attribute:NSLayoutAttributeCenterX
                                                  multiplier:1.0
                                                    constant:0.0];
    [self.view addSubview:iAdBanner];
    [self.view addConstraint:centerAd];

    // The rest of viewDidLoad is the stock code. I'm not pasting that in...
}

// iAd delegate methods

-(void) bannerViewDidLoadAd:(ADBannerView *)banner {
    // fade in iAd banner
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.5];
    [banner setAlpha:1.0];
    [UIView commitAnimations];
}

-(void) bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
    NSLog(@"iAd error: %@", error.localizedDescription);
    banner.alpha = 0.0;
}

Plus I set the deployment target to 7.1 (and obviously include the iAd framework in the project). 另外,我将部署目标设置为7.1(并且显然在项目中包括了iAd框架)。

As you can see, I'm not doing anything to the app that could cause this crash. 如您所见,我没有对可能导致此崩溃的应用程序执行任何操作。 I simply add the iAd banner and that's it. 我只需添加iAd横幅即可。 So the problem is not in my code. 因此,问题不在我的代码中。 This must be a bug in Apple's frameworks. 这一定是Apple框架中的错误。

Does anyone know a workaround? 有谁知道解决方法? I have found several topics on this on the internet, but nobody could suggest a working solution. 我在互联网上找到了一些与此相关的主题,但是没有人可以提出可行的解决方案。

EDIT: 编辑:

I found out that iOS 7.1 on my device calls bannerViewActionDidFinish: when returning to the app . 我发现我的设备上的iOS 7.1在返回应用程序时调用bannerViewActionDidFinish: iOS 8 in the simulator however, calls that method before leaving the app (exactly when you leave the app to be exact). 但是,模拟器中的iOS 8会在离开应用程序之前调用该方法(确切地说,确切地说是在离开应用程序时)。 That doesn't directly affect the code posted above, since it doesn't implement this method. 这不会直接影响上面发布的代码,因为它没有实现此方法。 But it does indicate that the iAd implementations iOS 7.1 and iOS 8 do things differently. 但这确实表明iAd实现iOS 7.1和iOS 8的功能有所不同。

--- Final answer in EDIT 2 --- - 编辑2的最终答案 -

Well I did read about this before, and I did try it, but seems like I failed when I tried it earlier. 好吧,我之前确实读过关于此的内容,并且确实尝试过,但是当我较早尝试时似乎失败了。 I tried it again and it works now. 我再次尝试过,现在可以使用了。

So what you want to do is set the canDisplayBannerAds property of your view controller to YES , then use the originalContentView property instead of the normal view one to set up your SKView . 因此,您要做的是将视图控制器的canDisplayBannerAds属性设置为YES ,然后使用originalContentView属性而不是普通view设置SKView Or if you want to access your view from inside a scene, that would be: self.view.window.rootViewController.originalContentView . 或者,如果您想从场景内部访问视图,则为: self.view.window.rootViewController.originalContentView So basically any time you need to do something with your view that is specific to SKView (like transition to a scene) and what cannot be done with a regular UIView then use scene.view.window.rootViewController.originalContentView instead of just scene.view . 因此,基本上,任何时候您都需要对视图进行特定于SKView (例如过渡到场景),而常规UIView无法完成的操作则使用scene.view.window.rootViewController.originalContentView而不是仅仅scene.view The reason for this is that iAd somehow explicitly casts your view as UIView when you set the canDisplayBannerAds property in your view controller, so you cannot use the SKView methods on your view anymore. 原因是当在视图控制器中设置canDisplayBannerAds属性时,iAd会以某种方式将视图明确转换为UIView ,因此您将无法再在视图上使用SKView方法。 The originalContentView is a workaround for this. originalContentView是解决此问题的方法。

This totally solved my problem, the app returns to its normal state now. 这完全解决了我的问题,该应用现在恢复到正常状态。

EDIT: 编辑:

Nope, it didn't solve my problem. 不,这没有解决我的问题。 :( :(

Switching to another app and back while an ad is open now doesn't freeze the app. 现在,在打开广告的同时切换到另一个应用程序并不会冻结该应用程序。 Good. 好。 But simply opening and closing an ad now freezes it the same way. 但是,现在只需打开和关闭广告就可以冻结广告。 This makes no sense... 这没有道理...

So if I don't set canDisplayBannerAds in my view controller, then leaving the app and coming back is the case when the app freezes. 因此,如果我未在视图控制器中设置canDisplayBannerAds ,则在应用程序冻结时会离开应用程序并返回。 But just opening and closing an ad works fine. 但是只是打开和关闭广告就可以了。 But if I do set canDisplayBannerAds , then it's the other way around. 但是,如果我确实设置了canDisplayBannerAds ,那么canDisplayBannerAds

This really makes no sense. 这真的没有道理。 I'm very confused now... 我现在很困惑

EDIT 2 (actual solution): 编辑2(实际解决方案):

Finally I solved it! 终于我解决了! But it wasn't easy god damn it... So the problem was in the view hierarchy. 但是,天哪,这不是一件容易的事……所以问题出在视图层次结构中。 If I add the ADBannerView as a subview of my main view, then it freezes the app. 如果我将ADBannerView添加为主视图的子视图,则它将冻结该应用程序。 This is strange, since that's the suggested method to add a banner to the screen. 这很奇怪,因为这是将标语添加到屏幕的建议方法。 If I don't add the banner as as subview manually, it sill appears on the screen though! 如果我没有将横幅手动添加为子视图,则它仍会出现在屏幕上! I guess iAd is implemented in a way that once initialized, it will display itself on the screen no matter what. 我猜iAd的实现方式是一旦初始化,无论如何它都会在屏幕上显示自己。 It appears a bit differently though. 看起来却有些不同。 If it's not a subview of any view, then it comes in from the bottom with a "slide up" animation, resizing everything to a smaller box that's above it. 如果它不是任何视图的子视图,那么它将从底部以“向上滑动”动画出现,将所有内容调整为上方的一个较小的框。 This is a default behavior of an iAd banner I guess. 我猜这是iAd标语的默认行为。 So this way it doesn't freeze the screen, it works just fine! 因此,这种方式不会冻结屏幕,效果很好! But since I wanted a bit more control over the banner (like animating it myself, instead of leaving that to the banner itself) I did the following: 但是由于我想要对横幅进行更多控制(例如自己制作动画,而不是将其留给横幅本身),所以我执行了以下操作:

In my view controller, I created an instance of SKView (NOT by casting self.view as SKView as usual, but a completely new instance). 在我的视图控制器,我创建的实例SKView (没有因铸造self.view作为SKView像往常一样,但一个完全新的实例)。 Then I added that as a subview of self.view . 然后我将其添加为self.view的子视图。 After that, I initialize the ADBannerView , and add it as a subview of self.view as well. 在那之后,我初始化ADBannerView ,并将其添加为一个子视图self.view为好。 Note that self.view is not directly displaying anything, I use it as a "container" to hold the other two. 注意self.view不会直接显示任何内容,我将其用作容纳其他两个的“容器”。 The view hierarchy then looks something like this: 然后,视图层次结构如下所示:

        self.view
        /        \
    SKView    ADBannerView

This way the ADBannerView is not the direct subview or superview of my SKView (which is the main view my game uses) so it cannot screw it up because it doesn't have a concept of that view since they are both subviews of the same view. 这样, ADBannerView并不是我的SKView的直接子视图或超级视图(这是我的游戏使用的主视图),因此它无法搞砸,因为它没有该视图的概念,因为它们都是同一个视图的子视图。 At this point I have no idea whether you need to set canDisplayBannerAds in your view controller or not. 目前,我不知道是否需要在视图控制器中设置canDisplayBannerAds I have it set, and it works. 我已经设置好了,而且有效。 I didn't try leaving that out. 我没有尝试过把它排除在外。

In a nutshell, I have full control of the banner view as well as my game view, and they can't mess with each other since they are not in a subview/superview relationship. 简而言之,我可以完全控制横幅视图和游戏视图,并且由于它们不在子视图/超级视图关系中,因此它们不会彼此混乱。

This was very tough to figure out, but here you go. 这很难弄清楚,但是到这里开始。 If you also have problems with iAd and Sprite Kit, just organize your views like this. 如果您在iAd和Sprite Kit方面也遇到问题,只需像这样整理视图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM