NFC Money/Transport Card Reading in Swift - ios

I'm trying to build an iOS app for reading money/transportation card (eg. credit card) information. My apps already detect it. However, I still can't get the data inside the byte I retrieve.
Here's my APDU command code:
if case let .iso7816(tag) = nfcTag {
let apdu = NFCISO7816APDU(instructionClass: 13, instructionCode: 0xB2, p1Parameter: 0, p2Parameter: 0, data: ReaderType.cardInfo.rawValue.hexStringToData(), expectedResponseLength: 32)
self.tagSession?.alertMessage = "Select Command Success!"
tag.sendCommand(apdu: apdu) { (data:Data, sw1:UInt8, sw2:UInt8, error:Error?) in
guard error == nil else {
print("Error send command: \(error!)")
session.invalidate(errorMessage: "Error send command: \(error!)")
return
}
self.processingData(data: data, sTag: tag, session: session)
}
}
}
}
Here's my data processing code:
func processingData(data: Data, sTag: NFCISO7816Tag, session: NFCReaderSession) {
print(String(data:data,encoding: .utf8) ?? "")
let tagUIDData = sTag.identifier
var byteData: [UInt8] = []
tagUIDData.withUnsafeBytes { byteData.append(contentsOf: $0) }
var uidString = ""
for byte in byteData {
let decimalNumber = String(byte, radix: 16)
if (Int(decimalNumber) ?? 0) < 10 {
uidString.append("0\(decimalNumber)")
} else {
uidString.append(decimalNumber)
}
}
print("\n\(byteData) converted to Tag UID: \(uidString)")
let value: String = getBalanceTagConverter(byteData.hexa)
print("\ncardUID : \(value)")
self.tagSession?.alertMessage = "Your UID is \(byteData.hexa)"
self.tagSession?.invalidate()
}

Related

Wrong Print Order With Web Request

I am trying to read data from Google Sheet API and get the last 5 rows. Here is my function:
func fetchData() {
let range = "TestSheet"
var convertedLogList : [Log] = []
var fetchResult: [[String]] = []
let query = GTLRSheetsQuery_SpreadsheetsValuesGet.query(withSpreadsheetId: Globals.shared.YOUR_SHEET_ID, range: range)
Globals.shared.sheetService.executeQuery(query) { (ticket, result, error) in
if let error = error {
print(error)
return
}
guard let values = (result as? GTLRSheets_ValueRange)?.values else {
print("No data found.")
return
}
fetchResult = values.map { $0.map { $0 as? String ?? "" } }
for row in fetchResult {
// convert [String] to a Log object
var log = Log()
log.timestamp = row[0]
log.nthTime = row[1]
log.openNew = row[2]
if row.count == 4 {
log.note = row[3]
}
convertedLogList.append(log)
}
print("===== convertedLogList: ", convertedLogList)
}
var latestLogs : [Log] = []
var counter = 0
// take the latest 5 logs
for log in convertedLogList.reversed() {
if counter < convertedLogList.count && counter < 5 {
counter += 1
latestLogs.append(log)
} else {
break
}
}
print("+++++ latestLogs: ", latestLogs)
}
I have 2 print statements in my code but the print order is wrong. Here is the print output:
+++++ latestLogs: []
===== convertedLogList: [Log(id: xxxxxxxxx, timestamp: "10/24/2022", nthTime: "1", openNew: "Yes", note: "), Log(id:xxxxxxx,....) .... ]
I wonder why the print order is wrong. How can I utilize the await with Google Sheet API in Swift to solve this issue?

SwiftUI View not updating when #ObservedObject changes using GCD

I'm still in the early stages with SwiftUI. Everything's been fine up until now, but I'm running into problems with using GCD - never worked with multi-threading before.
I am getting data from various sensors over TCP continuously running in the background. All this seems fine, I can see the data coming across and it appears to be getting stored where I want it...
Raw data
$AIMTW,26.1,C*1E
Contents of struct
(src: "AI", timeStamp: 2021-09-11 10:43:01 +0000, temp: 26.1, units: "ºC")
I think I'm getting the data processing happening on the main thread where it should update my View, but it doesn't update. I expect I've missed something pretty fundamental, but I just can't work out what it is. Any help would be appreciated.
This should hopefully be enough to reproduce the problem. Originally the code would be reading in a constant stream of data from a TCP source; I have modified it to read from a text file. The View should update after each line of the text file.
import Foundation
struct NMEA{
// Mean Temperature of Water
var mtw = (src: "", // Source
timeStamp: Date(), // Generated Time Stamp
temp: 0.0, // temperature
units: "") // unit of measurement, Celsius (C)
}
import SwiftUI
struct ContentView: View {
#ObservedObject var nmeaHandler = NMEAhandler()
var body: some View {
HStack{
Text("Water Temperature: ")
Text(String(nmeaHandler.nmea.mtw.temp))
Text(nmeaHandler.nmea.mtw.units)
}
.onAppear{
nmeaHandler.fetchNMEA()
}
}
}
import Foundation
class NMEAhandler: ObservableObject{
#Published var nmea = NMEA()
func fetchNMEA() {
DispatchQueue.global(qos: .userInitiated).async { self.receiveNMEA()
}
}
private func receiveNMEA() {
do {
let path = Bundle.main.path(forResource: "reprex-input", ofType: "txt") ?? "" // file path for file "data.txt"
let message = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
print(message)
message.enumerateLines(invoking: { (line, stop) -> () in
print("Line = \(line)")
})
DispatchQueue.main.async {
self.prepareSentences(data: message)
print("The View updates now.")
}
} catch {
print("Error:", error)
}
}
private func prepareSentences(data: String){
var messages: [String] = []
var fields: [String] = []
if data != "-"{
messages = data.components(separatedBy: "\r\n")
for message in messages{
fields = message.components(separatedBy: ",")
let lastField = fields.last
let splitLast = lastField?.components(separatedBy: "*") ?? [""]
fields.removeLast(1)
fields.append(contentsOf: splitLast)
let valid = checksum(message: message, checksum: fields.last ?? "")
if valid{
parseNMEA(fields: fields)
// The View should be updated by now
}
}
return
}
}
private func checksum(message: String, checksum: String) -> Bool {
let messageLength = message.count
let firstCharacter = message.first
if messageLength < 5 || firstCharacter != "$"{
return false
}
let actualMessage = message.slice(1, messageLength - 4)
var calcChecksum = 0
for c in actualMessage.utf8 {
calcChecksum = calcChecksum ^ Int(c)
}
if calcChecksum == Int(checksum, radix: 16) ?? 999{
return true
}
return false
}
private func parseNMEA(fields: [String]){
switch fields[0].slice(3, 5){
case "MTW":
nmea.mtw.src = fields[0].slice(1, 2)
nmea.mtw.timeStamp = Date()
nmea.mtw.temp = Double(fields[1]) ?? 0
nmea.mtw.units = "º" + fields[2]
print("MTW: \(nmea.mtw)")
default:
print("Missing sentence: \(fields[0].slice(1, 2))")
return
}
}
}
import Foundation
extension StringProtocol {
func slice(_ start: Int, _ end: Int) -> String {
if self.count >= end {
let lower = index(self.startIndex, offsetBy: start)
let upper = index(lower, offsetBy: end - start)
return String(self[lower...upper])
} else {
return self as! String
}
}
}
Text file used for input:
$AIMTW,24.7,C*1A
$AIMTW,24.9,C*14
$AIMTW,24.8,C*15
$SDMTW,19.4,C*08
$AIMTW,24.9,C*14
$SDMTW,19.4,C*08
$SDMTW,19.4,C*08
$AIMTW,24.7,C*1A
$SDMTW,19.6,C*0A
$AIMTW,23.9,C*13

Unwrapping optional value (returned by data.withUnsafeBytes(_:)) sometimes does not work with guard let

I have issue with guard let statement, which behaves strange. Whole code is below. Else block of statement guard let data = readData, let size = sizeOfData else ... in method readActivity(subdata: Data) is wrongly executed even thoug readData and sizeOfData are not nil.
Code
import Foundation
enum ActivityDataReaderError: Error {
case activityIsReadingOtherCentral
case bluetooth(Error?)
case staleData
}
protocol ActivityDataReaderDelegate: class {
func didReadActivity(data: Data)
func didFailToReadActivity(error: ActivityDataReaderError)
}
final class ActivityDataReader {
private var sizeOfData: Int?
private var isOtherDeviceReading: Bool {
// 0xFFFF
return sizeOfData == 65535
}
private var readData: Data?
var isEmpty: Bool {
return sizeOfData == nil
}
weak var delegate: ActivityDataReaderDelegate?
static func timestampValue(_ timestamp: UInt32) -> Data {
var value = timestamp
return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func reset() {
readData = nil
sizeOfData = nil
NSLog("reset() -- \(Thread.current)")
}
func readActivity(data: Data?, error: Error? = nil) {
guard let data = data else {
delegate?.didFailToReadActivity(error: .bluetooth(error))
return
}
let isFirstChunk = readData == nil
if isFirstChunk {
let sizeData = data.subdata(in: 0..<2)
sizeOfData = sizeData.withUnsafeBytes { $0.pointee }
guard !isOtherDeviceReading else {
delegate?.didFailToReadActivity(error: .activityIsReadingOtherCentral)
return
}
NSLog(String("readActivity() Size of data: \(String(describing: sizeOfData))"))
let subdata = data.subdata(in: 2..<data.count)
readActivity(subdata: subdata)
} else {
readActivity(subdata: data)
}
}
private func readActivity(subdata: Data) {
if let lastReadData = readData {
readData = lastReadData + subdata
} else {
readData = subdata
}
guard let data = readData, let size = sizeOfData else {
NSLog("WTF? data:\(String(describing: readData)), "
+ "sizeOfData: \(String(describing: sizeOfData)), "
+ "thread: \(Thread.current)")
assertionFailure("WTF")
return
}
NSLog("subdata: \(String(describing: subdata)), "
+ "totalReadBytes: \(data.count), "
+ "size: \(size)")
if data.count == size {
delegate?.didReadActivity(data: data)
reset()
}
}
}
Test
Test which sometimes passes and sometimes crashes because of assertionFailure("WTF").
class ActivityDataServiceReaderTests: XCTestCase {
var service: ActivityDataReader?
override func setUp() {
super.setUp()
service = ActivityDataReader()
}
override func tearDown() {
service = nil
super.tearDown()
}
func testBufferIsNotEmpty() {
NSLog("testBufferIsNotEmpty thread: \(Thread.current)")
guard let service = service else { fatalError() }
let firstDataBytes = [UInt8.min]
let data1 = Data(bytes: [7, 0] + firstDataBytes)
service.readActivity(data: data1)
XCTAssertFalse(service.isEmpty)
service.reset()
XCTAssertTrue(service.isEmpty)
}
}
Log of console in case of crash
2018-10-25 14:53:30.033573+0200 GuardBug[84042:11188210] WTF? data:Optional(1 bytes), sizeOfData: Optional(7), thread: <NSThread: 0x600003399d00>{number = 1, name = main}
Environment
Xcode10
swift 4.1 with legacy build system
swift 4.2
In my opinion, there is no possible way to execute code in else block in guard let else block of method readActivity(subdata: Data). Everything is running on main thread. Am I misssing something? How is possible sometimes test passes and sometimes crasshes?
Thank you for any help.
Edit:
More narrow problem of guard let + data.withUnsafeBytes:
func testGuardLet() {
let data = Data(bytes: [7, 0, UInt8.min])
let sizeData = data.subdata(in: 0 ..< 2)
let size: Int? = sizeData.withUnsafeBytes { $0.pointee }
guard let unwrappedSize = size else {
NSLog("failure: \(size)")
XCTFail()
return
}
NSLog("success: \(unwrappedSize)")
}
Log:
2018-10-25 16:32:19.497540+0200 GuardBug[90576:11351167] failure: Optional(7)
Thanks to help at: https://forums.swift.org/t/unwrapping-value-with-guard-let-sometimes-does-not-work-with-result-from-data-withunsafebytes-0-pointee/17357 problem was with the line:
let size: Int? = sizeData.withUnsafeBytes { $0.pointee }
Where read data was downcasted to Optional Int (8 bytes long) but sizeData it self was just 2 bytes long. I have no idea how is possible it sometimes worked but solution -- which seems to work properly -- is to use method withUnsafeBytes in fallowing way:
let size = sizeData.withUnsafeBytes { (pointer: UnsafePointer<UInt16>) in pointer.pointee }
Returned value is not optional and has the proper type UInt16 (2 bytes long).
If you check Documentation, there is a warning:
Warning The byte pointer argument should not be stored and used
outside of the lifetime of the call to the closure.
Seems like You should deal with the size inside the closure body
func testGuardLet() {
let data = Data(bytes: [7, 0, UInt8.min])
var sizeData = data.subdata(in: 0 ..< 2)
withUnsafeBytes(of: &sizeData) { bytes in
print(bytes.count)
for byte in bytes {
print(byte)
}
}
let bytes = withUnsafeBytes(of: &sizeData) { bytes in
return bytes // BUGS ☠️☠️☠️
}
}

Data, UnsafeMutablePointer and extended attributes in Swift 3 [duplicate]

I am looking for a solution to add extended file attributes for a file in swift. I checked this link Write extended file attributes, but the solutions are in objective c and I need a solution for swift.
Here is a possible implementation in Swift 5 as an extension for URL,
with methods to get, set, list, and remove extended attributes of
a file. (Swift 2, 3, and 4 code can be found in the edit history.)
extension URL {
/// Get extended attribute.
func extendedAttribute(forName name: String) throws -> Data {
let data = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> Data in
// Determine attribute size:
let length = getxattr(fileSystemPath, name, nil, 0, 0, 0)
guard length >= 0 else { throw URL.posixError(errno) }
// Create buffer with required size:
var data = Data(count: length)
// Retrieve attribute:
let result = data.withUnsafeMutableBytes { [count = data.count] in
getxattr(fileSystemPath, name, $0.baseAddress, count, 0, 0)
}
guard result >= 0 else { throw URL.posixError(errno) }
return data
}
return data
}
/// Set extended attribute.
func setExtendedAttribute(data: Data, forName name: String) throws {
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
let result = data.withUnsafeBytes {
setxattr(fileSystemPath, name, $0.baseAddress, data.count, 0, 0)
}
guard result >= 0 else { throw URL.posixError(errno) }
}
}
/// Remove extended attribute.
func removeExtendedAttribute(forName name: String) throws {
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
let result = removexattr(fileSystemPath, name, 0)
guard result >= 0 else { throw URL.posixError(errno) }
}
}
/// Get list of all extended attributes.
func listExtendedAttributes() throws -> [String] {
let list = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> [String] in
let length = listxattr(fileSystemPath, nil, 0, 0)
guard length >= 0 else { throw URL.posixError(errno) }
// Create buffer with required size:
var namebuf = Array<CChar>(repeating: 0, count: length)
// Retrieve attribute list:
let result = listxattr(fileSystemPath, &namebuf, namebuf.count, 0)
guard result >= 0 else { throw URL.posixError(errno) }
// Extract attribute names:
let list = namebuf.split(separator: 0).compactMap {
$0.withUnsafeBufferPointer {
$0.withMemoryRebound(to: UInt8.self) {
String(bytes: $0, encoding: .utf8)
}
}
}
return list
}
return list
}
/// Helper function to create an NSError from a Unix errno.
private static func posixError(_ err: Int32) -> NSError {
return NSError(domain: NSPOSIXErrorDomain, code: Int(err),
userInfo: [NSLocalizedDescriptionKey: String(cString: strerror(err))])
}
}
Example usage:
let fileURL = URL(fileURLWithPath: "/path/to/file")
let attr1 = "com.myCompany.myAttribute"
let attr2 = "com.myCompany.otherAttribute"
let data1 = Data([1, 2, 3, 4])
let data2 = Data([5, 6, 7, 8, 9])
do {
// Set attributes:
try fileURL.setExtendedAttribute(data: data1, forName: attr1)
try fileURL.setExtendedAttribute(data: data2, forName: attr2)
// List attributes:
let list = try fileURL.listExtendedAttributes()
print(list)
// ["com.myCompany.myAttribute", "com.myCompany.otherAttribute", "other"]
let data1a = try fileURL.extendedAttribute(forName: attr1)
print(data1a as NSData)
// <01020304>
// Remove attributes
for attr in list {
try fileURL.removeExtendedAttribute(forName: attr)
}
} catch let error {
print(error.localizedDescription)
}

Write extend file attributes swift example

I am looking for a solution to add extended file attributes for a file in swift. I checked this link Write extended file attributes, but the solutions are in objective c and I need a solution for swift.
Here is a possible implementation in Swift 5 as an extension for URL,
with methods to get, set, list, and remove extended attributes of
a file. (Swift 2, 3, and 4 code can be found in the edit history.)
extension URL {
/// Get extended attribute.
func extendedAttribute(forName name: String) throws -> Data {
let data = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> Data in
// Determine attribute size:
let length = getxattr(fileSystemPath, name, nil, 0, 0, 0)
guard length >= 0 else { throw URL.posixError(errno) }
// Create buffer with required size:
var data = Data(count: length)
// Retrieve attribute:
let result = data.withUnsafeMutableBytes { [count = data.count] in
getxattr(fileSystemPath, name, $0.baseAddress, count, 0, 0)
}
guard result >= 0 else { throw URL.posixError(errno) }
return data
}
return data
}
/// Set extended attribute.
func setExtendedAttribute(data: Data, forName name: String) throws {
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
let result = data.withUnsafeBytes {
setxattr(fileSystemPath, name, $0.baseAddress, data.count, 0, 0)
}
guard result >= 0 else { throw URL.posixError(errno) }
}
}
/// Remove extended attribute.
func removeExtendedAttribute(forName name: String) throws {
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
let result = removexattr(fileSystemPath, name, 0)
guard result >= 0 else { throw URL.posixError(errno) }
}
}
/// Get list of all extended attributes.
func listExtendedAttributes() throws -> [String] {
let list = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> [String] in
let length = listxattr(fileSystemPath, nil, 0, 0)
guard length >= 0 else { throw URL.posixError(errno) }
// Create buffer with required size:
var namebuf = Array<CChar>(repeating: 0, count: length)
// Retrieve attribute list:
let result = listxattr(fileSystemPath, &namebuf, namebuf.count, 0)
guard result >= 0 else { throw URL.posixError(errno) }
// Extract attribute names:
let list = namebuf.split(separator: 0).compactMap {
$0.withUnsafeBufferPointer {
$0.withMemoryRebound(to: UInt8.self) {
String(bytes: $0, encoding: .utf8)
}
}
}
return list
}
return list
}
/// Helper function to create an NSError from a Unix errno.
private static func posixError(_ err: Int32) -> NSError {
return NSError(domain: NSPOSIXErrorDomain, code: Int(err),
userInfo: [NSLocalizedDescriptionKey: String(cString: strerror(err))])
}
}
Example usage:
let fileURL = URL(fileURLWithPath: "/path/to/file")
let attr1 = "com.myCompany.myAttribute"
let attr2 = "com.myCompany.otherAttribute"
let data1 = Data([1, 2, 3, 4])
let data2 = Data([5, 6, 7, 8, 9])
do {
// Set attributes:
try fileURL.setExtendedAttribute(data: data1, forName: attr1)
try fileURL.setExtendedAttribute(data: data2, forName: attr2)
// List attributes:
let list = try fileURL.listExtendedAttributes()
print(list)
// ["com.myCompany.myAttribute", "com.myCompany.otherAttribute", "other"]
let data1a = try fileURL.extendedAttribute(forName: attr1)
print(data1a as NSData)
// <01020304>
// Remove attributes
for attr in list {
try fileURL.removeExtendedAttribute(forName: attr)
}
} catch let error {
print(error.localizedDescription)
}

Resources