Can't I do the screen transition only from ViewController?

Asked 1 years ago, Updated 1 years ago, 100 views

I would like to tap on the TableView cell in Swift 3.0 and transition the screen to ViewController on another Storyboard.
The following methods for screen transition

 present(viewController, animated:true, completion:nil)

cannot be implemented in TableView class.
In this case, is there no other way but to use the TableView Controller?
I would appreciate it if you could reply.

Use of unresolved identifier 'present'
/*
     * FolderTableView.swift
     */
    import UIKit

    class FolderTableView:NSObject, UITableViewDelegate, UITableViewDataSource{

        // half-way omission

        functableView(_tableView:UITableView, didSelectRowAtindexPath:IndexPath){

            let storyboard:UIStoryboard=UIStoryboard(name: "Task", bundle:nil)

            lettaskListViewController=storyboard.instantiateViewController(withIdentifier: "Task")

            self.present(taskListViewController, animated:true, completion:nil)
             ↑ I want to use this method to transition the screen
        }

    }

    /*
     * FolderListViewController.swift
     */
    import UIKit
    import RealmSwift

    class FolderListViewController:UIViewController {

        @IBOutlet weak var folderTableView: UITableView!

        let folderTable=FolderTableView()

        override func viewDidLoad(){
            super.viewDidLoad()

            folderTableView.delegate=folderTable
            folderTableView.dataSource=folderTable

        }

        // omission    

    }

·Implement the present method within FolderListViewController calling TableView
→The following error occurs in the line folderTableView.delegate=folderTable when tapping the cell

 fatal error: unexpectedly found nil while unwrapping an optional value

·Create a ViewController class for the present method and call the method in FolderTableView
→The following error occurs when tapping the cell

Warning: Attempt to present<skillup7.TaskListViewController:0x7f98b423650>on<skillup7.TestViewController:0x7f98b522230>whose view is not in the window hierarchy!

↓↓Prepared ViewController Class ↓↓

/*
 * TestViewController.swift
 */
import UIKit

class TestViewController:UIViewController {

    override func viewDidLoad(){
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override funcdidReceiveMemoryWarning(){
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func send (viewController: UIViewController) {
        self.present(viewController, animated:true, completion:nil)
    }

}

languages:Swift 3.0

swift ios swift3

2022-09-30 21:25

2 Answers

Can't I do screen transition only from ViewController?
→Yes

Is the only way to do this is to use the TableViewController?
(UITableViewController means) → No
(If you mean ViewController displaying UITableView) → Yes

Implement the present method in FolderListViewController calling TableView

I can't say anything about the code that is currently presented because there is no part of the FolderListViewController that implements the present method.

Create a ViewController class for the present method and invoke the method in FolderTableView

This is bound to fail; the instance of the ViewController class that invokes the present method must be 現在the one currently responsible for displaying the screen 表示.Even if you are in the same class, you will fail if you create a different instance than the one that is responsible for displaying the screen.

While I'm not sure what I've tried above, it would be easier to add properties to FolderTableView because the present method should be called from the ViewController instance currently responsible for displaying the screen.

Also, as you can see in the comments, it's so disgusting to have a class name ...View in a class that is not View, so in the following code example, we have renamed it FolderTable without permission.

/*
 * FolderTable.swift
 */
import UIKit

classFolderTable:NSObject, UITableViewDelegate, UITableViewDataSource{

    // Properties to keep the ViewController instance currently responsible for displaying the screen
    weak var owner —UIViewController?

    // half-way omission

    functableView(_tableView:UITableView, didSelectRowAtindexPath:IndexPath){

        let storyboard:UIStoryboard=UIStoryboard(name: "Task", bundle:nil)

        lettaskListViewController=storyboard.instantiateViewController(withIdentifier: "Task")

        // Call the `present(_:animated:completion:)` method for the ViewController instance that is currently responsible for displaying the screen
        owner?.present(taskListViewController, animated:true, completion:nil)
    }
}

/*
 * FolderListViewController.swift
 */
import UIKit
import RealmSwift

class FolderListViewController:UIViewController {

    @IBOutlet weak var folderTableView: UITableView!

    let folderTable=FolderTable()

    override func viewDidLoad(){
        super.viewDidLoad()

        "/ Set ""ViewController Instance currently responsible for displaying the screen"" (===self) in ""folderTable"""
        folderTable.owner=self

        folderTableView.delegate=folderTable
        folderTableView.dataSource=folderTable

    }

    // omission

}

Personally, implementing UITableViewDelegate, UITableViewDataSource in a separate class seems to have far more disadvantages than advantages and disadvantages.In iOS programming, the ViewController tends to get bloated, so you might have wanted to avoid it, but in Swift, extensions are much easier to use, so I think the code will be much cleaner.

class FolderListViewController:UIViewController {

    @IBOutlet weak var folderTableView: UITableView!

    override func viewDidLoad(){
        super.viewDidLoad()

        folderTableView.delegate=self
        folderTableView.dataSource=self

    }

    // omission

}

extensionFolderListViewController:UITableViewDelegate,UITableViewDataSource{

    // half-way omission

    functableView(_tableView:UITableView, didSelectRowAtindexPath:IndexPath){

        let storyboard:UIStoryboard=UIStoryboard(name: "Task", bundle:nil)

        lettaskListViewController=storyboard.instantiateViewController(withIdentifier: "Task")

        self.present(taskListViewController, animated:true, completion:nil)
    }

}

You cannot declare properties for extension, but I don't think it will be a big problem if you design a model class that is easy to implement UITableViewDelegate, UITableViewDataSource and make it a different class.


2022-09-30 21:25

Because the present(_:animated:completion:) function is the UIViewController, only classes inheriting the UIViewController

can be invoked.

The error message UUse of unresolved identifier 'present' 」 means that a method named にpresent されて is not implemented in the FolderTableView class.This is an error because you are calling something that does not exist.

If you want to run the present function after processing within a class that cannot use the present(_:animated:completion:) function, you can create a custom delegate.For example, create a new protocol like this

.
import UIKit

protocolFolderTableViewTransitionDelegate{
  funcgoToTaskListScene()
}

Then, create the above delegate properties in the class that triggers the transition execution, and call the delegate method within the method that actually triggers the transition execution.

class FolderTableView: NSObject, UITableViewDelegate, UITableViewDataSource{

  // Properties referencing the delegate protocol (optional, no value here)
  vardelegate —FolderTableViewTransitionDelegate?

  // UITableViewDelegate method called when selecting cells in a table view
  functableView(_tableView:UITableView, didSelectRowAtindexPath:IndexPath){

    // call a custom delivery method
    delete?goToTaskListScene()
  }

  // Abbreviated below
}

Then, the controller class responsible for the transition process will conform to the protocol that you just created.Then set itself to the delegate property.In addition, it implements a method that actually performs transition processing.

// Add a protocol name to make this class compliant
class FolderListViewController:UIViewController, FolderTableViewTransitionDelegate{

  @IBOutlet weak var folderTableView: UITableView!

  privatelet folderTable=FolderTableView()


  // MARK:-UIViewController method

  override func viewDidLoad(){
    super.viewDidLoad()

    // Configure this Class for the Deligate Properties
    folderTable.delegate=self

    folderTableView.delegate=folderTable
    folderTableView.dataSource=folderTable
  }


  // MARK:- FolderTableViewTransitionDelegate method

  // method for performing a transition
  funcgoToTaskListScene(){

    let storyboard:UIStoryboard=UIStoryboard(name: "Task", bundle:nil)
    lettaskListViewController=storyboard.instantiateViewController(withIdentifier: "Task")
    self.present(taskListViewController, animated:true, completion:nil)
  }

}

By implementing the delegate function using the protocol as described above, the present(_:animated:completion:) method can be used to achieve a modal transition, even from non-classes that inherit the UIViewController or UIViewController.

You do not need to create a new UIViewController subclass just to use the present function.In this case, wouldn't it be more efficient to use an existing class?

However, as you pointed out in the other answers and comments, there is a fundamental problem with this code.Apple recommends a MVC (Model-View-Controller) design pattern to program application development.This code appears to be out of the recommended naming convention because some sections are not organized in the form of MVC.Understanding MVC and Swift naming conventions and writing code should reduce errors.You should also be able to create more efficient and appropriate subclasses.

The "fatal error: unexpected found nil while unwrapping an optional value" error appears to be due to the outlet not being linked properly. We recommend that you first check the outlet's connection status with Connections Inspector, and then try a new code.


2022-09-30 21:25

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.