解除意外行为
Unwind unexpected behaviour
我的项目中传递展开数据时遇到问题。
正如我在 dfri 回答中看到的 post
它工作得很好,我打印了保存值的变量,它们以正确的顺序打印,第一个是要传递的变量,第二个是传递的变量。第二次从展开功能中打印出来。
当我以与上述示例相同的方式实现展开功能时,我得到了完全不同的变量打印顺序。
在我的例子中,我首先从 unwind 函数获得打印,然后从 CollectionView didSelect 函数获得打印。
并且应该接收数据的变量保持为零。
我还尝试为静态变量赋值并使用它,但也没有对其进行任何更改。
这是两个 ViewControllers 代码:
import UIKit import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var dropPinButton: UIButton!
@IBOutlet weak var centerMApButton: UIButton!
var pin: AnnotationPinn!
var dataReceived: String?
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
// variables that hold values for selected icon, to be used for displaying the pin
let latitude: Double = 44.498955
let longitude: Double = 11.327591
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000)
mapView.setRegion(region, animated: true)
// title may be to be taken from iconNames[indexpath.row]
pin = AnnotationPinn(title: "strada chiusa", subtitle: "", coordinate: coordinate)
}
//custom pin image , named: iconsImages[indexPath.row]
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: pin, reuseIdentifier: "strada chiusa")
annotationView.image = UIImage(named: "\(String(describing: dataReceived))") // here choose the image to load // annotationView.image = UIImage(named: "\(String(describing: MyVariables.dataReceived))") // here choose the image to load
// annotationView.image = UIImage(iconsNames[1])
let transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
annotationView.transform = transform
return annotationView
}
func dropPin() { // print("3\(String(describing: dataReceived))")
mapView.addAnnotation(pin)
}
@IBAction func dropPinButton(_ sender: Any) {
performSegue(withIdentifier: "chooseIconSegue", sender: self)
}
@IBAction func unwindHere(sender:UIStoryboardSegue) { // datas coming back
if let sourceViewController = sender.source as? IconsViewController { // MyVariables.dataReceived = sourceViewController.dataPassed
dataReceived = sourceViewController.dataPassed // print(MyVariables.dataReceived!)
print("3\(String(describing: dataReceived))")
dropPin()
}
}
}
vc2
import UIKit
class IconsViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var dataPassed: String?
@IBOutlet weak var iconsCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
var iconsNames = ["lavori in corso", "ciclabile chiusa", "strada chiusa", "bici rubata", "bici sospetta" ]
var iconsImages = [UIImage(named: "lavori in corso"), UIImage(named: "ciclabile chiusa"), UIImage(named: "strada chiusa"), UIImage(named: "bici rubata"), UIImage(named: "bici sospetta")]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return iconsNames.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "iconCell", for: indexPath as IndexPath) as! IconsCollectionViewCell
cell.iconImage?.image = self.iconsImages[indexPath.row]
cell.iconLabel?.text = iconsNames[indexPath.row]
// MyVariables.dataReceived = iconsNames[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
dataPassed = iconsNames[indexPath.row]
MyVariables.dataReceived = dataPassed
print ("2\(iconsNames[indexPath.row])")
print("1\(dataPassed!)")
// navigationController?.popViewController(animated: true) // // dismiss(animated: true, completion: nil)
}
}
如您所见,当您直接从 collectionView 单元连接 segue 时,segue 在 didSelectItemAt
运行之前运行。
有几种方法可以解决这个问题。一种是跳过 didSelectItemAt
并在 prepare(for:sender)
.
中完成所有工作
本例中的 sender
是 collectionView 单元格,因此使用它来获取 indexPath
然后设置您的数据:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let cell = sender as? UICollectionViewCell,
let indexPath = self.iconsCollectionView.indexPath(for: cell) {
self.dataPassed = iconsNames[indexPath.row]
}
}
注意:你应该给你的 unwind segue 一个标识符(例如 "unwindToCaller"
)并检查它。您可以在 Document Outline 视图中找到 segue,并在 Xcode 右侧的 Attributes Inspector 中设置标识符。
然后你会这样检查:
if segue.identifier == "unwindToCaller" {
if let cell = sender as? ...
}
备选方案:
- 不是从 collectionView 单元连接你的 segue,而是从 collectionViewController 顶部的 viewController 图标连接它。给 segue 一个标识符,例如
"returnToCaller"
.
在didSelectItemAt
中,设置数据值后调用segue:
self.performSegue(withIdentifier: "returnToCaller", sender: self)
我的项目中传递展开数据时遇到问题。
正如我在 dfri 回答中看到的 post
import UIKit import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
@IBOutlet weak var mapView: MKMapView!
@IBOutlet weak var dropPinButton: UIButton!
@IBOutlet weak var centerMApButton: UIButton!
var pin: AnnotationPinn!
var dataReceived: String?
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
// variables that hold values for selected icon, to be used for displaying the pin
let latitude: Double = 44.498955
let longitude: Double = 11.327591
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000)
mapView.setRegion(region, animated: true)
// title may be to be taken from iconNames[indexpath.row]
pin = AnnotationPinn(title: "strada chiusa", subtitle: "", coordinate: coordinate)
}
//custom pin image , named: iconsImages[indexPath.row]
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: pin, reuseIdentifier: "strada chiusa")
annotationView.image = UIImage(named: "\(String(describing: dataReceived))") // here choose the image to load // annotationView.image = UIImage(named: "\(String(describing: MyVariables.dataReceived))") // here choose the image to load
// annotationView.image = UIImage(iconsNames[1])
let transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
annotationView.transform = transform
return annotationView
}
func dropPin() { // print("3\(String(describing: dataReceived))")
mapView.addAnnotation(pin)
}
@IBAction func dropPinButton(_ sender: Any) {
performSegue(withIdentifier: "chooseIconSegue", sender: self)
}
@IBAction func unwindHere(sender:UIStoryboardSegue) { // datas coming back
if let sourceViewController = sender.source as? IconsViewController { // MyVariables.dataReceived = sourceViewController.dataPassed
dataReceived = sourceViewController.dataPassed // print(MyVariables.dataReceived!)
print("3\(String(describing: dataReceived))")
dropPin()
}
}
}
vc2
import UIKit
class IconsViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var dataPassed: String?
@IBOutlet weak var iconsCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
var iconsNames = ["lavori in corso", "ciclabile chiusa", "strada chiusa", "bici rubata", "bici sospetta" ]
var iconsImages = [UIImage(named: "lavori in corso"), UIImage(named: "ciclabile chiusa"), UIImage(named: "strada chiusa"), UIImage(named: "bici rubata"), UIImage(named: "bici sospetta")]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return iconsNames.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "iconCell", for: indexPath as IndexPath) as! IconsCollectionViewCell
cell.iconImage?.image = self.iconsImages[indexPath.row]
cell.iconLabel?.text = iconsNames[indexPath.row]
// MyVariables.dataReceived = iconsNames[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
dataPassed = iconsNames[indexPath.row]
MyVariables.dataReceived = dataPassed
print ("2\(iconsNames[indexPath.row])")
print("1\(dataPassed!)")
// navigationController?.popViewController(animated: true) // // dismiss(animated: true, completion: nil)
}
}
如您所见,当您直接从 collectionView 单元连接 segue 时,segue 在 didSelectItemAt
运行之前运行。
有几种方法可以解决这个问题。一种是跳过 didSelectItemAt
并在 prepare(for:sender)
.
本例中的 sender
是 collectionView 单元格,因此使用它来获取 indexPath
然后设置您的数据:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let cell = sender as? UICollectionViewCell,
let indexPath = self.iconsCollectionView.indexPath(for: cell) {
self.dataPassed = iconsNames[indexPath.row]
}
}
注意:你应该给你的 unwind segue 一个标识符(例如 "unwindToCaller"
)并检查它。您可以在 Document Outline 视图中找到 segue,并在 Xcode 右侧的 Attributes Inspector 中设置标识符。
然后你会这样检查:
if segue.identifier == "unwindToCaller" {
if let cell = sender as? ...
}
备选方案:
- 不是从 collectionView 单元连接你的 segue,而是从 collectionViewController 顶部的 viewController 图标连接它。给 segue 一个标识符,例如
"returnToCaller"
. 在
didSelectItemAt
中,设置数据值后调用segue:self.performSegue(withIdentifier: "returnToCaller", sender: self)