在这里,我正在玩泄漏,所以我有意识地做了一个强大的参考周期,看看仪器是否会检测到某些东西,我得到了意想不到的结果.仪器中显示的泄漏确实有意义,但随机崩溃有点神秘(由于我将在后面提到的两个事实).

我这里有一个名为SomeClass的类:

class SomeClass{

    //As you can guess,I will use this shady property to make a strong cycle :)
    var closure:(()->())?
    init(){}
    func method(){}
    deinit {print("SomeClass deinited")}
}

我还有两个场景,GameScene:

class GameScene: SKScene {

    override func didMovetoView(view: SKView) {

        backgroundColor = .blackColor()

        let someInstance = SomeClass()

        let closure = {[uNowned self] in

            someInstance.method() //This causes the strong reference cycle...
            self.method()  
        }
        someInstance.closure = closure
    }

    override func touchesBegan(touches: Set<UITouch>,withEvent event: UIEvent?) {

        if let nextScene = MenuScene(fileNamed: "MenuScene"){
            nextScene.scaleMode = .AspectFill
            let transition = SKTransition.fadeWithDuration(1)
            view?.presentScene(nextScene,transition: transition)
        }
    }

    deinit {print("GameScene deinited")}

    func method(){}
}

最后,MenuScene与GameScene完全相同,只是使用了一个空的didMovetoView方法(它只实现了touchesBegan方法).

再现崩溃

可以通过在场景之间转换几次来重现崩溃.通过这样做,泄漏将发生,因为someInstance由闭包变量保留,并且闭包变量由someInstance变量保留,因此我们有一个循环.但是,这仍然不会产生崩溃(它只会泄漏).当我真的尝试在闭包内添加self.method()时,应用程序崩溃了,我得到了这个:

还有这个:

如果我试图在它引用的对象被释放时尝试访问无主参考,我可以产生完全相同的崩溃,例如.当闭包超过捕获的实例时.这是有道理的,但这不是这里的情况(封闭永远不会执行).

神秘的部分

神秘的部分是这次崩溃只发生在iOS 9.1而不是iOS9.3上.另一个神秘的事情是,应用程序随机崩溃,但大多数在前十个转换中.此外,奇怪的部分是如果从不执行闭包,或者没有访问它捕获的实例(至少不是我),它崩溃的原因.

问题的解决方案而不是问题的答案

当然崩溃可以通过几种方式解决周期,我知道只有当我完全确定捕获的实例在初始化后永远不会变为零时我才应该使用uNowned.但是,由于事实上我没有完成这个关闭,在它失去现场之后,这次崩溃对我来说非常尴尬.此外,值得一提的是,每次过渡后场景都会成功消失.

有趣

如果我在捕获列表中使用弱自我,应用程序将不会崩溃(当然泄漏仍然存在).这是有道理的,因为如果在取消分配块之前场景变为零,则通过可选链接访问场景将防止崩溃.但有趣的是,即使我使用这样的强制解包,它也不会崩溃:

let closure = {[weak self] in
      someInstance.method() 
      self!.method()  
}

这让我觉得……欣赏有关如何调试此内容的任何提示或有关导致崩溃的原因的解释……

编辑:

这是Github repo

解决方法

崩溃正在发生,因为GameScene对象已在动画结束前发布.

实现这一点的一种方法是将SomeClass对象传递回闭包中.

class SomeClass {
    var closure: (SomeClass->Void)?
}

将使用这样:

override func didMovetoView(view: SKView) {
    let someInstance = SomeClass()
    someInstance.closure = { [uNowned self] someClass in
        someClass.method() // no more retain cycle
        self.method()
    }
}

UPDATE

事实证明,这是一个细微差别的组合在一起?(fileNamed :)滥用[无主自我]造成你的崩溃.

虽然官方文档似乎没有说明,但正如在blog post中简要解释的那样,便利初始化器实际上将重用相同的对象.

File References

The scene editor allows you to reference content between different .sks (scene) files,meaning you can put together a bunch of sprites in a single scene file and then reference the file from another scene file.

You might wonder why you would need more than one scene,and there a couple of reasons:

1) You can reuse the same collection of sprites in multiple different scenes,meaning you don’t have to recreate them over and over again.

2) If you need to change the referenced content in all of your scenes,all you have to do is edit the original scene and the content automatically updates in every scene that references it. Smart,right?

在创建周围添加日志记录,设置闭包和deinit会产生一些有趣的输出:

GameScene init: 0x00007fe51ed023d0
GameScene setting closure: 0x00007fe51ed023d0
MenuScene deinited
GameScene deinited: 0x00007fe51ed023d0
GameScene init: 0x00007fe51ed023d0
GameScene setting closure: 0x00007fe51ed023d0

注意两次使用相同的内存地址.我假设在引擎盖下苹果正在做一些有趣的内存管理以进行优化,这可能导致在deinit之后仍然存在过时的关闭.

可以对SpriteKit的内部进行更深入的挖掘,但是现在我只用[弱自我]替换[无主自我].

ios – 使用捕获列表中的无主内容导致崩溃,即使块本身也不会执行的更多相关文章

  1. ios – Swift中的UIView动画不起作用,错误的参数错误

    我正在尝试制作动画并使用下面的代码.我得到“无法使用类型’的参数列表调用’animateWithDuration'(FloatLiteralConvertible,延迟:FloatLiteralConvertible,选项:UIViewAnimationoptions,动画:()–>()–>$T4,完成:(Bool)–>(Bool)–>$T5)’“错误.这意味着我使用了错误的参数.我错了.请

  2. ios – 使用捕获列表中的无主内容导致崩溃,即使块本身也不会执行

    欣赏有关如何调试此内容的任何提示或有关导致崩溃的原因的解释……

  3. ios – Swift传递封闭与Params

    目前我传递一个闭包作为一个对象的属性,该对象不接受参数并且没有返回值,如下所示:到目前为止,这工作得很好.我希望能够在设置此闭包时传入一个参数,以便在MyClass的实例中使用.我正在寻找下面的SOMETHING,虽然我确定语法不正确:我如何将参数传递给可以在MyClass中使用的闭包–即可以在属性本身的didSet部分内使用的值,如第二个示例中所示?

  4. ios – 来自UIAlertController的self.navigationController?.popViewControllerAnimated

    我是新手,但我想我已经掌握了它.这让我的进步很难过.我想要做的是当我们无法找到他的查询的相关数据时向用户抛出错误消息,然后继续将他带回到之前的ViewController.但是,我在这方面遇到了麻烦.在我添加操作的行上,我收到以下错误:’UIViewController?’不是Void的子类型我该怎么做呢?

  5. ios – 如何添加@noescape注释到可选闭包

    我的功能有这个签名:而现在我想让自己在给定的关闭中逃脱自我.但是当我尝试这个:编译器抱怨:是否可以在可选参数中使用它?

  6. ios – Swift闭包为AnyObject

    如何将()–>()转换为AnyObject?我试图将它转换为:处理程序为AnyObject,但它给我一个错误说:()–>()不符合协议’AnyObject’解决方法HowcanIcast()->()intoAnyObject?

  7. ios – 在swift中将捕获列表正确放置在嵌套闭包中

    在Swift中为哪些嵌套闭包定义捕获的引用?如果[weakself]被捕获在只有内部最后面的闭包,GCD将保留ExampleDataSource,直到块完成执行,这就解释了为什么调试看起来像这样:同样的事情会发生,如果没有捕获列表被包括,我们从来没有可选地解开自己,尽管编译器,确实试图警告你!

  8. ios – 两个类,回调和单元测试

    而且,我不觉得这样的行为会很容易测试?

  9. 寒城攻略:Listo 教你 25 天学会 Swift 语言 - 18 Automatic Reference Counting

    //每个Person类的实例拥有一个被初始化为nil的apartment可选属性,因为一个人并不一定拥有一座公寓)}}classApartment{letnumber:Intinit{number=number}tenant:Person1?//声明Apartment2类中的tenant属性为弱引用varPin:Person2?鉴于这种关系,Customer类有一个可选类型属性card,而CreditCard类的customer属性则是非可选类型的classCustomer{varcard:CreditC

  10. 【Swift初见】Swift闭包

    闭包是功能性自包含模块,可以在代码中被传递和使用。闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。闭包的函数体部分由in关键字引入,in后面就是代表该闭包的函数体部分。swift函数有类型推断的功能,排序闭包又是作为函数的参数传入的,那么swift可以推断出它的参数和返回值类型,那么sorted函数可以改写为:我们可以看出得出的结果还是一样的。单行表达式闭包可以通过隐藏return关键字来隐式返回表达式的结果。

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部