0

Explanation

I'm trying to build a simple email code in separate swift files (in this case: GameViewController.swift and MailViewController.swift).

What should happen: I gotta touch the screen in GameViewController to call MailViewController, and when canceling or sending an email, it shall go back to GameViewController.

What is happening: It calls MailViewController and go back when touching Cancel or Send, but only once. When I try to do it again (even when closing and opening the app again) a black screen shows up when trying to get back to GameViewController.


Code

You can download the code below by clicking here.

GameViewController

import UIKit
import SpriteKit

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set view size.
        let scene = GameScene(size: view.bounds.size)

        // Configure the view.
        let skView = view as! SKView
        skView.showsFPS = true
        skView.showsNodeCount = true

        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView.ignoresSiblingOrder = true

        /* Set the scale mode to scale to fit the window */
        scene.scaleMode = .ResizeFill

        skView.presentScene(scene)

        //Register mail observer (so I can call from GameScene)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.openMailViewController), name: "openMailViewController", object: nil)
    }

    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return .Landscape
        } else {
            return .Landscape
        }
    }
}

extension GameViewController{

    func openMailViewController(){
        self.performSegueWithIdentifier("openMailViewController", sender: self)
    }
}

MailViewController

import UIKit
import SpriteKit
import MessageUI

class MailViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.openMailController()
    }

    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return .AllButUpsideDown
        } else {
            return .All
        }
    }
}

//Mail
extension MailViewController: MFMailComposeViewControllerDelegate {

    func openMailController() {

        let mailComposerVC = MFMailComposeViewController()
        mailComposerVC.mailComposeDelegate = self //extremely important to set the mailComposeDelegate property, not the delegate property

        self.presentViewController(mailComposerVC, animated: true, completion: nil)
    }

    func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {

        //dismiss mail
        self.dismissViewControllerAnimated(true, completion: nil)

        //go back to the game
        backToGameViewController()
    }
}

extension MailViewController{

    func backToGameViewController(){
        self.performSegueWithIdentifier("backToGameViewController", sender: self)
    }
}

Main.storyboard

enter image description here


Thanks in advance,
Luiz.

Luiz
  • 1,275
  • 4
  • 19
  • 35

2 Answers2

1

Try removing the reverse segue back in the storyboard from the MailViewController to the GameViewController. And in your MailViewController, use this function to go back:

func backToGameViewController(){
    dismissViewControllerAnimated(true, completion: nil)
}

Change the function to following :

func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {

        //dismiss mail
        self.dismissViewControllerAnimated(true) {
            //go back to the game
            self.backToGameViewController()
        }

    }

Also try this on your device, not on the simulator. Simulator returns an error while trying to open the MFMailComposeViewController.

A segue creates a new object, and pushes that on the stack, you would not want to create repeated stacks of objects on top of each other..

Hope this helps.

vj9
  • 1,546
  • 1
  • 11
  • 18
  • I tried to do it, but it isn't closing `MailViewController`. A white screen shows up when I, for example, cancel an email. You can see it in [this](http://i.imgur.com/mgoVcAL.png) image. – Luiz Sep 09 '16 at 23:41
  • Call backToGame in the completion of the MailCompose dismiss. Also, try this on a device, not on the simulator. The simulator gives an error while opening the MFMailComposeViewController – vj9 Sep 10 '16 at 06:31
  • I just did! I worked!! Buuuuuut its quite slow when dismissing two view controllers. Since I can't present `MFMailComposeController` directly from `GameViewController`, because I need this mail to have different orientations, is there any other way to open only `MFMailComposeController`? I mean, when touching the screen it opens `MFMailComposeController` directly, instead of opening `MailViewController` and then `MFMailComposeController`. – Luiz Sep 10 '16 at 13:53
1

If you replace

self.performSegueWithIdentifier("backToGameViewController", sender: self)

with

self.dismissViewControllerAnimated(true, completion: nil)

your code will work, but I don't think it's actually what you want to do.

The reason this works is from your game controller you're presenting MailViewController, which is then presenting an MFMailComposeViewController. Since you're presenting two at once, you're getting an odd double animation where a blank view slides up before the mail view slides up. In order to fully dismiss the mail views then, you need to call dismissViewController twice.

A better approach would be to present the MFMailComposeController directly from GameController.

charmingToad
  • 1,597
  • 11
  • 18
  • I tried to do it (as you can see [here](http://i.imgur.com/mgoVcAL.png)), but it didn't work. A white screen shows up when I, for example, cancel an email. – Luiz Sep 09 '16 at 23:43
  • Don't remove your previous dismissViewController. You've presented twice, so you need to dismiss twice. http://imgur.com/a/7Yw4H – charmingToad Sep 10 '16 at 10:12
  • It worked!! Buuuuuut its quite slow when dismissing two view controllers. Since I can't present `MFMailComposeController` directly from `GameViewController`, because I need this mail to have different orientations, is there any other way to open only `MFMailComposeController`? I mean, when touching the screen it opens `MFMailComposeController` directly, instead of opening `MailViewController` and then `MFMailComposeController`. – Luiz Sep 10 '16 at 13:51
  • That's going to be tricky... this post might help: http://stackoverflow.com/questions/26357162/how-to-force-view-controller-orientation-in-ios-8 – charmingToad Sep 10 '16 at 17:17