【问题标题】:Terminating app due to uncaught exception 'NSInternalInconsistencyException' problem由于未捕获的异常“NSInternalInconsistencyException”问题而终止应用程序
【发布时间】:2021-01-29 22:19:17
【问题描述】:

我正在尝试实现一个表格视图,在每个单元格中显示书籍信息。我从 API 获得这些信息。这是我的代码:

class ViewController: UIViewController {
    

    @IBOutlet weak var allBooksTable: UITableView!
    
    var bookList:myList? = nil {
    didSet {
          allBooksTable.reloadData()
       }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        self.allBooksTable.dataSource = self
        self.allBooksTable.delegate = self

        
        
        let url = URL(string: "https://ipvefa0rg0.execute-api.us-east-1.amazonaws.com/dev/books?lang=fr&term=self")!
        var request = URLRequest(url: url)
        
        request.setValue(
            "jFXzWHx7SkK6",
            forHTTPHeaderField: "api-key"
        )

        request.httpMethod = "GET"

        
        let session = URLSession.shared
        let task = session.dataTask(with: request) { (data, response, error) in

            if let error = error {
                print(error.localizedDescription)
            } else if let data = data {
                do {
                    let decodedData = try JSONDecoder().decode(myList.self,
                                                               from: data)
                    
                    
                    self.bookList = decodedData
                    print("user: ", decodedData.list[0].imageLinks.thumbnail)

                    print("===================================")
                } catch let DecodingError.dataCorrupted(context) {
                    print(context)
                } catch let DecodingError.keyNotFound(key, context) {
                    print("Key '\(key)' not found:", context.debugDescription)
                    //print("codingPath:", context.codingPath)
                } catch let DecodingError.valueNotFound(value, context) {
                    print("Value '\(value)' not found:", context.debugDescription)
                    print("codingPath:", context.codingPath)
                } catch let DecodingError.typeMismatch(type, context)  {
                    print("Type '\(type)' mismatch:", context.debugDescription)
                    print("codingPath:", context.codingPath)
                } catch {
                    print("error: ", error)
                }
            } else {
                // Handle unexpected error
            }
        }
        
        
        task.resume()
                        
    }
    


}


extension ViewController: UITableViewDataSource , UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 200
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as! bookTableViewCell
                cell.bookName.text = bookList?.list[indexPath.row].title
        if bookList?.list[indexPath.row].imageLinks.smallThumbnail != nil{
            
            //cell.img.load(url: (bookList?.list[indexPath.row].imageLinks.smallThumbnail)!)
            print((bookList?.list[indexPath.row].imageLinks.smallThumbnail)!)
           cell.img.downloaded(from: (bookList?.list[indexPath.row].imageLinks.smallThumbnail)!)
            
        }

                return cell
    }
    
}


extension UIImageView {
    func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
        contentMode = mode
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil,
                let image = UIImage(data: data)
                else { return }
            DispatchQueue.main.async() { [weak self] in
                self?.image = image
            }
        }.resume()
    }
    func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
        guard let url = URL(string: link) else { return }
        downloaded(from: url, contentMode: mode)
    }
}

当我运行应用程序时,它只显示我的第一本书,然后崩溃并出现以下错误。

2020-10-15 23:12:00.953424+1100 MSA[50129:2517792] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff2043a126 __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007fff20177f78 objc_exception_throw + 48
    2   CoreAutoLayout                      0x00007fff58010d41 -[NSISEngine tryToOptimizeReturningMutuallyExclusiveConstraints] + 0
    3   CoreAutoLayout                      0x00007fff58010fcd -[NSISEngine withBehaviors:performModifications:] + 25
    4   UIKitCore                           0x00007fff24ac64ad -[UIView(AdditionalLayoutSupport) _recursiveUpdateConstraintsIfNeededCollectingViews:forSecondPass:] + 112
    5   UIKitCore                           0x00007fff24ac6136 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 827
    6   UIKitCore                           0x00007fff24ac6a08 __100-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]_block_invoke + 85
    7   UIKitCore                           0x00007fff24ac6594 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:] + 154
    8   UIKitCore                           0x00007fff24ac7482 -[UIView(AdditionalLayoutSupport) _updateConstraintsAtEngineLevelIfNeededWithViewForVariableChangeNotifications:] + 393
    9   UIKitCore                           0x00007fff24ba9ad6 -[UIView _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] + 275
    10  UIKitCore                           0x00007fff24bbda37 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2979
    11  QuartzCore                          0x00007fff27a3dd87 -[CALayer layoutSublayers] + 258
    12  QuartzCore                          0x00007fff27a44239 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
    13  UIKitCore                           0x00007fff24ba8fe9 -[UIView(Hierarchy) layoutBelowIfNeeded] + 573
    14  UIKitCore                           0x00007fff24bb0479 +[UIView(Animation) performWithoutAnimation:] + 84
    15  UIKitCore                           0x00007fff248954d0 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 1300
    16  UIKitCore                           0x00007fff2485e8bb -[UITableView _updateVisibleCellsNow:] + 2942
    17  UIKitCore                           0x00007fff2487e6e6 -[UITableView layoutSubviews] + 237
    18  UIKitCore                           0x00007fff24bbd9ce -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2874
    19  QuartzCore                          0x00007fff27a3dd87 -[CALayer layoutSublayers] + 258
    20  QuartzCore                          0x00007fff27a44239 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
    21  QuartzCore                          0x00007fff27a4ff91 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65
    22  QuartzCore                          0x00007fff27990078 _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
    23  QuartzCore                          0x00007fff279c6e13 _ZN2CA11Transaction6commitEv + 783
    24  QuartzCore                          0x00007fff279c7616 _ZN2CA11Transaction14release_threadEPv + 210
    25  libsystem_pthread.dylib             0x00007fff5dcda054 _pthread_tsd_cleanup + 551
    26  libsystem_pthread.dylib             0x00007fff5dcdc512 _pthread_exit + 70
    27  libsystem_pthread.dylib             0x00007fff5dcd9ddd _pthread_wqthread_exit + 77
    28  libsystem_pthread.dylib             0x00007fff5dcd8afc _pthread_wqthread + 481
    29  libsystem_pthread.dylib             0x00007fff5dcd7b77 start_wqthread + 15
)
libc++abi.dylib: terminating with uncaught exception of type NSException

你能帮我理解这里发生了什么吗?我已经查看了类似的主题,但大多数解决方案都是针对该问题的。

【问题讨论】:

  • allBooksTable.reloadData(),在didSet,它不在主线程中。仔细阅读错误:“从主线程访问后,不得从后台线程执行对布局引擎的修改。” ”。重新加载 TableView,这是 UI 相关的,你不觉得吗?

标签: ios swift uiview


【解决方案1】:

如果 UIElement 在后台线程中得到更新,这就是应用程序崩溃的原因,所以每当您想要更新 UI 时,您需要在主线程中更新该 UI 元素,并且您的会话数据任务正在后台线程中运行,您可以在那里设置值bookList 但是当设置bookList 时,有一个属性观察器在后台线程中重新加载表视图,因此有两种解决方案。

  1. 在您的 api 调用函数中,您需要在主线程中设置属性,如下所示:-
    DispatchQueue.main.async {
        self.bookList = decodedData
      }
  1. 在您的财产观察者中,您需要这样做
var bookList:myList? = nil {
    didSet {
          DispatchQueue.main.async {
              allBooksTable.reloadData()
          }
       }
    }

享受:-

【讨论】:

    【解决方案2】:

    问题是您从后台线程设置bookList(因为URLSession.dataTask 在后台线程上调用其完成)并在bookListdidSet 中更新UI。您应该将 UI 更新分派到主线程。

    var bookList:myList? = nil {
        didSet {
              DispatchQueue.main.async {
                  allBooksTable.reloadData()
              }
           }
        }
    

    【讨论】:

      【解决方案3】:

      您可以在主线程上设置bookList,如下所示...

       DispatchQueue.main.async {
          self.bookList = decodedData
        }
      

      【讨论】:

        猜你喜欢
        • 2014-01-05
        • 2012-07-28
        • 2015-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-08
        相关资源
        最近更新 更多