重新呈现视图控制器时出错

Posted

技术标签:

【中文标题】重新呈现视图控制器时出错【英文标题】:Error when re-presenting view controller 【发布时间】:2017-02-14 20:18:05 【问题描述】:

我展示了一个模态视图控制器,用户可以在其中输入一些信息,然后使用此功能保存该信息...

func handleSave() 

    guard let newProductUrl = NSURL(string: urlTextField.text!) else 
        print("error getting text from product url field")
        return
    
    guard let newProductName = self.nameTextField.text else 
        print("error getting text from product name field")
        return
    
    guard let newProductImage = self.logoTextField.text else 
        print("error getting text from product logo field")
        return
    

    DispatchQueue.main.async 
        self.productController?.save(name: newProductName, url: newProductUrl as URL, image: newProductImage)
    


    // Present reloaded view controller with new product added
    let ac = UINavigationController()
    let pController = ProductController()
    productController = pController
    ac.viewControllers = [pController]
    present(ac, animated: true, completion: nil)


...我在ProductControllerviewWillAppear 中遇到错误(呈现模态视图控制器的控制器,现在正试图返回)

override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)

    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else 
            return
    

    let managedContext =
        appDelegate.persistentContainer.viewContext

    let companyToDisplay = self.navigationItem.title!

    let fetchRequest =
        NSFetchRequest<NSManagedObject>(entityName: "Product")

    fetchRequest.predicate = NSPredicate(format:"company.name == %@",companyToDisplay)

    do 
        products = try managedContext.fetch(fetchRequest)
        print(products)
     catch let error as NSError 
        print("Could not fetch. \(error), \(error.userInfo)")
    

错误是:在展开可选选项时意外发现 nil,位于 let companyToDisplay = self.navigationItem.title! 行。如何指定它正在寻找(和丢失)的self.navigationItem.title 是发送模态视图的控制器的self.navigationItem.title

感谢您的帮助,我已经尝试解决这个问题好几天了,但无法解决。

编辑:这就是我从ProductController 呈现模态视图AddProductController 的方式

func presentModalView() 

    let nc = UINavigationController()
    let addProductController = AddProductController()
    nc.viewControllers = [addProductController]

    self.modalTransitionStyle = UIModalTransitionStyle.coverVertical
    self.modalPresentationStyle = .currentContext
    self.present(nc, animated: true, completion: nil)

编辑:将代码放入调度块中:

    DispatchQueue.main.async 
        self.productController?.save(name: newProductName, url: newProductUrl, image: newProductImage)

        let pController = ProductController()
        self.productController = pController
        self.navigationController?.pushViewController(pController, animated: true)
    

【问题讨论】:

【参考方案1】:

问题是这个调用里面的块:

DispatchQueue.main.async 
    self.productController?.save(name: newProductName, url: newProductUrl as URL, image: newProductImage)

实际上在您的handleSave() 方法返回之后执行。看起来您希望它相对于该方法中的其他代码按顺序执行。

DispathQueue.main.async 将块添加到代码队列中,以便在将来某个时间点执行——它不会立即执行。

要解决此问题,您需要将代码放入调度块中,该块会执行接下来需要发生的任何事情。这将类似于您在此处的内容:

// Present reloaded view controller with new product added
let ac = UINavigationController()
let pController = ProductController()
productController = pController
ac.viewControllers = [pController]
present(ac, animated: true, completion: nil)

但您可能想要清理创建和关闭视图控制器的方式/位置——您在这里所拥有的东西看起来会不必要地堆积一堆视图控制器。

【讨论】:

是的,这就是我遇到的问题。我尝试将代码放在调度块中,但仍然遇到我的问题中提到的相同错误。我编辑了我的问题以显示我尝试过的新代码(仍然习惯于浏览视图和核心数据,所以如果有更好的方法,请告诉我) 如果不查看所有代码,很难判断您要做什么,但请尝试重新定义问题,以便您只使用 ProductController 的一个实例。您似乎不需要在每次保存内容时都创建一个新的。 我知道,对不起,这对我来说是一个很大的学习项目,我迷失在视图控制器/导航控制器中。我以为我只有一个 ProductController 实例,然后是模态视图AddProductController。我真的很困惑,无法真正正确解释...如果您想查看错误,这就是项目(点击编辑->完成->点击一家公司并尝试添加产品以查看错误):@ 987654321@ 您是否尝试过使用情节提要来实现这一点?这通常是这样的应用程序的组合方式。使用故事板可能会帮助您以一种避免您遇到的错误的方式来组织事物。 我想在没有故事板的情况下完成它,如果我想使用故事板,我真的必须重新开始整个项目,我已经为此工作了一个多月正是这个特殊的问题阻碍了我完成它。【参考方案2】:

这是您的问题,您使用 present(ac, animated: true, completion: nil) 来访问此视图,因此此演示文稿是模态的,并且没有导航控制器。 您必须使用 UINavigationController.pushViewController 来呈现视图,这样您将获得 navigationController。

编辑:

        let nc = UINavigationController()
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let addProductController = storyboard.instantiateViewController(withIdentifier: "addProductVC")
    nc.viewControllers = [addProductController]

    self.modalTransitionStyle = UIModalTransitionStyle.coverVertical
    self.modalPresentationStyle = .currentContext
    self.present(nc, animated: true, completion: nil)

别忘了在 storyboard 中设置 addProductController 的标识符,将 storyboard 和 VC 标识符改成你自己的。

编辑 2:

            let nc = UINavigationController()
    let addProductController = ProductController()
    addProductController.navigationItem.title = "Have a good one"
    nc.viewControllers = [addProductController]

    self.modalTransitionStyle = UIModalTransitionStyle.coverVertical
    self.modalPresentationStyle = .currentContext
    self.present(nc, animated: true, completion: nil)

【讨论】:

我已将其更改为 ac.pushViewController(pController, animated: true),现在出现崩溃并出现错误:“不支持多次推送同一个视图控制器实例” 你不应该只改变代码中的一件事,将 ac 更改为 UINavigationController,如果它不起作用,请告诉我编辑我的帖子并放置完整的代码 我不确定我是否理解您的要求 - UINavigationController.pushViewController(pController, animated: true) 不起作用。 刚刚将我的帖子编辑为您的代码,我对其进行了测试,这对我有用,并在导航栏中显示了第二个 VC,这是您需要的吗? 我会试一试,但我没有使用故事板,这都是程序化的,所以我不知道如何设置标识符

以上是关于重新呈现视图控制器时出错的主要内容,如果未能解决你的问题,请参考以下文章

动画视图控制器并同时在表格视图中重新加载数据

tableview 在 connectionDidFinishLoading 中重新加载数据时出错(由 json 解析)

如何防止尝试在已经呈现的控制器上呈现控制器时出错?

索引ViewResult在从ajax调用回调后不重新呈现

如何快速从另一个视图控制器重新加载表格视图

呈现模式视图控制器时呈现视图控制器响应触摸事件