3

I'm getting a strange Firebase Crashlytics reports which we're unable to reproduce or track the issue, Only 1.5% of the users are getting this crash but we need to get it fixed.

Crashed: com.apple.main-thread.   EXC_BREAKPOINT 0x0000000100b057a4    
SearchViewController.tableView(_:cellForRowAt:)
0  AppName                        0x100b057a4 SearchViewController.tableView(_:cellForRowAt:) + 4309342116 (<compiler-generated>:4309342116)
1  AppName                        0x100b05834 @objc SearchViewController.tableView(_:cellForRowAt:) + 4309342260 (<compiler-generated>:4309342260)
2  UIKitCore                      0x211f3b618 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 680
3  UIKitCore                      0x211f3bb18 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 80
4  UIKitCore                      0x211f08320 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2260
5  UIKitCore                      0x211f25640 -[UITableView layoutSubviews] + 140
6  UIKitCore                      0x2121b4170 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1292
7  QuartzCore                     0x1e9a6cc60 -[CALayer layoutSublayers] + 184
8  QuartzCore                     0x1e9a71c08 CA::Layer::layout_if_needed(CA::Transaction*) + 332
9  QuartzCore                     0x1e99d43e4 CA::Context::commit_transaction(CA::Transaction*) + 348
10 QuartzCore                     0x1e9a02620 CA::Transaction::commit() + 640
11 QuartzCore                     0x1e9a0315c CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 92
12 CoreFoundation                 0x1e54c04fc __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
13 CoreFoundation                 0x1e54bb224 __CFRunLoopDoObservers + 412
14 CoreFoundation                 0x1e54bb7a0 __CFRunLoopRun + 1228
15 CoreFoundation                 0x1e54bafb4 CFRunLoopRunSpecific + 436
16 GraphicsServices               0x1e76bc79c GSEventRunModal + 104
17 UIKitCore                      0x211d1cc38 UIApplicationMain + 212
18 AppName                        0x100a19654 main + 18 (RatingDetailsTableViewCell.swift:18)
19 libdyld.dylib                  0x1e4f7e8e0 start + 4
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = list[indexPath.row]
        switch selectedType {
        case .book, .bundle, .gadget, .author:
            let cell = tableView.dequeue(cellForItemAt: indexPath) as ItemTableViewCell
            cell.configure(item)
            return cell

        case .none:
            return UITableViewCell()
        }
    }
    public func configure(_ item: Itemizable) {
        self.item = item
        // Adjest imageview shape depending on item
        let isAuthor = ItemType.author == item.type
        twoThirdRatioConstraint.isActive = !isAuthor
        oneRatioConstraint.isActive = isAuthor
        imgView.layer.cornerRadius = isAuthor ? imgView.bounds.width / 2 : 10
    }

Thanks in advance..

Update 1

Adding array list & numberOfRowsInSection

    fileprivate var list = [Itemizable]() {
        didSet {
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
Ahmed M. Hassan
  • 709
  • 9
  • 14

2 Answers2

2

I would suggest you to add a basic protection.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // A good practice to prevent crashes is to always compare 
        // the number of objects and the indexPath.row

        guard list.count > indexPath.row else { 
            // You could add a log here to know if that's your problem
            return UITableViewCell() 
        }

        let item = list[indexPath.row]
        switch selectedType {
        case .book, .bundle, .gadget, .author:
            let cell = tableView.dequeue(cellForItemAt: indexPath) as ItemTableViewCell
            cell.configure(item)
            return cell

        case .none:
            return UITableViewCell()
        }
    }
CoachThys
  • 280
  • 3
  • 9
0

There is a small window that you have a new list that is used for numberOfRowsInSection but reloadData() is not called because it's executed asynchronously. What you should do is to enforce that assigning the the new value of the list is performed on the main thread and after that immediately call reloadData() without dispatching it.