如何解决XCODE SWIFT如何在按下按钮之后但在另一个文件/类中执行代码?
我正在使用MapKit,用户可以添加注释。他们可以点击屏幕,提示他们是否要使用UIAlert添加注释,如果他们回答“是”,它将显示另一个视图控制器,以便用户可以输入有关注释的信息,例如位置名称,描述等。该视图控制器顶部有一个“ Done” BarButtonItem,以确认他们输入的信息并创建注释。
@IBAction func doneButtonpressed(_ sender: UIBarButtonItem) {
doneButtonHasBeenpressed = true
dismiss(animated: true,completion: nil)
}
问题是,必须在原始视图控制器的“ touchesEnded”函数中创建注释,该注释将用户发送到视图控制器,在此他们输入注释信息,因为这是从()获取CLCoordinate2D的地方使用touchesEnded)。正是在相同的touchsEnded函数中,我将用户发送到下一个视图控制器。这是touchesEnded代码及其使用的辅助函数:
override func touchesEnded(_ touches: Set<UITouch>,with event: UIEvent?) {
if let touch = touches.first {
let touchLocation = touch.location(in: view)
// Converts CGPoint coordinates and UIView to CLLocationCordinate2D (map coordinates) Remember to rename if addButtonpressed order of creation of annotation gets changed!
let coordinatesTouchedToCreateAnnotation = mapView.convert(touchLocation,toCoordinateFrom: view)
if userIsAllowedToAddAnnotation {
let alertController = UIAlertController(title: "Confirm",message: "Are you sure you want to add a jump location here?",preferredStyle: .alert)
let noAction = UIAlertAction(title: "No",style: .cancel,handler: nil)
let yesAction = UIAlertAction(title: "Yes",style: .default) { (action) in
// Segue takes user to JumpSpotCreatorController to input information about the jump location
self.performSegue(withIdentifier: "CreateJumpSpot",sender: self)
if self.jumpSpotCreatorController.doneButtonHasBeenpressed == true {
self.jumpSpotCreatorController.doneButtonHasBeenpressed = false
self.createJumpSpotAnnotation(coordinatesDeterminedByTouch: coordinatesTouchedToCreateAnnotation)
self.userIsAllowedToAddAnnotation = false
self.tapToAddJumpSpotLabel.isHidden = true
}
}
alertController.addAction(noAction)
alertController.addAction(yesAction)
present(alertController,animated: true,completion: nil)
} else {
return
}
}
}
// Force unwrap is okay because this will only be called if 'Done' button is pressed in the JumpSpotCreatorController,which mandates that those inputs not be nil.
func createJumpSpotAnnotation(coordinatesDeterminedByTouch: CLLocationCoordinate2D) {
mapView.addAnnotation(JumpSpotAnnotation(name: jumpSpotCreatorController.nameTextField.text!,coordinate: coordinatesDeterminedByTouch,estimatedHeight: jumpSpotCreatorController.estimatedHeightTextField.text!,locationDescription: jumpSpotCreatorController.descripitionTextView.text,warnings: jumpSpotCreatorController.warningsTextView.text ?? "",image: jumpSpotCreatorController.jumpSpotimageView.image ?? UIImage(imageLiteralResourceName: "Image-1")))
}
如您所见,在touchesEnded函数中创建注释的代码块(位于我向alertController添加动作的位置的上方,以防您找不到它。大约4行),将立即执行,而不是在需要时(在我的其他视图控制器(JumpSpotCreatorController)中按下“完成”按钮)。我尝试使用doneButtonHasBeenpressed变量修复该问题,但这没有什么区别(出于明显的原因)。仅在按下“完成”按钮后如何执行?我不能将另一个视图控制器初始化为主对象中的一个对象(带有touchesEnded的对象是主要对象),因为它将在两个视图控制器之间创建无限循环的引用。 dispatchQueue可以以某种方式提供帮助吗?我已经研究了几个小时,但还不太清楚如何在这里应用它。非常感谢。
解决方法
如果我做对了,那么您正在尝试获得如下内容:
Class A {
weak var referenceToB: B?
@IBAction func buttonAction(_ sender: Any) {
guard var referenceToB = referenceToB else {
fatalError("referenceToB not set!")
}
referenceToB!.otherFunction()
}
}
Class B {
func otherFunction() {
//stuff
}
}
在您的情况下,实例化VC之后,将引用分配给包含所需功能的类的对象。
,我不会100%跟踪,但这会有所帮助:
-
按钮被点击,您处于“ A”状态
-
“ A”调用B做某事,并且
-
“ A”带有对自身的引用
(也就是说,在B中的该调用中“添加参数”,这是类“ A”的变量。假设该变量的名称为“ callMeWhenYou'reFinished”)
-
当“ B”完成其应做的工作
-
只需调用callMeWhenYou'reFinished#WhateverFunction
...然后走开!
作为一种“一般编程问题”(忘记了Swift中的可用功能,等等),您只是在描述“回调”。如果我正确地跟随了您,希望对您有所帮助!
进一步:
具有某种循环引用是完全可以的。 (因此,A知道有关B的信息,而B则得到了对A中某物的回调。)
很显然,如果您随后错误地进行了无限循环,那就是无限循环。但是“意外地造成无限循环”与您是否具有单独的类,引用等完全无关。
,有很多方法可以做到这一点-每种都有优点和缺点。
这种方法使用委托/协议模式。
我们定义了一个协议,该协议将允许类在其委托类中执行函数:
// protocol / delegate pttern
protocol JumpSpotDelegate: class {
func createJumpSpotAnnotation(_ name: String,estimatedHeight: String,locationDescription: String,warnings: String,image: UIImage?)
func cancelAnnotation()
}
在具有您的地图视图的控制器中,我们遵守该委托:
class MapViewController: UIViewController,JumpSpotDelegate {
在JumpSpotCreatorController
中,我们设置了一个delegate
属性:
class JumpSpotCreatorController: UIViewController {
weak var delegate: JumpSpotDelegate?
当我们导航到JumpSpotCreatorController
时,我们将self分配为其委托:
override func prepare(for segue: UIStoryboardSegue,sender: Any?) {
// make sure we're acting on the correct segue
if segue.identifier == "CreateJumpSpot",let vc = segue.destination as? JumpSpotCreatorController {
// set the delegate in the JumpSpotCreatorController we're navigating to
vc.delegate = self
}
}
在JumpSpotCreatorController
中,点击完成按钮后,我们通过委托函数告诉地图控制器:
delegate?.createJumpSpotAnnotation(name,estimatedHeight: estimatedHeight,locationDescription: description,warnings: warnings,image: img)
在这里。我通过let
语句添加了对象来编写此代码……我希望您将它们作为@IBOutlet
连接:
// protocol / delegate pttern
protocol JumpSpotDelegate: class {
func createJumpSpotAnnotation(_ name: String,image: UIImage?)
func cancelAnnotation()
}
class MapViewController: UIViewController,JumpSpotDelegate {
// this will hold the touch point while we navigate to and back from the JumpSpotCreatorController
var lastTouch: CLLocationCoordinate2D?
let mapView: MKMapView!
var userIsAllowedToAddAnnotation = true
let tapToAddJumpSpotLabel = UILabel()
override func touchesEnded(_ touches: Set<UITouch>,with event: UIEvent?) {
if let touch = touches.first {
let touchLocation = touch.location(in: view)
// Converts CGPoint coordinates and UIView to CLLocationCordinate2D (map coordinates)
// store in class property
self.lastTouch = mapView.convert(touchLocation,toCoordinateFrom: view)
if userIsAllowedToAddAnnotation {
let alertController = UIAlertController(title: "Confirm",message: "Are you sure you want to add a jump location here?",preferredStyle: .alert)
let noAction = UIAlertAction(title: "No",style: .cancel,handler: nil)
let yesAction = UIAlertAction(title: "Yes",style: .default) { (action) in
// Segue takes user to JumpSpotCreatorController to input information about the jump location
self.performSegue(withIdentifier: "CreateJumpSpot",sender: self)
}
alertController.addAction(noAction)
alertController.addAction(yesAction)
present(alertController,animated: true,completion: nil)
} else {
return
}
}
}
override func prepare(for segue: UIStoryboardSegue,let vc = segue.destination as? JumpSpotCreatorController {
// set the delegate in the JumpSpotCreatorController we're navigating to
vc.delegate = self
}
}
// called by Button action in JumpSpotCreatorController
func createJumpSpotAnnotation(_ name: String,image: UIImage?) {
// the coordinate parameter was stored in our class property "lastTouch"
guard let lastTouch = self.lastTouch else {
// self.lastTouch was not set!
return
}
mapView.addAnnotation(JumpSpotAnnotation(name: name,coordinate: lastTouch,image: image ?? UIImage(imageLiteralResourceName: "Image-1")))
self.userIsAllowedToAddAnnotation = false
self.tapToAddJumpSpotLabel.isHidden = true
// pop from JumpSpotCreatorController back to self
self.navigationController?.popViewController(animated: true)
}
// I'm assuming you would also have a Cancel button?
func cancelAnnotation() {
self.lastTouch = nil
// pop from JumpSpotCreatorController back to self
self.navigationController?.popViewController(animated: true)
}
}
class JumpSpotCreatorController: UIViewController {
weak var delegate: JumpSpotDelegate?
let nameTextField = UITextField()
let estimatedHeightTextField = UITextField()
let descripitionTextView = UITextView()
let warningsTextView = UITextView()
let jumpSpotImageView = UIImageView()
@IBAction func doneBtnTapped() {
// presumably,you'll validate all these
guard let name = nameTextField.text,let estimatedHeight = estimatedHeightTextField.text,let description = descripitionTextView.text,let warnings = warningsTextView.text,let img = jumpSpotImageView.image else {
// notify user required fields were blank
return
}
delegate?.createJumpSpotAnnotation(name,image: img)
}
@IBAction func cancelBtnTapped() {
delegate?.cancelAnnotation()
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。