Hey everyone! While working on an app which reads the Unique Identifiers of NFC tags I ran into a problem. When I run the code the phone is able to read the tag and add the UID into an array (I checked this by making it print the array whenever the array is updated) but I am unable to make the View update. The reason this is tricky is that when you press a button on the view, it activates the reader function reader.activate() which then updates the array in the Data class only if it successfully extracted the UID. How would I make the View reload every time a new UID is added to the array? Below is the code for the content view, Data class and then the NFC reader. Thanks!
View:
struct ContentView: View {
@StateObject var data = Data()
let reader : NFCReader = NFCReader()
var body: some View {
NavigationView {
List {
Section(
header: Text("\(data.itemCount)" + " Items")
) { ForEach(data.products, id: \.self) {
product in Text(product)
}
.onDelete(perform: data.deleteItem)
.onMove(perform: data.moveItem)
}
}
.navigationTitle("My Products")
.navigationBarItems(leading: EditButton(), trailing: AddButton)
.navigationViewStyle(.stack)
}
.environmentObject(data)
}
var AddButton: some View {
Button(action: {
reader.activate()
// Next, once reader.activate() is done and sends data the tagUID, i need to open a new view with text imputs for name and description of product.
}, label: {
Image(systemName: "iphone.radiowaves.left.and.right")
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
// Do I need EnvironmentObject here???
.environmentObject(Data())
}
}
Data class:
//import Foundation
class Data: ObservableObject {
var tagCode = "UID"
@Published var products: [String] = []
@Published var itemCount = 0
func addItem() {
products.append(tagCode)
itemCount = itemCount + 1
print(tagCode + " Works!")
print(products)
}
func deleteItem(indexSet : IndexSet) {
products.remove(atOffsets: indexSet)
itemCount = itemCount - 1
}
func moveItem(indices : IndexSet, newOffset : Int) {
products.move(fromOffsets: indices, toOffset: newOffset)
}
}
NFC Reader:
import Foundation
import CoreNFC
import SwiftUI
class NFCReader: NSObject, ObservableObject, NFCTagReaderSessionDelegate {
var data : Data = Data()
private var tagUID = "UID"
private var session: NFCTagReaderSession?
func activate() {
self.session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self)
self.session?.alertMessage = "Hold Your Phone Near NFC Tag"
self.session?.begin()
}
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
print("Session Begun!")
}
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
print("Error with Launching Session")
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
print("Connecting To Tag")
if tags.count > 1{
session.alertMessage = "More Than One Tag Detected, Please try again"
session.invalidate()
}
let tag = tags.first!
session.connect(to: tag) { [self] (error) in
if nil != error{
session.invalidate(errorMessage: "Connection Failed")
}
if case let .miFare(sTag) = tag{
let UID = sTag.identifier.map{ String(format: "%.2hhx", $0)}.joined()
print("UID:", UID)
print(sTag.identifier)
session.alertMessage = "UID Captured"
session.invalidate()
DispatchQueue.main.async {
self.tagUID = "\(UID)"
data.tagCode = "\(UID)"
data.addItem()
// add inputview change here
}
}
}
}
}
Post
Replies
Boosts
Views
Activity
Hey everyone! So I've been creating a program to extract the UID (unique identifier) from an NFC Tag and have been stuck on this very last problem: On the third line I created a variable which I want to be able to change called tagUID, initially just "UID". If you look down to the very last line of code, you see that (if there is a connection to the tag) the last thing it's supposed to do is change the state of tagUID to whatever the UID of the tag is, but it's refusing to do so. Everything else works great its only not changing that variable!
class NFCReader: NSObject, ObservableObject, NFCTagReaderSessionDelegate {
@State var tagUID = "UID"
var session: NFCTagReaderSession?
func activate() {
self.session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self)
self.session?.alertMessage = "Hold Your Phone Near the NFC Tag"
self.session?.begin()
}
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
print("Session Begun!")
}
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
print("Error with Launching Session")
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
print("Connecting To Tag")
if tags.count > 1{
session.alertMessage = "More Than One Tag Detected, Please try again"
session.invalidate()
}
let tag = tags.first!
session.connect(to: tag) { [self] (error) in
if nil != error{
session.invalidate(errorMessage: "Connection Failed")
}
if case let .miFare(sTag) = tag{
let UID = sTag.identifier.map{ String(format: "%.2hhx", $0)}.joined()
print("UID:", UID)
print(sTag.identifier)
session.alertMessage = "UID Captured"
session.invalidate()
DispatchQueue.main.async {
self.tagUID = "\(UID)"
}
tagUID = "\(UID)"
}
}
}
}
Hey again, I recently asked about updating a variable but now have a new problem. I am creating an NFC reader which when I press scan it prints the UID (Unique Identifier) of the NFC in a text field. When the button labeled "Scan" is pressed, the function activate() runs which activates the NFC reader and updates a variable within the NFCReader class called tagUID to the UID of the NFC chip. After activate() the button then changes tagCode to equal tagUID. The problem is that I want it to update only after the NFCTagReaderSession ends, as it only updates it to the previous UID scanned right now as it did not finish scanning before I update the variable. How do I do this? The code is below:
struct ContentView: View {
let reader: NFCReader = NFCReader()
@State var tagCode = "UID"
var body: some View {
VStack{
Text(tagCode)
Button {
reader.activate()
tagCode = reader.tagUID
} label: {
Text("Scan")
.font(.title)
}.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
class NFCReader: NSObject, ObservableObject, NFCTagReaderSessionDelegate {
var tagUID = "UID"
var session: NFCTagReaderSession?
func activate() {
self.session = NFCTagReaderSession(pollingOption: .iso14443, delegate: self)
self.session?.alertMessage = "Hold Your Phone Near the NFC Tag"
self.session?.begin()
}
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
print("Session Begun!")
}
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
print("Error with Launching Session")
}
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
print("Connecting To Tag")
if tags.count > 1{
session.alertMessage = "More Than One Tag Detected, Please try again"
session.invalidate()
}
let tag = tags.first!
session.connect(to: tag) { [self] (error) in
if nil != error{
session.invalidate(errorMessage: "Connection Failed")
}
if case let .miFare(sTag) = tag{
let UID = sTag.identifier.map{ String(format: "%.2hhx", $0)}.joined()
print("UID:", UID)
print(sTag.identifier)
session.alertMessage = "UID Captured"
session.invalidate()
DispatchQueue.main.async {
self.tagUID = "\(UID)"
}
}
}
}
}