如何从现有的视图控制器类调用函数?

时间:2022-10-25 03:14:12

I'm still an early stage Swift developer. I'm trying to create a feature where I click a button on a screen, then I get prompted by the iPhone to allow location, and when I click allow, I am automatically navigated to another screen.

我还是一个早期的Swift开发人员。我在尝试创建一个功能,点击屏幕上的一个按钮,然后iPhone提示我允许位置,当我点击允许,我自动导航到另一个屏幕。

So far I've done the following things:

到目前为止,我已经做了以下事情:

  • created a seperate class ("User") where all the location functions are handled
  • 创建一个分离类(“User”),在其中处理所有位置函数
  • Setup a button on the first view controller and the appropiate IBAction that calls the location prompt function from "User"
  • 在第一个视图控制器上设置一个按钮,以及调用“User”中调用位置提示函数的appropiate IBAction
  • Added storyboard IDs for the first and second view controller
  • 为第一个和第二个视图控制器添加了故事板id
  • Created a function ("changeScreen") in the first view controller class that performs the navigation to another view
  • 在执行到另一个视图的导航的第一个视图控制器类中创建一个函数(“changeScreen”)
  • Setup a listener in the "User" class for when user has clicked allow location, which then calls the "changeScreen" function
  • 在“User”类中为用户单击“允许位置”设置侦听器,然后调用“changeScreen”函数

I think there's another way to do this (call some sort of completion handler) and I toyed around with that for 1-2 hours and nothing worked. So far this solution has almost completely worked but I get the following error:

我认为还有另一种方法(调用某种完成处理程序),我花了1-2个小时来摆弄它,但什么都不管用。到目前为止,这个解决方案几乎是完全有效的,但我得到了以下错误:

Warning: Attempt to present ____ on _____ whose view is not in the window hierarchy!

警告:试图在视图不在窗口层次结构中的_____上显示____ !

Here's the code in my "User" class

这是我的“用户”类中的代码

class User: NSObject, CLLocationManagerDelegate {

func getLocation(){

    // For use in foreground
    locationManager.requestWhenInUseAuthorization()

    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    //locationManager.startUpdatingLocation()

    println("hello location")


}

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status:CLAuthorizationStatus){

        if status == .AuthorizedWhenInUse {

            locationManager.startUpdatingLocation()

            firstView!.showSecondScreen() // this is where I call the other      class's function

        }
    }
  }

Here's the code in my First View controller class

这是我的第一个视图控制器类中的代码

var firstView: FirstView? = nil

class FirstView: UIViewController {

var newUser = User()

override func viewDidAppear(animated: Bool) {

    firstView = self.storyboard!.instantiateViewControllerWithIdentifier("firstView") as? FirstView

// here i take the first view controller class and store it into a public variable

}

@IBAction func allowLocationBtn(sender: AnyObject) {

    newUser.getLocation()  // this is the first button clicked

}

func showSecondScreen(){

    let secondScreen = self.storyboard!.instantiateViewControllerWithIdentifier("SecondScreen") as! SecondScreen

    self.presentViewController(secondScreen, animated: true, completion:   nil  )

}

Ps. I know I can combine all the code into one class, and it could all work like that. But I want to do it the "proper" way, have different functionalities in different classes.

我知道我可以把所有的代码合并到一个类中,它可以这样工作。但是我想用“合适”的方法,在不同的类中有不同的功能。

2 个解决方案

#1


1  

  • try to set first = self , dont instantiate a new view-controller
  • 尝试先设置= self,不要实例化一个新的视图控制器
  • if using storyboard, better to use segues to display another screen
  • 如果使用故事板,最好使用segue来显示另一个屏幕

Though the correct thing here would be to have a UserDelegate Protocol

虽然这里正确的做法是使用UserDelegate协议

protocol UserDelegate { func displayOtherScreen( ) }

协议UserDelegate {func displayOtherScreen()}

then in User add var delegate: UserDelegate? and in the locationManager function instead of calling firstView!.showSecondScreen call delegate?.displayOtherScreen( )

然后在用户添加var委托:UserDelegate?在locationManager函数中,而不是调用firstView!showSecondScreen叫委托吗?。displayOtherScreen()

Then make FirstView adopt the UserDelegate Protocol

然后使FirstView采用UserDelegate协议

class FirstView: UIViewController, UserDelegate {
var newUser = User()

override func viewDidAppear(animated: Bool) {
    newUser.delegate = self
    ...
    }
    ...
    ...
func displayOtherScreen( ) {
    showSecondSceen( ) 
    }

Now there is no need for the first variable..

现在不需要第一个变量了。

#2


0  

Ideally the situation you are trying handle multiple MVC's. Your second Screen by itself should be a different View and should have its own Model View Controller. That way you are not breaking the rules of MVC architecture. Your ShowSecondScreen() function should be controlled by a SecondViewController.

理想情况下,您正在尝试处理多个MVC。第二个屏幕本身应该是一个不同的视图,并且应该有自己的模型视图控制器。这样就不会违反MVC架构的规则。您的ShowSecondScreen()函数应该由SecondViewController控制。

Once you have this multiple MVC's defined you can wire them up. There are some ways to do this - UISplitViewController, UITabViewController, UINavigationViewController. In your case, UINavigationViewController seems best option. You can add Navigation Controller to wireup MVC's using Editor -> Embed on your class FirstView. That would make FirstView controller as your rootViewController.

一旦定义了多个MVC,就可以将它们连接起来。有一些方法可以实现这个——UISplitViewController, UITabViewController, UINavigationViewController。在你的例子中,UINavigationViewController看起来是最好的选择。您可以添加导航控制器到wireup MVC的编辑器->嵌入您的类FirstView。这会使FirstView控制器成为你的rootViewController。

Then add a segue from your button on the FirstView to your controller for the SecondScreen i.e SecondViewController

然后从FirstView上的按钮向控制器添加一个用于SecondScreen i的segue。e SecondViewController

class FirstView: UIViewController {
    override func prepareForSegue(..) {
        if let secondControllerObject = segue.destinationViewController as? SecondViewController {
            if let identifier = segue.identifier {
                 switch identifier {
                       case "<your_buttons_identifier_string" : secondControllerObject .callToSecondScreen() 
/* Now will move the Second View to the top of the MVC stack and you 
will be also able to go back to first view as you have a 
Navigation Controller hooked up.*/
/* callToSecondScreen - should be a controller object displaying the
 controlling and displaying contents in the second screen's view. 
Data for second screen's view will come from its Model */

        }

#1


1  

  • try to set first = self , dont instantiate a new view-controller
  • 尝试先设置= self,不要实例化一个新的视图控制器
  • if using storyboard, better to use segues to display another screen
  • 如果使用故事板,最好使用segue来显示另一个屏幕

Though the correct thing here would be to have a UserDelegate Protocol

虽然这里正确的做法是使用UserDelegate协议

protocol UserDelegate { func displayOtherScreen( ) }

协议UserDelegate {func displayOtherScreen()}

then in User add var delegate: UserDelegate? and in the locationManager function instead of calling firstView!.showSecondScreen call delegate?.displayOtherScreen( )

然后在用户添加var委托:UserDelegate?在locationManager函数中,而不是调用firstView!showSecondScreen叫委托吗?。displayOtherScreen()

Then make FirstView adopt the UserDelegate Protocol

然后使FirstView采用UserDelegate协议

class FirstView: UIViewController, UserDelegate {
var newUser = User()

override func viewDidAppear(animated: Bool) {
    newUser.delegate = self
    ...
    }
    ...
    ...
func displayOtherScreen( ) {
    showSecondSceen( ) 
    }

Now there is no need for the first variable..

现在不需要第一个变量了。

#2


0  

Ideally the situation you are trying handle multiple MVC's. Your second Screen by itself should be a different View and should have its own Model View Controller. That way you are not breaking the rules of MVC architecture. Your ShowSecondScreen() function should be controlled by a SecondViewController.

理想情况下,您正在尝试处理多个MVC。第二个屏幕本身应该是一个不同的视图,并且应该有自己的模型视图控制器。这样就不会违反MVC架构的规则。您的ShowSecondScreen()函数应该由SecondViewController控制。

Once you have this multiple MVC's defined you can wire them up. There are some ways to do this - UISplitViewController, UITabViewController, UINavigationViewController. In your case, UINavigationViewController seems best option. You can add Navigation Controller to wireup MVC's using Editor -> Embed on your class FirstView. That would make FirstView controller as your rootViewController.

一旦定义了多个MVC,就可以将它们连接起来。有一些方法可以实现这个——UISplitViewController, UITabViewController, UINavigationViewController。在你的例子中,UINavigationViewController看起来是最好的选择。您可以添加导航控制器到wireup MVC的编辑器->嵌入您的类FirstView。这会使FirstView控制器成为你的rootViewController。

Then add a segue from your button on the FirstView to your controller for the SecondScreen i.e SecondViewController

然后从FirstView上的按钮向控制器添加一个用于SecondScreen i的segue。e SecondViewController

class FirstView: UIViewController {
    override func prepareForSegue(..) {
        if let secondControllerObject = segue.destinationViewController as? SecondViewController {
            if let identifier = segue.identifier {
                 switch identifier {
                       case "<your_buttons_identifier_string" : secondControllerObject .callToSecondScreen() 
/* Now will move the Second View to the top of the MVC stack and you 
will be also able to go back to first view as you have a 
Navigation Controller hooked up.*/
/* callToSecondScreen - should be a controller object displaying the
 controlling and displaying contents in the second screen's view. 
Data for second screen's view will come from its Model */

        }