This is a Swift 2.1 project with an iOS 8.0+ target.
Much like user Cybermew in this question, I have a set-up where A->B->C->D. A is a navigation controller and the rest are regular UIViewControllers. When unwinding from D to B, C does not get released. This results in a memory leak and other unintended side-effects.
As opposed to the question linked above, I don't have any NSTimer that I know of that might keep the view in memory. What could be causing this to happen?
Code of C (trimmed):
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()
}
}
Moved here from chat:
swipeHandler
is declared as:
var swipeHandler: ((Swap) -> ())?
and swap is:
struct Swap: CustomStringConvertible, Hashable {
// blabla
}
and once filled with a swap if calls this on the 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
}
}