由于未捕获的异常 'NSInternalInconsistencyException' 问题而终止应用程序

Terminating app due to uncaught exception 'NSInternalInconsistencyException' problem

我正在尝试实现一个 table 视图,在每个单元格中显示图书信息。我从 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

你能帮我理解这是怎么回事吗?我已经查看过类似的线程,但大多数解决方案都是针对该问题的。

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

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

您可以像下面这样在主线程上设置 bookList...

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

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

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

享受:-