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 */
}