Optional and onTapGesture

Following this thread : https://developer.apple.com/forums/thread/670309

I previously created a structure in order to store what is contained in my NDEF tag.
After displaying all its data [from the tag], I need to update it and to format the received data and update it into a String.

Here is where I am having an issue.
When I fill the string inside onTapGesture method. Nothing is happening. Here is the code :
Code Block Swift
/* nfcWriteButton(data: $data) */
/* I would like to perform the onTapGesture here instead of the button. The Button is for debug purposes */
Button(action: {
        print("\(self.nfcData.lastName)") /* 1 */
print("\(String(describing:self.deciphered["lastName"])")) /* 1 */ /* displaying `Optional("Paul")` */
        print(self.data) /* 2 */
    }) {
        Text("UPDATE - test")
    }
        .onTapGesture {
            self.data = "lastName:\(self.deciphered["lastName"])\ngender:\(self.deciphered["gender"])\nfirstName:\(self.deciphered["firstName"])\nage:\(self.deciphered["age"])\n"
print("self.data")
        }

I noticed that (1) printed the updated value. Whereas (2) prints the data string as it got it, without the update made in the onTapGesture
Then I also noticed that the print un the onTapGesture is never executed. 

Is is normal because I'm doing this onTapGesture for the button and it won't accept it because there is already the action in the first part of the Button?
Will it - the onTapGesture method - work for nfcWriteButton?

Here is part of the code of this button: 
Code Block Swift
struct nfcWriteButton : UIViewRepresentable {
    @Binding var data: String
    func updateUIView(_ uiView: UIButton, context: Context) {    }
    func makeUIView(context: UIViewRepresentableContext<nfcWriteButton>) -> UIButton {
        let button = UIButton()
        button.setTitle("Write on Tag", for: .normal)
        button.addTarget(context.coordinator, action: #selector(context.coordinator.beginScan(_:)), for: .touchUpInside)
        return button
    }
    func makeCoordinator() -> nfcWriteButton.Coordinator {
        return Coordinator(data: $data)
    }
}

Answered by Paul_a_Dance in 658486022
Here is the solution.

Instead of using onTapGesture, I used a Observable class where I stored all the data from the tag.
Code Block Swift
struct NFCWriteButton : UIViewRepresentable {
    @Binding var data: String
    @ObservedObject var dataToWrite: NFCData
    func updateUIView(_ uiView: UIButton, context: Context) {    }
    func makeUIView(context: UIViewRepresentableContext<NFCWriteButton>) -> UIButton {
        let button = UIButton()
        button.setTitle("Write on Tag", for: .normal)
        button.addTarget(context.coordinator, action: #selector(context.coordinator.beginScan(_:)), for: .touchUpInside)
        return button
    }
    func makeCoordinator() -> NFCWriteButton.Coordinator {
        return Coordinator(data: $data, toWrite: _dataToWrite)
    }
    class Coordinator: NSObject, NFCNDEFReaderSessionDelegate {
        var session : NFCNDEFReaderSession?
        @ObservedObject var dataToWrite: NFCDataSec = NFCDataSec()
        @Binding var data: String
        @ObservedObject var nfcData: NFCData
        @objc func beginScan(_ sender: Any) {
            guard NFCNDEFReaderSession.readingAvailable else {
                print("error: Scanning not support")
                return
            }
            session = NFCNDEFReaderSession(delegate: self, queue: .main, invalidateAfterFirstRead: true)
            session?.alertMessage = "Hold your iphone near to scan."
            session?.begin()
        }
        init(data: Binding<String>, toWrite: ObservedObject<NFCData>) {
            _data = data
            _nfcData = toWrite
        }


it won't accept it because there is already the action in the first part of the Button?

It depends on the internal implementation of SwiftUI. We cannot say why, but it is clear under the current implementation of SwiftUI on iOS, the closure passed to onTapGesture is not executed.

Will it - the onTapGesture method - work for nfcWriteButton?

UIViewRepresentable and hidden Coordinator are making things more complex, and it depends on how you define the word work. But as far as I tried, the closure passed to onTapGesture is called, but the target-action method is not.


Generally, you should better not write such fragile code, meaning depending on the implementation detail of the frameworks.
  • Do not put onTapGesture on Button and write all things to do in the action closure

  • Add action closure to your nfcWriteButton (in Swift, type names should start with Capital letter) like Button

Do not put onTapGesture on Button and write all things to do in the action closure

The onTapGesture is called properly when called for the NFCWriteButton. I may need to consolidate my code in order to make it cleaner and safer.

Add action closure to your nfcWriteButton (in Swift, type names should start with Capital letter) like Button

I forgot the capital letter, I put it everywhere else in my code. I will look how to do it with UIButton().addTarget method.

I may need to consolidate my code in order to make it cleaner and safer.

We do not call something safer or cleaner when it does not work as expected or not work steadily. In case of NFCWriteButton, beginScan will not be called. Is that what you want?

I will look how to do it with UIButton().addTarget method.

Please share your solution when you solved it, or please show your latest code if you cannot solve it yourself.
Accepted Answer
Here is the solution.

Instead of using onTapGesture, I used a Observable class where I stored all the data from the tag.
Code Block Swift
struct NFCWriteButton : UIViewRepresentable {
    @Binding var data: String
    @ObservedObject var dataToWrite: NFCData
    func updateUIView(_ uiView: UIButton, context: Context) {    }
    func makeUIView(context: UIViewRepresentableContext<NFCWriteButton>) -> UIButton {
        let button = UIButton()
        button.setTitle("Write on Tag", for: .normal)
        button.addTarget(context.coordinator, action: #selector(context.coordinator.beginScan(_:)), for: .touchUpInside)
        return button
    }
    func makeCoordinator() -> NFCWriteButton.Coordinator {
        return Coordinator(data: $data, toWrite: _dataToWrite)
    }
    class Coordinator: NSObject, NFCNDEFReaderSessionDelegate {
        var session : NFCNDEFReaderSession?
        @ObservedObject var dataToWrite: NFCDataSec = NFCDataSec()
        @Binding var data: String
        @ObservedObject var nfcData: NFCData
        @objc func beginScan(_ sender: Any) {
            guard NFCNDEFReaderSession.readingAvailable else {
                print("error: Scanning not support")
                return
            }
            session = NFCNDEFReaderSession(delegate: self, queue: .main, invalidateAfterFirstRead: true)
            session?.alertMessage = "Hold your iphone near to scan."
            session?.begin()
        }
        init(data: Binding<String>, toWrite: ObservedObject<NFCData>) {
            _data = data
            _nfcData = toWrite
        }


Optional and onTapGesture
 
 
Q