vincent
vincent

Reputation: 267

Any reason why the NotificationCenter causes EXC_BAD_ACCESS on simulator, but not on device?

I have this code here:

    @objc func buttonTapped(sender: DateFieldButton) {

        // Thread 1: EXC_BAD_ACCESS (code=1, address=0xfffe) here
        NotificationCenter.default.post(name: .dateFieldTapped, object: nil, userInfo: [0 : sender.pattern])

    }
extension Notification.Name {

    static let dateFieldTapped = Notification.Name("dateFieldTapped")

}

Had button.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)

DeviceFieldButton is just a subclass of UIButton, with an additional field of pattern. On a physical device (iPhone X on iOS 13.2), EXC_BAD_ACCESS does not occur. It is only replicable in the Simulator. Have cleaned project multiple times with same observations.

Edit:

Back trace:

libobjc.A.dylib`objc_retain:
    0x7fff50b51c60 <+0>:  testq  %rdi, %rdi
    0x7fff50b51c63 <+3>:  je     0x7fff50b51c81            ; <+33>
    0x7fff50b51c65 <+5>:  js     0x7fff50b51c83            ; <+35>
->  0x7fff50b51c67 <+7>:  movq   (%rdi), %rax
    0x7fff50b51c6a <+10>: testb  $0x4, 0x20(%rax)
    0x7fff50b51c6e <+14>: jne    0x7fff50b51c88            ; objc_object::sidetable_retain()
    0x7fff50b51c74 <+20>: movq   0x3908fee5(%rip), %rsi    ; "retain"
    0x7fff50b51c7b <+27>: jmpq   *0x36ced19f(%rip)         ; (void *)0x00007fff50b37400: objc_msgSend
    0x7fff50b51c81 <+33>: xorl   %edi, %edi
    0x7fff50b51c83 <+35>: movq   %rdi, %rax
    0x7fff50b51c86 <+38>: retq   
    0x7fff50b51c87 <+39>: nop    
Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:]:
    0x7fff2590ddf0 <+0>:  testq  %rdx, %rdx
    0x7fff2590ddf3 <+3>:  je     0x7fff2590de44            ; <+84>
    0x7fff2590ddf5 <+5>:  pushq  %rbp
    0x7fff2590ddf6 <+6>:  movq   %rsp, %rbp
    0x7fff2590ddf9 <+9>:  pushq  %r15
    0x7fff2590ddfb <+11>: pushq  %r14
    0x7fff2590ddfd <+13>: pushq  %rbx
    0x7fff2590ddfe <+14>: pushq  %rax
    0x7fff2590ddff <+15>: movq   %rdi, %r14
    0x7fff2590de02 <+18>: movq   0x62206d9f(%rip), %rdi    ; (void *)0x00007fff87b1d538: NSConcreteNotification
    0x7fff2590de09 <+25>: movq   0x622003a8(%rip), %rsi    ; "newTempNotificationWithName:object:userInfo:"
    0x7fff2590de10 <+32>: movq   0x5b06b749(%rip), %r15    ; (void *)0x00007fff50b37400: objc_msgSend
    0x7fff2590de17 <+39>: callq  *%r15
    0x7fff2590de1a <+42>: movq   %rax, %rbx
    0x7fff2590de1d <+45>: movq   0x8(%r14), %rdi
    0x7fff2590de21 <+49>: movq   %rax, %rsi
    0x7fff2590de24 <+52>: xorl   %edx, %edx
    0x7fff2590de26 <+54>: callq  0x7fff25ae65d8            ; symbol stub for: _CFXNotificationPost
->  0x7fff2590de2b <+59>: movq   0x6220038e(%rip), %rsi    ; "recycle"
    0x7fff2590de32 <+66>: movq   %rbx, %rdi
    0x7fff2590de35 <+69>: movq   %r15, %rax
    0x7fff2590de38 <+72>: addq   $0x8, %rsp
    0x7fff2590de3c <+76>: popq   %rbx
    0x7fff2590de3d <+77>: popq   %r14
    0x7fff2590de3f <+79>: popq   %r15
    0x7fff2590de41 <+81>: popq   %rbp
    0x7fff2590de42 <+82>: jmpq   *%rax
    0x7fff2590de44 <+84>: retq   

DeviceFieldButton :

class DateFieldButton: UIButton {

    var pattern = String()

    override var isSelected: Bool {
        didSet {
            if #available(iOS 13.0, *) {
                backgroundColor = isHighlighted ?  .highlightKeyboardColor : .keyboardColor
            } else {
                backgroundColor = isHighlighted ?  .highlightLightKeyboard : .lightKeyboard
            }
        }
    }

    override var isHighlighted: Bool {
        didSet {
            if #available(iOS 13.0, *) {
                backgroundColor = isHighlighted ?  .highlightKeyboardColor : .keyboardColor
            } else {
                backgroundColor = isHighlighted ?  .highlightLightKeyboard : .darkKeyboard
            }
        }
    }

}

Usage:

            let button = DateFieldButton(type: .custom)
            button.layer.cornerRadius = 10

            dateFormatter.dateFormat = pattern
            let realPattern = dateFormatter.string(from: Date())

            button.setTitle(realPattern, for: .normal)
            button.titleLabel?.text = realPattern
            button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)

            if #available(iOS 13, *) {
                button.setTitleColor(.blackAndWhite, for: .normal)
            }
            else {
                button.setTitleColor(.black, for: .normal)
            }
            button.pattern = pattern

            button.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)

Upvotes: 3

Views: 563

Answers (1)

vincent
vincent

Reputation: 267

after a day of debugging, I have found the issue to the crash.

Previously I was using this for the receiving end, I was using this:

NotificationCenter.default.addObserver(self, selector: #selector(dateButtonTapped(_:for:)), name: .dateFieldTapped, object: nil)
@objc func dateButtonTapped(_ sender: Notification, for event: UIEvent) {

}

This causes the crash in the Simulator, which does not occur, if the for parameter is removed, which was a left over from another method which I copied over due to laziness.

NotificationCenter.default.addObserver(self, selector: #selector(dateButtonTapped(_:)), name: .dateFieldTapped, object: nil)
@objc func dateButtonTapped(_ sender: Notification) {

}

So, I'm answering my own question, in case others in the future stumble across with the same issue.

By the way, thanks to @Philip Mills in the above comment! That made me look into the receiving end instead of focusing on the posting end.

Upvotes: 5

Related Questions