【问题标题】:Unwind segue (D->B) does not release CUnwind segue (D->B) 不释放 C
【发布时间】:2025-11-23 21:40:01
【问题描述】:

这是一个带有 iOS 8.0+ 目标的 Swift 2.1 项目。

很像this question 中的用户 Cyber​​mew,我有一个 A->B->C->D 的设置。 A 是一个导航控制器,其余的是常规的 UIViewControllers。当从 D 展开到 B 时,C 不会被释放。这会导致内存泄漏和其他意想不到的副作用。

与上面链接的问题相反,我没有任何我知道的 NSTimer 可能会将视图保留在内存中。什么可能导致这种情况发生?

C 代码(修剪):

import UIKit
import SpriteKit
import AVFoundation
import AVFoundation.AVAudioSession

class GameViewController: UIViewController {

var scene: GameScene!
var level: Level!

@IBOutlet weak var gameOverPanel: UIImageView!
@IBOutlet weak var heroPicture: UIImageView!
@IBOutlet weak var villainPicture: UIImageView!
@IBOutlet weak var spellOneButton: UIButton!
@IBOutlet weak var doubleLife: UISwitch!

let attackSound = SKAction.playSoundFileNamed("Attack.wav", waitForCompletion: false)

var tapGestureRecognizer: UITapGestureRecognizer!

var backgroundMusic: AVAudioPlayer = {

    let sess = AVAudioSession.sharedInstance()
    if sess.otherAudioPlaying {
        _ = try? sess.setCategory(AVAudioSessionCategoryAmbient, withOptions: [])
        _ = try? sess.setActive(true, withOptions: [])
    }

    let url = NSBundle.mainBundle().URLForResource("BackgroundMusic", withExtension: "mp3")
    let player = try? AVAudioPlayer(contentsOfURL: url!)
    player!.numberOfLoops = -1

    return player!
}()

override func prefersStatusBarHidden() -> Bool {
    return true
}

override func shouldAutorotate() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.AllButUpsideDown
}

override func viewDidLoad() {
    super.viewDidLoad()

    let skView = view as! SKView
    skView.multipleTouchEnabled = false

    scene = GameScene(size: skView.bounds.size)
    scene.scaleMode = .AspectFill

    level = Level(filename: "Level_0")
    scene.level = level
    scene.addTiles()
    scene.swipeHandler = handleSwipe

    skView.presentScene(scene)
    backgroundMusic.play()
    beginGame()
}
}

从聊天移到这里:

swipeHandler 声明为:

var swipeHandler: ((Swap) -> ())?

而交换是:

struct Swap: CustomStringConvertible, Hashable { 

    // blabla
}

如果在GameViewController 上调用它,则一旦填充了交换:

func handleSwipe(swap: Swap) { 

    view.userInteractionEnabled = false 

    if level.isPossibleSwap(swap) { 
        level.performSwap(swap) 
        scene.animateSwap(swap, completion: handleMatches) 
    } else { 
        scene.animateInvalidSwap(swap) { 
        self.view.userInteractionEnabled = true 
    } 
} 

【问题讨论】:

  • C 是否包含对 B 的强引用?
  • 不幸的是它没有。
  • C 是如何创建的?你能发布 C 的代码吗?
  • 描述已更新。我删除了一些占用大量空间并且很可能无关紧要的部分(变量的初始化)。
  • 尝试注释掉部分代码,减少功能,直到找到罪魁祸首。尝试先注释掉提供和播放背景音乐的代码。

标签: ios swift memory segue


【解决方案1】:

你有一个引用循环导致你的 viewController 没有被释放。我建议将swipeHandler 转换为弱委托指针,您可以通过该指针调用handleSwipe。这样一来,您的 GameScene 将不会保留任何指向 GameViewController 的强指针,这将允许在执行展开转场时释放它。

protocol SwipeHandler: class {
    func handleSwipe(swap: Swap)
}

class GameViewController: UIViewController, SwipeHandler {

    var level = Level()
    var scene: GameScene!

    override func viewDidLoad() {
        super.viewDidLoad()

        scene = GameScene()
        scene.swipeHandler = self
    }

    func handleSwipe(swap: Swap) {
        // ...    
    }
}

class GameScene {
    weak var swipeHandler: SwipeHandler?

    // function to demonstrate call to handleSwipe
    func useSwipeHandler() {
        let swap = Swap()
        swipeHandler?.handleSwipe(swap)
    }
}

【讨论】:

  • 工作就像一个魅力!非常感谢。
最近更新 更多