Search code examples
swiftxcodeswiftuicore-nfc

How can I update the view when the app is done scanning for NFC?


I have a Swift application that reads from an NFC card. I want it to show the data it read on the screen, which I am able to do if I have a button that checks for updated data using the getDetected() function. I want to, however, update the view when it is done reading the NFC tag so I can immediately display the data. How can I do this?

NFC Reader class:

import Foundation
import CoreNFC

class NFCReader: NSObject, NFCNDEFReaderSessionDelegate {
    var detected = [NFCNDEFMessage]()
    var session: NFCNDEFReaderSession?
    func beginScanning() {
        guard NFCNDEFReaderSession.readingAvailable else { return }
        session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
        session?.alertMessage = "Hold your iPhone near the reader to unlock."
        session?.begin()
    }
    func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
        self.detected = messages
        self.session = nil
    }
    func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
        self.session = nil
    }
    func getDetected() -> [NFCNDEFMessage] {
        return detected
    }
}

Solution

  • you could try the following approach, using a ObservableObject. Whenever the @Published var detected is changed, the UI will be updated.

    class NFCReader: NSObject, NFCNDEFReaderSessionDelegate, ObservableObject { // <--- here
        @Published var detected = [NFCNDEFMessage]()  // <--- here
        
        var session: NFCNDEFReaderSession?
        
        func beginScanning() {
            guard NFCNDEFReaderSession.readingAvailable else { return }
            session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true)
            session?.alertMessage = "Hold your iPhone near the reader to unlock."
            session?.begin()
        }
        
        func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
            self.detected = messages
            self.session = nil
        }
        
        func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
            self.session = nil
        }
        
        // no real need for this
        func getDetected() -> [NFCNDEFMessage] {
            return detected
        }
        
    }
    
    
    struct ContentView: View {
        @StateObject var readerNFC = NFCReader()  // <-- here
        
        var body: some View {
            ForEach(readerNFC.detected, id: \.self) { msg in
               //     .....
            }
        }
        
    }