【问题标题】:Destroy previous viewController when presenting a new one在呈现新视图控制器时销毁先前的视图控制器
【发布时间】:2015-10-25 07:36:05
【问题描述】:

我有一个带有 sideBarMenu 的应用程序,它有五个部分。在我的故事板中,我创建了嵌入在 NavigationController 中的启动 MainViewController。然后我创建了相同的五个 VC,并再次将它们嵌入到 NavigationController 中。所以我有 6 个 VC,每个都封装在自己的 NavigationController 中。

每个 VC 都使用具有所选菜单索引的函数实现 sideBarDelegate。

代码如下:

// SideBarTableViewController

protocol SideBarTableViewControllerDelegate {
    func SideBarControlDidSelectRow(indexPath: NSIndexPath)
}

class SideBarTableViewController: UITableViewController {

// ...

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        tableView.deselectRowAtIndexPath(indexPath, animated: false)
        println(indexPath.row)
        delegate?.SideBarControlDidSelectRow(indexPath)
    }
}


// SideBar class ------------------------------------------------

@objc protocol SideBarDelegate {
    func SideBarDidSelectButtonAtIndex(index: Int)
    optional func SideBarWillClose()
    optional func SideBarWillOpen()
}

class SideBar: NSObject, SideBarTableViewControllerDelegate {

// ...

    func SideBarControlDidSelectRow(indexPath: NSIndexPath) {
        println(indexPath.row)
        delegate!.SideBarDidSelectButtonAtIndex(indexPath.row)
    }
}

然后在这个函数中我想呈现需要的 ViewController:

func SideBarDidSelectButtonAtIndex(index: Int) {
    presentViewControllerByIndex(index)
}

func presentViewControllerByIndex(index: Int) {
    let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    switch index {
    case 0:
        var viewController = storyBoard.instantiateViewControllerWithIdentifier("SearchVC") as! SearchViewController
        viewController.delegate = self
        self.presentViewController(viewController, animated: false, completion: nil)
        break

    // the same code here for other 4 VC's with their StoryboardId's

    default: break
    } 
}

然后在呈现的视图控制器中,如果用户在菜单中选择另一个部分,我应该在呈现选定的视图控制器之前销毁这个 VC 吗?因为当我运行我的应用程序并开始在控制器之间切换时,xCode 中的应用程序内存会增加 (screenshot)。

当我看到我开始搜索并找到this 答案时。所以我在我的第一个菜单 VC 中创建了一个协议,只是为了测试。

protocol myProtocol {
    func dissmissAndPresend(index: Int) -> Void
}

当我需要介绍新的 VC 时,我只需致电:

self.delegate?.dissmissAndPresend(index)

然后在我的 MainVC 中,我实现了这个协议并尝试关闭以前的 VC 并呈现新的:

class MainViewController: UIViewController, SideBarDelegate, myProtocol {

func dissmissAndPresend(index: Int) {
    self.dismissViewControllerAnimated(false, completion: {
        self.presentViewControllerByIndex(index)
    })
}

现在,当我启动我的程序并开始单击第一个菜单项时,它会打开新的 VC,但我的内存仍像以前一样增加。并且显示视图的导航控制器已经消失,但在故事板中显示的 VC 嵌入在导航控制器中。

我做错了什么?有人可以帮我吗?

更新::--------------------------------------------

这是我尝试过的:

class MainViewController: UIViewController, SideBarDelegate, searchVCProtocol {
    var searchVC: SearchViewController!
    var searchNavController: ShadowUINavigationController!

    override func viewDidLoad() {
        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        searchVC = mainStoryboard.instantiateViewControllerWithIdentifier("SearchVC") as! SearchViewController
        searchVC.delegate = self
        searchNavController = ShadowUINavigationController(rootViewController: searchVC)
    }

    func SideBarDidSelectButtonAtIndex(index: Int) {
        switch index {
        case 0:
            println("asda")
            self.presentViewController(searchNavController, animated: false, completion: nil)
            break
        }
    }

然后它将用户带到 SearchViewController,如果用户再次打开菜单并再次单击 SearchViewController 会怎样。我怎样才能将其关闭并重新打开。这是我尝试过的方法,但它不起作用:

在 SeachViewController 我创建了一个协议:

protocol searchVCProtocol {
    func dismissAndPresent(index: Int) -> Void
}

然后我为委托添加了一个变量:

var delegate: searchVCProtocol?

然后当用户选择菜单项时,它会触发此事件:

func SideBarDidSelectButtonAtIndex(index: Int) {
    delegate?.dismissAndPresent(index)
}

在 MainViewController 中,我实现了这个协议并创建了 dismissAndPresent 方法,但我不知道如何重新启动呈现的 viewController。

class MainViewController: UIViewController, SideBarDelegate, searchVCProtocol {
    func dismissAndPresent(index: Int) {
        // code to restart this VC
    }
}

我应该编写什么代码来重新启动提供的 VC?

【问题讨论】:

    标签: ios swift protocols delegation presentviewcontroller


    【解决方案1】:

    您每次都在调用 instantiateViewControllerWithIdentifier,这会在每次新的 ViewController 时创建(“实例化”)。最好只执行一次,保留对它的引用,然后根据需要重新使用它。

    您可以在此处保留参考。首先,您在类级别创建一个新变量:

    class MyClass {
        var viewController: SearchViewController!
    

    然后,在 viewDidLoad 中,实例化视图控制器并将其分配给变量。

    func viewDidLoad() {
        viewController = storyBoard.instantiateViewControllerWithIdentifier("SearchVC") as! SearchViewController
    }
    

    viewDidLoad 仅被调用一次,因此您创建多个实例时不会再发生。

    然后你可以一次又一次地重用这个视图控制器:

    func presentViewControllerByIndex(index: Int) {
        let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        switch index {
        case 0:
            // Here you can reuse the formerly created viewcontroller 
            viewController.delegate = self
            self.presentViewController(viewController, animated: false, completion: nil)
            break
    
        // the same code here for other 4 VC's with their StoryboardId's
    
        default: break
        } 
    }
    

    【讨论】:

    • 拜托,你能给我一个例子,如何为实例化的 viewController 保留引用吗?
    • 我已经更新了。如果这回答了您的问题,请将其标记为“回答”。
    • 我稍后会尝试回复
    • 嗯,这完全是另一个问题,应该作为另一个问题发布。我提出的方案是否解决了内存泄漏问题?
    • 如我所见,它解决了内存泄漏,但现在我很困惑如何在需要时重新启动 viewController 或启动另一个选定的 menuVC,因为或此警告:Warning: Attempt to present <College_App_Test.ShadowUINavigationController: 0x15ee177d0> on <College_App_Test.MainViewController: 0x15ed08810> whose view is not in the window hierarchy!
    猜你喜欢
    • 1970-01-01
    • 2017-07-09
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多