EXC_BAD_ACCESS 将数组传递给新 ViewController
EXC_BAD_ACCESS while passing array to new ViewController
我正在从 Web 服务(汽车数据)加载一些 XML,创建一些汽车对象并希望在 TableViewController 中显示它们。
当用户选择了起始位置和目标位置后,我将对网络服务进行异步调用,显示一个 activity 指示器,并在加载数据后立即转到新视图。所以我有这样的东西:
class NewReservationViewController : UIViewController {
@IBAction func searchCarsClicked(sender: UIBarButtonItem) {
//show load cars activity indicator
loadingCarsActivityIndicator.startAnimating()
//load available cars from webservice asyncronously
DataManager.getAvailableCars([...parameter list...], carsLoadedCallback: carsLoaded)
}
func carsLoaded(loadedCars: [Car]) {
//dismiss the waiting widget
//trigger the segue and advance to the next screen
loadingCarsActivityIndicator.stopAnimating()
print("stopped cars loading activity indicator")
print("cars loaded callback called")
print("loaded \(loadedCars.count) distinct cars")
self.cars = loadedCars
performSegueWithIdentifier("showAvailableCars", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showAvailableCars" {
let carTableViewController = segue.destinationViewController as! CarTableViewController
carTableViewController.cars = self.cars
presentViewController(carTableViewController, animated: false, completion: nil)
}
}
}
class DataManager {
class func getAvailableCars([...parameter list...], carsLoadedCallback: ([Car]) -> Void){
Webservice.getAvailability([...parameter list...], completionHandler: { (data, response, error) in
//parse xml
//in the end I get an Array of Car objects
var cars: [Car] = ...
carsLoadedCallback(cars)
})}
}
}
当我用我在 CarTableViewController class 中创建的一些 DummyData 填充 TableView 时,它工作正常。但是,当我尝试将汽车数组传递给我的 TableViewController 时,我得到一个 EXC_BAD_ACCESS code = 2 异常。据我所知,这是某种内存异常,通常是由损坏的指针引起的。所以我猜我在静态 DataManager class 中创建的汽车数组在我调用的静态方法中被销毁了。但是我不确定,因为自动引用计数应该避免这种情况。
table 视图甚至显示数据,但随后立即崩溃并出现 EXC_BAD_ACCESS 异常。我尝试在 XCode 的断点选项卡中设置一个常规断点,但是我没有收到有关应用崩溃原因的合理错误消息。
你知道为什么会这样吗?我怎样才能得到更好的错误信息?
提前感谢您的帮助。
首先检查这个函数:
func carsLoaded(loadedCars: [Car])
它作为回调返回 - 它是什么线程 运行?主要还是背景?
你应该调用主线程
dispatch_async(dispatch_get_main_queue(), {
performSegueWithIdentifier("showAvailableCars", sender: self)
})
如果没有帮助 - 请提供调试器中中断的行,这样我可以提供帮助并查看更多信息。
UPD:没注意到,你为什么要做人工礼物?
presentViewController(carTableViewController, animated: false, completion: nil)
您的 segue 会自动显示视图控制器,您可以在故事板中更改它的样式(模态、推送)。
我可以看到两个潜在的问题。第一个是你从一个可能不在主线程上的方法触发你的 segue,你需要确保这是在主线程上完成的。另一个问题是,在你为 segue 做准备时,你正在打开新的 ViewController 而不检查它,所以试试这个:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showAvailableCars" {
if let carTableViewController = segue.destinationViewController as? CarTableViewController {
carTableViewController.cars = self.cars
presentViewController(carTableViewController, animated: false, completion: nil)
}
}
}
正如您所说,table 视图显示数据然后立即崩溃,我认为问题出在您的 CarTableViewController 中。您可以检查的一件事是当您的单元格被渲染时,如果您试图访问一些来自 Car 对象的 null 信息
我正在从 Web 服务(汽车数据)加载一些 XML,创建一些汽车对象并希望在 TableViewController 中显示它们。
当用户选择了起始位置和目标位置后,我将对网络服务进行异步调用,显示一个 activity 指示器,并在加载数据后立即转到新视图。所以我有这样的东西:
class NewReservationViewController : UIViewController {
@IBAction func searchCarsClicked(sender: UIBarButtonItem) {
//show load cars activity indicator
loadingCarsActivityIndicator.startAnimating()
//load available cars from webservice asyncronously
DataManager.getAvailableCars([...parameter list...], carsLoadedCallback: carsLoaded)
}
func carsLoaded(loadedCars: [Car]) {
//dismiss the waiting widget
//trigger the segue and advance to the next screen
loadingCarsActivityIndicator.stopAnimating()
print("stopped cars loading activity indicator")
print("cars loaded callback called")
print("loaded \(loadedCars.count) distinct cars")
self.cars = loadedCars
performSegueWithIdentifier("showAvailableCars", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showAvailableCars" {
let carTableViewController = segue.destinationViewController as! CarTableViewController
carTableViewController.cars = self.cars
presentViewController(carTableViewController, animated: false, completion: nil)
}
}
}
class DataManager {
class func getAvailableCars([...parameter list...], carsLoadedCallback: ([Car]) -> Void){
Webservice.getAvailability([...parameter list...], completionHandler: { (data, response, error) in
//parse xml
//in the end I get an Array of Car objects
var cars: [Car] = ...
carsLoadedCallback(cars)
})}
}
}
当我用我在 CarTableViewController class 中创建的一些 DummyData 填充 TableView 时,它工作正常。但是,当我尝试将汽车数组传递给我的 TableViewController 时,我得到一个 EXC_BAD_ACCESS code = 2 异常。据我所知,这是某种内存异常,通常是由损坏的指针引起的。所以我猜我在静态 DataManager class 中创建的汽车数组在我调用的静态方法中被销毁了。但是我不确定,因为自动引用计数应该避免这种情况。
table 视图甚至显示数据,但随后立即崩溃并出现 EXC_BAD_ACCESS 异常。我尝试在 XCode 的断点选项卡中设置一个常规断点,但是我没有收到有关应用崩溃原因的合理错误消息。
你知道为什么会这样吗?我怎样才能得到更好的错误信息? 提前感谢您的帮助。
首先检查这个函数:
func carsLoaded(loadedCars: [Car])
它作为回调返回 - 它是什么线程 运行?主要还是背景? 你应该调用主线程
dispatch_async(dispatch_get_main_queue(), {
performSegueWithIdentifier("showAvailableCars", sender: self)
})
如果没有帮助 - 请提供调试器中中断的行,这样我可以提供帮助并查看更多信息。
UPD:没注意到,你为什么要做人工礼物?
presentViewController(carTableViewController, animated: false, completion: nil)
您的 segue 会自动显示视图控制器,您可以在故事板中更改它的样式(模态、推送)。
我可以看到两个潜在的问题。第一个是你从一个可能不在主线程上的方法触发你的 segue,你需要确保这是在主线程上完成的。另一个问题是,在你为 segue 做准备时,你正在打开新的 ViewController 而不检查它,所以试试这个:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showAvailableCars" {
if let carTableViewController = segue.destinationViewController as? CarTableViewController {
carTableViewController.cars = self.cars
presentViewController(carTableViewController, animated: false, completion: nil)
}
}
}
正如您所说,table 视图显示数据然后立即崩溃,我认为问题出在您的 CarTableViewController 中。您可以检查的一件事是当您的单元格被渲染时,如果您试图访问一些来自 Car 对象的 null 信息