如何识别我的SIGTrap崩溃的原因?

9

我的团队最近推出了一款应用程序,但出现了大量SIGTRAP崩溃。以前我发现这些问题相对简单,只需要找到一个错误的强制转换或在有问题的函数中将隐式解包的可选项设置为nil即可解决。然而这一次,我找不到任何类似的问题。我最好的猜测是,由于日历错误,TimeBlock对象或其属性之一可能为nil。

我们的应用程序是一款会议组织者,以空闲时间、冲突和会议TimeBlocks的形式显示用户的本机iOS日历事件。我可以访问已崩溃的多个用户的日历。

Apple SigTrap定义

如果在运行时遇到意外情况,比如:

  • 非可选类型具有nil值
  • 强制类型转换失败

Swift代码将以此异常类型终止。

崩溃函数

    /**
    Updates the conflictHours and meetingHours according to the timeblocks
    it is used as quick light reference to the button
 */
func updateTimeHours(timeblocks : [Timeblock]) {
    for timeblock in timeblocks {
        switch timeblock {
        case is MeetingTimeblock:
            for i in timeblock.startHour...timeblock.endHour {
                self.meetingHours[i] = true
            }
            break
        case is ConflictTimeblock:
            for i in timeblock.startHour...timeblock.endHour {
                self.conflictsHours[i] = true
            }
            break
        default: break
        }
    }
    updateButtonByOffset(offset: self.scrollTimeline.contentOffset.x)
}

调用崩溃函数

    /**
    This function inits the variables and button layout according to the timeblocks
 */
func handleTimeblocksDependantComponents() {
    buttonLayout()
    guard Scheduler.sharedInstance.timelines.count > SharedGlobals.Calendar.TODAY_INDEX else {
        return
    }
    updateTimeHours(timeblocks : (Scheduler.sharedInstance.timelines[SharedGlobals.Calendar.TODAY_INDEX].timeblocks))
}

SetHeaderHeight

/**
 Adjusts the height of the header depending on whether there are hosted meetings or 
 meeting VIP's or not.
*/
private func setHeaderHeight() {
    self.tableView.tableHeaderView = self.headerView
    let hostedMeetings = OverviewInteractor.getHostedMeetings(dayIndex: SharedGlobals.Calendar.SELECTED_DAY)
    let vips = OverviewInteractor.getVIPS(dayIndex: SharedGlobals.Calendar.SELECTED_DAY)

    self.tableView.beginUpdates()
    if let headerView = self.tableView.tableHeaderView {
        var height = 360.0
        if(vips.count == 0) { height -= 80.0 }
        if(hostedMeetings.count == 0) { height -= 80.0 }
        headerView.frame.size.height = CGFloat(height)
    }
    self.tableView.endUpdates()

}

时间块定义

// The Timeblock parent class. It simply holds a start and end time and provides its own duration. Not to be used as such
public class Timeblock {
    public let startTime: Date
    public let endTime: Date

    /// Returns the hour the Timeblock starts, in current timezone
    public var startHour: Int {
        get {
            return Calendar.current.component(.hour, from: startTime)
        }
    }

    /// Returns the hour the Timeblocks ends, in current timezone
    public var endHour: Int {
        get {
            return Calendar.current.component(.hour, from: endTime)
        }
    }

    /// Returns the minutes the Timeblocks starts
    public var startMinutes: Int {
        get {
            return Calendar.current.component(.minute, from: startTime)
        }
    }

    /// Returns the minutes the Timeblocks ends
    public var endMinutes: Int {
        get {
            return Calendar.current.component(.minute, from: endTime)
        }
    }

    /**
        Initialises the instance with a start and end time
        - Parameters:
            - startTime: The start time of the timeblock
            - endTime: The end time of the timeblock
    */
    public init(startTime: Date, endTime: Date) {
        self.startTime = startTime
        self.endTime = endTime
    }

    /**
        Provides the Timeblock's duration in the form of a DateInterval
        - warning: Only available on iOS 10.0 and up
        - returns: A DateInterval of the duration of the Timeblock
    */
    @available(iOS 10.0, *)
    public func getTimeInterval() -> DateInterval {
        return DateInterval(start: self.startTime, end: self.endTime)
    }

    /**
        Provides the Timeblock's duration in the form of a `Double` (number of seconds)

        - returns: The number of seconds that this Timeblock goes on for
    */
    public func getDuration() -> Double {
        return self.endTime.timeIntervalSince(self.startTime)
    }

}

崩溃报告

事件标识符: 98D4F477-C57B-4767-B957-E9EA2E0EE3EA 崩溃报告器密钥: 0000000000000000000000000000000000000000 硬件型号: 未定义 进程: xxxxxxx [784] 标识符: com.xxx.xxx.xx.xxxxxxx 版本: 4.0.3 代码类型: arm64 日期/时间: 星期日,2017年12月24日09:55:23 GMT+0000 (GMT) 启动时间: 无效日期 操作系统版本: 未定义11.0.3 (15A432) 报告版本: 105 异常类型: SIGTRAP 异常子类型: 未定义 线程0名称: 线程0已崩溃: 0 CallIn 0x0000000102c224e4 specialized TimelineHeader.updateTimeHours(timeblocks:) (TimelineHeader.swift:0) 1 CallIn 0x0000000102c20af0 TimelineHeader.handleTimeblocksDependantComponents() (TimelineHeader.swift:0) 2 CallIn 0x0000000102c7a28c specialized MeetingTableViewController.tableView(:viewForHeaderInSection:) (TimelineHeader.swift:78) 3 CallIn 0x0000000102c75d54 @objc MeetingTableViewController.tableView(:viewForHeaderInSection:) (MeetingTableViewController.swift:0) 4 UIKit 0x000000018d1157d8 -[UITableView _delegateViewForHeaderInSection:] (UIKit) 5 UIKit 0x000000018d11def0 96-[UITableView _sectionHeaderView:withFrame:forSection:floating:reuseViewIfPossible:willDisplay:]_block_invoke (UIKit) 6 UIKit 0x000000018cdf1a14 +[UIView(Animation) performWithoutAnimation:] (UIKit) 7 UIKit 0x000000018d11dc60 -[UITableView _sectionHeaderView:withFrame:forSection:floating:reuseViewIfPossible:willDisplay:] (UIKit) 8 UIKit 0x000000018cfc6c04 -[_UITableViewUpdateSupport(Private) _setupAnimationsForExistingHeadersAndFooters] (UIKit) 9 UIKit 0x000000018cfc1070 -[_UITableViewUpdateSupport _setupAnimations] (UIKit) 10 UIKit 0x000000018cfc0944 -[UITableView _updateWithItems:updateSupport:] (UIKit) 11 UIKit 0x000000018cfa8448 -[UITableView endCellAnimationsWithContext:] (UIKit) 12 UIKit 0x000000018cfa46e4 -[UITableView endUpdates] (UIKit) 13 CallIn 0x0000000102c761a4 MeetingTableViewController.setHeaderHeight() (MeetingTableViewController.swift:398) 14 CallIn 0x0000000102c7a7c8 specialized closure #1 in MeetingTableViewController.refreshTable(:) (MeetingTableViewController.swift:513) 15 CallIn 0x0000000102c7aacc partial apply for closure #1 in MeetingTableViewController.refreshTable(_:)(MeetingTableViewController.swift:0) 16 CallIn 0x0000000102cd17f0 thunk for @callee_owned () -> () (LoginPageViewController.swift:0) 17 libdispatch.dylib 0x000000018327ea54 _dispatch_call_block_and_release (libdispatch.dylib) 18 libdispatch.dylib 0x000000018327ea14 _dispatch_client_callout (libdispatch.dylib) 19 libdispatch.dylib 0x000000018328b698 _dispatch_main_queue_callback_4CF$VARIANT$mp (libdispatch.dylib) 20 CoreFoundation 0x00000001838aa544 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE(CoreFoundation) 21 CoreFoundation 0x00000001838a8120 __CFRunLoopRun (CoreFoundation) 22 CoreFoundation 0x00000001837c7e58 CFRunLoopRunSpecific (CoreFoundation) 23 GraphicsServices 0x0000000185674f84 GSEventRunModal (GraphicsServices) 24 UIKit 0x000000018ce4767c UIApplicationMain (UIKit) 25 CallIn 0x0000000102c02c08 main (AppDelegate.swift:18) 26 libdyld.dylib 0x00000001832e456c start (libdyld.dylib)

你能发布 MeetingTableViewController.setHeaderHeight() 方法吗? - Reinier Melian
@ReinierMelian 我已经更新了问题并包含了它。 - Declan McKenna
我认为问题与您在外部修改标题高度有关,您需要更改此操作并在heightForHeaderInSection方法中返回高度。 - Reinier Melian
你能展示一下Timeblock的定义吗?我看不出它是否有任何可选项。 - Upholder Of Truth
@UpholderOfTruth 已更新问题并附上了定义,其中没有可选项。 - Declan McKenna
显示剩余3条评论
1个回答

1

复现

这是由于索引被搞乱了,Timeblock.startHourTimeblock.endHourInt值。在查看用户日历后,我注意到所有用户的会议都在午夜结束。

因此,对于从下午5点到午夜进行的会议,我们会出现以下情况。

for i in timeblock.startHour...timeblock.endHour 变成了 for i in 0...17

这将给我一个非常精确的错误提示,告诉我不能迭代向后,一旦我复制了崩溃,这个问题就不幸地没有出现在崩溃报告中,这有点误导人。

修复

我们已经限制了创建timeblock.endHour属性的时间,因此下一天的> 0:00被更改为23:59以防止这种情况发生。修复方法就是将该限制应用于>= 0:00,因此在午夜结束的会议不会被视为跨越多天的会议。

未来的重构可能会将所有结束时间为整点的时间设置为前一小时,因为从技术上讲,如果您的会议在上午11:00结束,您仍然有一个小时的空闲时间。我还希望在Timeblock对象内处理这个问题,而不是过滤用于创建它的参数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接