pickerview didSelect 随机崩溃:__cfrunloop_is_calling_out_to_a_source1_perform1_function

Posted

技术标签:

【中文标题】pickerview didSelect 随机崩溃:__cfrunloop_is_calling_out_to_a_source1_perform1_function【英文标题】:random crash on pickerview didSelect : __cfrunloop_is_calling_out_to_a_source1_perform1_function 【发布时间】:2017-09-12 07:53:11 【问题描述】:

我收到了以下崩溃报告,但我不明白这个问题。第 487 行指向检查委托中的 pickerView 是否是特定变量。

Crashed: com.apple.main-thread
0  App                    0x1001c5208 specialized NewCorrectiveVC.pickerView(UIPickerView, didSelectRow : Int, inComponent : Int) -> () (NewCorrectiveVC.swift:487)
1  App                    0x1001c2028 @objc NewCorrectiveVC.pickerView(UIPickerView, didSelectRow : Int, inComponent : Int) -> () (NewCorrectiveVC.swift)
2  UIKit                  0x197a83154 -[UIPickerView _sendSelectionChangedForComponent:notify:] + 116
3  UIKit                  0x197a8338c -[UIPickerView _sendSelectionChangedFromTable:notify:] + 344
4  UIKit                  0x197fb0424 -[UIPickerTableView _scrollingFinished] + 188
5  UIKit                  0x197fb05fc -[UIPickerTableView scrollViewDidEndDecelerating:] + 28
6  UIKit                  0x197b216ac -[UIScrollView(UIScrollViewInternal) _scrollViewDidEndDeceleratingForDelegate] + 132
7  UIKit                  0x1979b6db0 -[UIScrollView(UIScrollViewInternal) _stopScrollDecelerationNotify:] + 332
8  UIKit                  0x1979b68ec -[UIScrollView _smoothScrollWithUpdateTime:] + 2356
9  QuartzCore             0x194bc01bc CA::Display::DisplayLinkItem::dispatch(unsigned long long) + 44
10 QuartzCore             0x194bc0068 CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 444
11 IOKit                  0x191c27138 IODispatchCalloutFromCFMessage + 372
12 CoreFoundation         0x19195056c __CFMachPortPerform + 180
13 CoreFoundation         0x191968934 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
14 CoreFoundation         0x1919680e8 __CFRunLoopDoSource1 + 436
15 CoreFoundation         0x191965bcc __CFRunLoopRun + 1840
16 CoreFoundation         0x191894048 CFRunLoopRunSpecific + 444
17 GraphicsServices       0x19331a198 GSEventRunModal + 180
18 UIKit                  0x1978792fc -[UIApplication _run] + 684
19 UIKit                  0x197874034 UIApplicationMain + 208
20 App                    0x100173d04 main (AppDelegate.swift:22)
21 libdispatch.dylib      0x1908785b8 (Missing)

代码:

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)

    if pickerView == assignedTo
    
        if employees.count > 0 
            selectedEmp =  employees[row].employeeId
        
    
    else if pickerView == category \\this is line 487
    
        if categories.count > 0 
            selectedCat = categories[row].wocategoryId
        
    

编辑:

不确定以下是否相关,但我确实有观察者链接到我的 pickerViews:

let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressed))
assignedTo.addGestureRecognizer(longPressRecognizer)
let catLongPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.catLongPressed))
category.addGestureRecognizer(catLongPressRecognizer)
self.hideKeyboardWhenTappedAround()
self.scroll.keyboardDismissMode = .interactive

仅供参考:

public func hideKeyboardWhenTappedAround() 
    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
    view.addGestureRecognizer(tap)

【问题讨论】:

能否分享一下您遇到了什么异常,这对我们更有帮助。 @AshokPolu 在 crashlytics 我看到 EXC_BREAKPOINT 然后上面粘贴了 sn-p 在 487 行下断点,调试应用程序,可能类别为 nil。 在 swift @AshokPolu 中与nil 比较是完全可能的 这种情况的任何部分(修改数组或调用 UIKit 方法)发生在非主线程上是最常见的原因。另一个是更改数组而不通知选择器视图事情已经改变(例如调用reloadAllComponents)。但请参阅下面的答案 【参考方案1】:

我怀疑问题出在对== 的调用中。

if pickerView == assignedTo

这不是你的意思。这会强制调用== 函数并尝试评估这两个对象之间的相等性。如果其中之一是nil,则会崩溃。

pickerView 永远不应该是 nil,但我遇到过 UIKit 发送 nil 以获取不应该是 nil 的参数的情况。 (如果在后台线程上有对 UIKit 方法的任何调用,尤其会发生这种情况。不要这样做,但也可能由于 UIKit 错误而发生。)

assignedTo 可以是 nil 如果视图尚未加载。理论上,在这种情况下你永远不应该得到这个调用,但同样,它可能存在错误,最常见的原因是从主线程调用 UIKit 方法(任何 UIKit 方法;它并不总是必须与这个特殊的选择器视图),但 UIKit 有时也有自己的错误。

无论如何,您的意思并不是“pickerView 等于 到assignedTo”。您的意思是“pickerView 与assignedTo 完全相同。”那是===

if pickerView === assignedTo

=== 进行指针比较,因此即使面对无效的nil 也是安全的。

请记住,这几乎肯定与竞态条件有关。当您在调试器中运行它时它不容易重现的事实并不意味着什么。它可能在 10k 次尝试中发生一次,仅在 Release 中,仅在 iPhone 6 上发生。这就是竞争条件的本质。

【讨论】:

很高兴认识罗伯!我会做出改变和更新,希望能解决崩溃 我仍然会在主线程之外寻找对 UIKit 的调用或对主线程之外的数组的修改。这些仍然可能是问题的根本原因(并且崩溃可能仍然在那些下标行上,而不是if)。在 Xcode9 中,您可以打开 Thread Sanitizer,它会检测某些不正确的线程访问。 将仔细检查所有的 pickerview 加载是否包含在 DispatchQueue.main.async 还有对数组的任何修改。还要确保任何修改数组长度的东西都会重新加载选择器(另一个很常见的错误是错过)。

以上是关于pickerview didSelect 随机崩溃:__cfrunloop_is_calling_out_to_a_source1_perform1_function的主要内容,如果未能解决你的问题,请参考以下文章

文本字段上的崩溃成为pickerview的第一响应者

Pickerview 在文本字段中第二次单击时显示为空,当我按下完成或取消应用程序崩溃时

解包 Optional 时,pickerView 意外发现 nil

具有多个组件的动态 PickerView:索引超出范围

EXC_BREAKPOINT UNKNOWN 行“0”崩溃

如何在本地运行 TestFlight 构建