Swift 2 到 3 迁移错误(libc++abi.dylib:以 NSException 类型的未捕获异常终止)
Posted
技术标签:
【中文标题】Swift 2 到 3 迁移错误(libc++abi.dylib:以 NSException 类型的未捕获异常终止)【英文标题】:Swift 2 to 3 Migration Error (libc++abi.dylib: terminating with uncaught exception of type NSException) 【发布时间】:2016-10-15 05:19:29 【问题描述】:我的一个控制器奇怪地导致运行时错误崩溃,而它在 Swift 2 中却没有。
我得到的错误是。
libc++abi.dylib:以 NSException 类型的未捕获异常终止
我附上了一个屏幕截图,显示我已经连接了所有界面构建器元素。
我做了一些实验来查看错误发生的时间点,我认为它可能与设置 textView 有关,但不确定。
1.) 注意控制台消息在print("Draw Undo html")
之后停止。我最初认为该错误与 after 行有关,因为我从未见过控制台消息print("Set attributed text accordingly")
。
2.) 如果我注释掉 incrementListTextView.attributedText = html.html2AttributedString
行,结果是这样的
错误仍然会发生,只是在它发生之前运行其余代码。很奇怪,但是看到错误似乎首先出现在该行周围,我认为它与 TextView 有关,但不确定它可能是什么。
我也附上了这个场景的图片。
InventoryItemController.Swift(完整文件参考)
//
// InventoryItemController.swift
// Inventory Counter
//
// Created by Joseph Astrahan on 4/3/16.
// Copyright © 2016 Joseph Astrahan. All rights reserved.
//
import UIKit
import CoreData
class InventoryItemController: UIViewController, UITextFieldDelegate
var inventoryItem : Inventory?
var m_incrementAmount = 0 //amount it will increment everytime you press (+)
var m_itemHistory = [Int]() //create array to store undo/redo history
var m_undoIndex = 0
@IBOutlet weak var inventoryBarCodeLabel: UILabel!
@IBOutlet weak var inventoryTotalLabel: UILabel!
//List of increments
@IBOutlet weak var incrementListTextView: UITextView!
//Amount to increment by
@IBOutlet weak var incrementAmountTextField: UITextField!
@IBOutlet weak var inventoryNameNavItem: UINavigationItem!
@IBAction func resetBarButtonAction(_: UIBarButtonItem)
//Present 'Are you sure?' Dialog & Reset Vars.
// create the alert in local scope (no need for weak or unowned reference to self in closures)
let alert = UIAlertController(title: "Are You Sure?", message: "This will delete all the counts you have done.", preferredStyle: UIAlertControllerStyle.alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.default, handler: action in
self.resetTotals()
))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
func resetTotals()
print("resetting...")
m_itemHistory = [Int]()
m_itemHistory.append(0)//first count is always 0 after reset.
m_undoIndex = 0 //set back to 0
updateTotal()//update total and save to disk.
print("reset!...")
@IBAction func addInventoryButtonAction(_: UIButton)
//When you add you have to first trim the array of everything that was after it. The redo history is now gone.
let slice = m_itemHistory[0...m_undoIndex]
m_itemHistory = Array(slice)//create new int array from the slice
m_incrementAmount = Int(incrementAmountTextField.text!)!
m_itemHistory.append(m_incrementAmount)
m_undoIndex = m_undoIndex + 1 //add to the index, because undo always happens from last added~
//Update addCount on actual inventoryItem (save to database)
updateTotal()
@IBAction func undoButtonAction(_: UIButton)
print("undo")
m_undoIndex = m_undoIndex - 1
updateTotal()
@IBAction func redoButtonAction(_: UIButton)
print("redo")
m_undoIndex = m_undoIndex + 1
updateTotal()
func textFieldShouldReturn(_ textField: UITextField) -> Bool
textField.resignFirstResponder()
return true
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool
textField.resignFirstResponder()
return true
func textFieldDidEndEditing(_ textField: UITextField)
textField.resignFirstResponder()
func dismissKeyboard()
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(LoginViewController.dismissKeyboard))
self.view.addGestureRecognizer(tap)
print("Showing Inventory Item In Question")
print(inventoryItem)
print("Inventory Name="+(inventoryItem?.name!)!)
//inventoryNameLabel.text = inventoryItem.name!
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
//add observer for contentSize so it centers vertically
incrementListTextView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.new, context: nil)
//Draw inventory name & barcode
inventoryNameNavItem.title = inventoryItem?.name
inventoryBarCodeLabel.text = inventoryItem?.barcode
//Load first time only when view appears to set default
m_itemHistory.append(Int((inventoryItem?.addCount!)!))//add initial value of last 'count'
m_undoIndex = 0 //reset to start.
updateTotal() //updates total to screen
print("Finished UpdateTotal, Should be Showing Screen Now")
func updateTotal()
//Get the max Index we can count to -1 (because arrays are 0 indexed)
let historyTotalMaxIndex = m_itemHistory.count - 1
print("historyTotalCheck: HistoryTotalMaxIndex=\(historyTotalMaxIndex)")
//Current state of undoIndex
print("Init: m_undoIndex =\(m_undoIndex)")
//Do checks to prevent out of index bounds.
if(m_undoIndex<0)
m_undoIndex = 0
if(m_undoIndex>historyTotalMaxIndex)
m_undoIndex = historyTotalMaxIndex
//After modifying...
print("Current: m_undoIndex =\(m_undoIndex)")
//Draw HTML
var html = "<html><font size=\"5\"><font color=\"#008800\"><center>"
for index in 0...m_undoIndex
let increment = m_itemHistory[index]
html = html + "+\(increment), "
html = html + "</center></font></font></html>"
print(html)
print("Draw Undo HTML")
incrementListTextView.attributedText = html.html2AttributedString
print("Set attributed text accordingly")
//get sum of itemHistory
let slice = m_itemHistory[0...m_undoIndex] //returns slice of the array we want.
let sumArray = Array(slice)//create new int array from the slice
print("SumArray Created")
let sum = sumArray.reduce(0, +) //now we can sum up that new sliced array
inventoryItem?.addCount = sum as NSNumber? //set the add count
print("Reduced the Array")
//reset html to different now
html = "<font size=\"10\"><center>Current: \(inventoryItem?.currentCount!) , <font color=\"#008800\"> Counted: \(inventoryItem?.addCount!)</font></center></font>"
inventoryTotalLabel.attributedText = html.html2AttributedString
print("save the context")
//Save the changes
(UIApplication.shared.delegate as! AppDelegate).saveContext()
override func viewWillDisappear(_ animated: Bool)
super.viewWillDisappear(animated)
//have to remove or will crash
incrementListTextView.removeObserver(self, forKeyPath: "contentSize")
/// Force the text in a UITextView to always center itself.
func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutableRawPointer)
let textView = object as! UITextView
var topCorrect = (textView.bounds.size.height - textView.contentSize.height * textView.zoomScale) / 2
topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect;
textView.contentInset.top = topCorrect
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
extension String
var html2AttributedString: NSAttributedString?
guard let data = data(using: .utf8) else return nil
do
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
catch let error as NSError
print(error.localizedDescription)
return nil
var html2String: String
return html2AttributedString?.string ?? ""
【问题讨论】:
你是否在项目中添加了 libc++.tbd 文件? 我该怎么做?或者我怎么知道我是否这样做了? 试试这个可能会解决它。单击您的项目 -> 常规 -> 链接框架和二进制文件 -> 单击 ON + 并搜索 libc++.tbd -> 添加 仍然错误,我认为问题不是库,因为库正在运行,它的库因 NSException 而崩溃。 用调试检查项目,我认为它是获取图像的问题。在您的错误日志中显示“获取图像时出错” 【参考方案1】:您好,我发现了您的问题并在此处修复。
问题是您从未遵循 Swift 3 风格的 KVO 方法调用 从 Swift 3 开始,方法原型发生了变化。
您的代码在这里:
func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutableRawPointer)
let textView = object as! UITextView
var topCorrect = (textView.bounds.size.height - textView.contentSize.height * textView.zoomScale) / 2
topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect;
textView.contentInset.top = topCorrect
但新原型如下:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
let textView = object as! UITextView
var topCorrect = (textView.bounds.size.height - textView.contentSize.height * textView.zoomScale) / 2
topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect;
textView.contentInset.top = topCorrect
你看到这里有什么不同吗?
我还发现了另一个问题: 您确实在 viewWillAppear 函数中添加了观察者,请将其移至 viewDidLoad 函数,并将 removeObserver 代码移至 deinit 或覆盖 func didReceiveMemoryWarning()。
代码如下:
deinit
incrementListTextView.removeObserver(self, forKeyPath: "contentSize")
希望对你有很大帮助!
【讨论】:
是的,解决了它。哇,绝对不会猜到所有这些问题! 非常感谢您的赞赏!以上是关于Swift 2 到 3 迁移错误(libc++abi.dylib:以 NSException 类型的未捕获异常终止)的主要内容,如果未能解决你的问题,请参考以下文章
Swift 2.3 到 Swift 3.1 迁移 - Alamofire 请求错误
从Swift 3.2迁移到Swift 4我使用autosavesInPlace收到错误