How get list value in Userdefaults - swift3

I have data with json in one func 1 get data have 1 list value but I go out func call value with userdefault I get 1 value.
func getdevices() {
var token = UserDefaults.standard.string(forKey: "token")
print("token", token)
var username = UserDefaults.standard.string(forKey: "username")
print("username", username)
let url: URL = URL(string: "/public/devices")!
let request: NSMutableURLRequest = NSMutableURLRequest(url: url)
request.httpMethod = "Get"
request.setValue(token , forHTTPHeaderField: "token")
request.setValue(username, forHTTPHeaderField: "username")
var responseError: NSError?
var response: URLResponse?
var urlData: Data?
do {
urlData = try NSURLConnection.sendSynchronousRequest(request as URLRequest, returning:&response)
} catch let error as NSError {
responseError = error
urlData = nil
}
if ( urlData != nil ) {
let res = response as! HTTPURLResponse!;
print("Response code: %ld tra ve" , res?.statusCode);
if ((res?.statusCode)! >= 200 && (res?.statusCode)! < 300)
{
//let responseData:NSString = NSString(data:urlData!, encoding:String.Encoding.utf8.rawValue)!
if let json = try? JSONSerialization.jsonObject(with: urlData!, options: []) as? [String : Any],
//let dataArray = json?["status"] as? [String : Any],
let items = json?["units"] as? [[String : Any]] {
for item in items {
var lat = item["latitude"] as? String
UserDefaults.standard.set(lat, forKey: "latitude")
var test = UserDefaults.standard.double(forKey: "latitude")
print("test", test)
var long = item["longitude"] as? String
UserDefaults.standard.set(long, forKey: "longitude")
print("long", long)
var devid = item["devid"] as? String
UserDefaults.standard.set(devid, forKey: "devid")
var devname = item["devname"] as? String
UserDefaults.standard.set(devname, forKey: "devname")
var speed = item["speed"] as? String
UserDefaults.standard.set(speed, forKey: "speed")
var statustt = item["status"] as? String
UserDefaults.standard.set(statustt, forKey: "statusxe")
var drivername = item["drivername"] as? String
UserDefaults.standard.set(drivername, forKey: "drivername")
var address = item["address"] as? String
UserDefaults.standard.set(address, forKey: "address")
print("address", address)
}
}
}
}
}
But when the app exists the func it doesn't get the list data, it has one value.
override func viewDidAppear(_ animated: Bool) {
GMSServices.provideAPIKey("AIzaSyB2IJzNc2s5km1qvdwAePDEat1OdPsOFVA")
guard let address = UserDefaults.standard.string(forKey: "address") else {return}
getdevices()
var lat = UserDefaults.standard.double(forKey: "latitude")
var long = UserDefaults.standard.double(forKey: "longitude")
var devname = UserDefaults.standard.string(forKey: "devname")
var speed = UserDefaults.standard.string(forKey: "speed")
print("lat", lat)
print("long", long)
print("address***", address)
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: long, zoom: 10)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
view = mapView
let marKer = GMSMarker()
marKer.position = CLLocationCoordinate2D(latitude: lat, longitude: long)
marKer.icon = UIImage(named: "vehicle_105")
marKer.title = "Biển số \(devname)"
//marKer.title = "Speed \(speed)"
marKer.map = mapView
}

You can only store a single object/value under a single key in UserDefaults. The problem is, you are overwriting the value under the same key in each iteration of your loop. What you should do is create an array before the loop, add the values to that array inside the loop and store the array in UserDefaults after the loop finished its iterations.
if let items = json?["units"] as? [[String : Any]] {
var latitudes = [String]()
var longitudes = [String]()
var devids = [String]()
var devnames = [String]()
var speeds = [String]()
var statustts = [String]()
var drivernames = [String]()
var addresses = [String]()
for item in items {
let lat = item["latitude"] as? String
latitudes.append(lat)
let long = item["longitude"] as? String
longitudes.append(long)
let devid = item["devid"] as? String
devids.append(devid)
var devname = item["devname"] as? String
devnames.append(lat)
var speed = item["speed"] as? String
speeds.append(speed)
var statustt = item["status"] as? String
statuses.append(statustt)
var drivername = item["drivername"] as? String
drivernames.append(drivername)
var address = item["address"] as? String
addresses.append(address)
}
UserDefaults.standard.set(latitudes, forKey: "latitude")
UserDefaults.standard.set(longitudes, forKey: "longitude")
UserDefaults.standard.set(devids, forKey: "devid")
UserDefaults.standard.set(devnames, forKey: "devname")
UserDefaults.standard.set(speeds, forKey: "speed")
UserDefaults.standard.set(statustts, forKey: "statusxe")
UserDefaults.standard.set(drivername, forKey: "drivername")
UserDefaults.standard.set(addresses, forKey: "address")
}

Related

how to get multiple parameter in swift

I am new to swift and I am doing a project to create a qr code generator with multiple parameters. I have tried add a parameter with date and it worked.
I don't know how to add more parameters in swift for qr code generator and i want to add more than 4 parameters. When i tried to add parameter, func generateqrcode (default: String, num: Int, time: Date, address: String)-> UIImage {....} after I added the parameters which I have wrotten above sentences, what should i write for the body?
My Orignal Code:
import Foundation
import SwiftUI
import CoreImage.CIFilterBuiltins
struct GenerateQRCode: View {
#State var default = "A1"
#Binding var time: Date
#State var address = "abcdefgh"
#Binding var num: Int
let filter = CIFilter.qrCodeGenerator()
let cont = CIContext()
var dateFormatter: DateFormatter {
let df = DateFormatter()
df.dateFormat = "HH:mm"
return df
}
var body: some View {
NavigationView{
Image(uiImage: imageGenerate(default: default, address: address, time: time, num: num))
.interpolation(.none)
.resizable()
.frame(width: 150, height: 150, alignment: .center)
}.navigationBarBackButtonHidden(true)
}
func generateqrcode(default: String, address: String, time: Date, num: Int)-> UIImage {
let str = dateFormatter.string(from: start)
let data = str.data(using: .utf8)
filter.setValue(data, forKey: "inputMessage")
if let qr = filter.outputImage {
if let qrImage = cont.createCGImage(qr, from: qr.extent){
return UIImage(cgImage: qrImage)
}
}
return UIImage(systemName: "xmark") ?? UIImage()
}
}
What should I add or change for the body? I have tried in my code.
Orignal Version:
func generateqrcode (_ time: Date)-> UIImage {
let str = dateFormatter.string(from: start)
let data = str.data(using: .utf8)
filter.setValue(data, forKey: "inputMessage")
if let qr = filter.outputImage {
if let qrImage = cont.createCGImage(qr, from: qr.extent){
return UIImage(cgImage: qrImage)
}
}
return UIImage(systemName: "xmark") ?? UIImage()
}
Updated Version(Body didn't change same as original version):
func generateqrcode(default: String, address: String, time: Date, num: Int)-> UIImage {
let str = dateFormatter.string(from: start)
let data = str.data(using: .utf8)
filter.setValue(data, forKey: "inputMessage")
if let qr = filter.outputImage {
if let qrImage = cont.createCGImage(qr, from: qr.extent){
return UIImage(cgImage: qrImage)
}
}
return UIImage(systemName: "xmark") ?? UIImage()
}

Copy CoreData data to CSV file

I am trying to use fileExport logic to copy history data from CoreData to a CSV file. Since the data is coming from CoreData I need to use #FetchRequest and it is my understanding that #FetchRequest may only be used in a view.
I'm getting a number of errors related to misusing a view and transferring the data to fileExporter. It seems like I'm misusing a view to transfer data. Are there other features of CoreData that can be used to retrieve data outside of a view?
I have several similar structures that create CSV files without using coreData working. Therefore I believe my structures CreateHistoryTable and MessageDocument are working correctly. So I need help getting my data from CoreData to fileExporter.
struct CreateHistoryTable: View {
#Environment(\.managedObjectContext) var viewContext
#State private var showingExporter: Bool = false
#State private var document: MessageDocument?
var body: some View {
VStack {
Button ( action: {
self.showingExporter = true
document = CreateHistoryCSV() <-- need help here retrieving document to export
}) {
HStack (alignment: .firstTextBaseline) {
Text("Export History Entries")
.fontWeight(.bold)
.font(.title3)
Image(systemName: "square.and.arrow.up")
}
}
}.fileExporter(
isPresented: $showingExporter,
document: document,
contentType: .plainText,
defaultFilename: "TripSenseHistory.csv"
) { result in
switch result {
case .success(let url):
print("Saved to \(url)")
case .failure(let error):
print(error.localizedDescription)
}
}
.navigationBarTitle(Text("Export History Entries"), displayMode: .inline)
}
}
Retrieve data from CoreData and copy to single text string
struct CreateHistoryCSV: View {
#Binding MessageDocument
var csvData: String = ""
var title = ",Trip Sense History Entries,\n"
var subtitle = "Date,Category,Payment Type, Amount\n"
var messageRow: String = ""
var sHisCatName: String = ""
var sHisDsc: String = ""
var sHisPayType: String = ""
var sHisMoney: String = ""
var dHisMoney: Double = 0.0
var sHisLoc: String = ""
var payType = ["Cash", "Debit", "Credit"]
var code: String = ""
var messageRow = ""
// fetch core data
#FetchRequest(
entity: CurrTrans.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \CurrTrans.entryDT, ascending: true)]
) var currTrans: FetchedResults<CurrTrans>
var body: some View {
var csvData = title + subtitle
for item in 0..<currTrans.count {
let messageRow = createHistoryRow(item: item)
csvData += messageRow
}
print(csvData)
//return MessageDocument(message: csvData)
}
func createHistoryRow(item: Int) ->(String) {
// format expense date and time
let dHisDate = currTrans[item].entryDT ?? Date()
let sHisDate = dHisDate.formatted(.dateTime.year().day().month(.wide).hour().minute())
// get history category
let sHisCatName = currTrans[item].entryCatName ?? "cat name"
// get payment type
let sHisPayType = payType[Int(currTrans[item].entryPT)]
// get description
let sHisDsc = currTrans[item].entryDsc ?? "Unk"
// format transaction amount
let code = currTrans[item].entryCode ?? "Unk" // 3 digit country code for this transaction
let dHisMoney = currTrans[item].entryMoney
let sHisMoney = dHisMoney.formatted(.currency(code: sym))
// get location
let sHisLoc = currTrans[item].entryAddr ?? "Unk"
messageRow = "\"\(sHisDate)\"" + "," + sHisCatName + "," + sHisPayType + "," + "\"\(sHisDsc)\"" + "," + "\"\(sHisMoney)\"" + "," + "\"\(sHisLoc)\"" + "\n"
return messageRow
}
}
This code is part of the Swiftui file export logic
struct MessageDocument: FileDocument {
static var readableContentTypes: [UTType] { [.plainText] }
var message: String = ""
init(message: String) {
self.message = message
}
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let string = String(data: data, encoding: .utf8)
else {
throw CocoaError(.fileReadCorruptFile)
}
message = string
}
// this will be called when the system wants to write our data to disk
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
return FileWrapper(regularFileWithContents: message.data(using: .utf8)!)
}
}
With further research I realized that I could place the #FetchRequest in CreateHistoryTable along with the fileExporter view logic. That allowed me to change CreateHistoryCSV to a function of CreateHistoryTable. No changes were made to createHistoryRow
// copy history entrys to csv file
struct CreateHistoryTable: View {
#EnvironmentObject var base: BaseCurrency
#EnvironmentObject var bank: BankWithdrawal
#EnvironmentObject var userData: UserData
#Environment(\.managedObjectContext) var viewContext
#State private var showingExporter: Bool = false
#State private var document: MessageDocument?
var title = ",Trip Sense History Entries,\n"
var subtitle = "Date,Category,Payment Type, Amount\n"
var messageRow: String = ""
var sHisCatName: String = ""
var sHisDsc: String = ""
var sHisPayType: String = ""
var sHisMoney: String = ""
var dHisMoney: Double = 0.0
var sHisLoc: String = ""
var payType = ["Cash", "Debit", "Credit"]
var sym: String = ""
// fetch core data
#FetchRequest(
entity: CurrTrans.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \CurrTrans.entryDT, ascending: true)]
) var currTrans: FetchedResults<CurrTrans>
var body: some View {
VStack {
Button ( action: {
self.showingExporter = true
let dates = userData.formatCsvDate(startDate: startDate, endDate: endDate)
document = CreateHistoryCSV(dates: dates)
}) {
HStack (alignment: .firstTextBaseline) {
Text("Export History Entries")
.fontWeight(.bold)
.font(.title3)
Image(systemName: "square.and.arrow.up")
}
}
}.fileExporter(
isPresented: $showingExporter,
document: document,
contentType: .plainText,
defaultFilename: "TripSenseHistory.csv"
) { result in
switch result {
case .success(let url):
print("Saved to \(url)")
case .failure(let error):
print(error.localizedDescription)
}
}
.navigationBarTitle(Text("Export History Entries"), displayMode: .inline)
}
func CreateHistoryCSV() -> (MessageDocument) {
var csvData = title + subtitle
for item in 0..<currTrans.count {
let messageRow = createHistoryRow(item: item)
csvData += messageRow
}
print(csvData)
return MessageDocument(message: csvData)
}

Swiftui Dynamic Cloudkit predicate results not filling array

I hope someone can help me - I have a dynamic cloudkit array which works fine up until it gets to the List part of my view. In the quertresultBlock when I print returnedItems the records are all there and filtered inline with my predicate. However, the staff array is empty. Its driving me mad. Could someone help please?
struct MarketingModel: Hashable {
let firstName: String
let lastName: String
let country: String
let department: String
let phoneNumber: String
let job: String
let headshot: URL?
let record: CKRecord
}
struct predicateFilter: View {
#State var text: String = ""
#State var staff: [MarketingModel] = []
#State private var countryselected: Country = .Management
var body: some View {
List {
ForEach(staff, id: \.self) { thepeople in
VStack (alignment: .leading) {
Text(thepeople.firstName)
extension predicateFilter {
init(filter: String) {
UISegmentedControl.appearance().selectedSegmentTintColor = UIColor(red: 116/255, green: 152/255, blue: 192/255, alpha: 1.0)
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
//func fetchItems() {
//let predicate = NSPredicate(value: true)
let predicate = NSPredicate(format: "department == %#", filter)
let query = CKQuery(recordType: "Staff", predicate: predicate)
query.sortDescriptors = [NSSortDescriptor(key: "lastName", ascending: true)]
let queryOperation = CKQueryOperation(query: query)
var returnedItems: [MarketingModel] = []
queryOperation.recordMatchedBlock = { (returnedRecordID, returnedResult) in
switch returnedResult {
case .success(let record):
guard let firstName = record["firstName"] as? String else { return }
guard let lastName = record["lastName"] as? String else { return }
guard let department = record["department"] as? String else { return }
guard let country = record["country"] as? String else { return }
guard let mobile = record["phone"] as? String else { return }
guard let job = record["job"] as? String else { return }
let imageAsset = record["headshot"] as? CKAsset
let imageURL = imageAsset?.fileURL
returnedItems.append(MarketingModel(firstName: firstName, lastName: lastName, country: country, department: department, phoneNumber: mobile, job: job, headshot: imageURL, record: record))
case .failure(let error):
print("Error recordMatchedBlock: \(error)")
}
}
queryOperation.queryResultBlock = { [self] returnedResult in
print("RETURNED RESULT \(returnedResult)")
DispatchQueue.main.async {
staff = returnedItems
print(staff)
}
}
addOperation(opertaion: queryOperation)
}
func addOperation(opertaion: CKDatabaseOperation) {
CKContainer.default().publicCloudDatabase.add(opertaion)
print("working")
}
}

Convert HTML text to displayable text in swiftUI [duplicate]

I was wondering how can HTML tags be stripped out of JSON from a web url. Do I have to use NSString of something similar.
So I am looking to strip out the html tags that are in the summary value. I looked around abit and it says NSString can be used but I was not sure if that was something that could be implemented into Swift 3. Any Help would be appreciated.
My code:
import UIKit
import Alamofire
struct postinput {
let mainImage : UIImage!
let name : String!
let author : String!
let summary : String!
}
class TableViewController: UITableViewController {
var postsinput = [postinput]()
var mainURL = "https://www.example.com/api"
typealias JSONstandard = [String : AnyObject]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callAlamo(url: mainURL)
}
func callAlamo(url : String){
Alamofire.request(url).responseJSON(completionHandler: {
response in
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData : Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONstandard
// print(readableJSON)
if let posts = readableJSON["posts"] as? [JSONstandard] {
for post in posts {
let title = post["title"] as! String
let author = post["author"] as! String
guard let dic = post["summary"] as? [String: Any], let summary = dic["value"] as? String else {
return
}
print(author)
if let imageUrl = post["image"] as? String {
let mainImageURL = URL(string: imageUrl )
let mainImageData = NSData(contentsOf: mainImageURL!)
let mainImage = UIImage(data: mainImageData as! Data)
postsinput.append(postinput.init(mainImage: mainImage, name: title, author: author, summary: summary))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
catch {
print(error)
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postsinput.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
// cell?.textLabel?.text = titles[indexPath.row]
let mainImageView = cell?.viewWithTag(2) as! UIImageView
mainImageView.image = postsinput[indexPath.row].mainImage
//(cell?.viewWithTag(2) as! UIImageView).image = postsinput[indexPath.row].mainImage
let mainLabel = cell?.viewWithTag(1) as! UILabel
mainLabel.text = postsinput[indexPath.row].name
mainLabel.font = UIFont(name: "Helvetica", size:14)
let autLabel = cell?.viewWithTag(3) as! UILabel
autLabel.text = postsinput[indexPath.row].author
autLabel.font = UIFont(name: "Helvetica", size:12)
let sumLabel = cell?.viewWithTag(4) as! UILabel
sumLabel.text = postsinput[indexPath.row].summary
sumLabel.font = UIFont(name: "Helvetica", size:12)
//(cell?.viewWithTag(3) as! UILabel).text = postsinput[indexPath.row].author
return cell!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can use this code for stripping html tags
From your previous question
guard let dic = post["summary"] as? [String: Any], let summary = dic["value"] as? String else {
return
}
let str = summary.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
print(str)
Edit
I have checked it and it is working
let summary = "<p>Latin text here</p>"
let str = summary.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
print(str)
Latin text here

list view is not updating in swift UI

I have started project in swiftUI. I am receiving data from web services adding into array list when I am changing data in backend but list view is not updating.
import Foundation
import SwiftUI
import Combine
var orders_List: [OrdersModel] = []
struct OrdersModel: Identifiable,Hashable{
var id: String = UUID().uuidString
let order_no: String
let seat_name: String
let seat_no: String
let time: String
init(id: String, order_no: String,seat_name:String,seat_no:String,time:String){
self.id = id
self.order_no = order_no
self.seat_name = seat_name
self.seat_no = seat_no
self.time = time
}
}
class Order_Manager: ObservableObject {
var objectWillChange = ObservableObjectPublisher()
var fetchedSongsResults = [orders_List] {
willSet {
objectWillChange.send()
}
}
init() {
fetch_orders()
}
func fetch_orders() {
let defaults = UserDefaults.standard
let parameters = ["tokken": "a56af0a01e137f61a44a93398195f5db","order_status":"Submitted"]
guard let url = URL(string: "https://www.appvelo.com/golfcourseios/api/OrderApis/fetch_status_based_orders") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else { return }
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let posts = json["data"] as? [[String: Any]] ?? []
orders_List.removeAll()
for result in posts {
//print(json)
let id = result["id"] as! String
let order_no = result["order_no"] as! String
let seat_no = result["order_no"] as! String
let seat_name = result["seat_type_image"] as! String
let time = result["time"] as! String
let order_Model = OrdersModel(id: id,order_no: order_no, seat_name: seat_name, seat_no: seat_no,time:time)
orders_List.append(order_Model)
// print(order_Model)
}
} catch {
print(error)
}
}
}.resume()
}
}
struct ContentView: View {
var body: some View {
VStack{
List {
ForEach(orders_List){ person in
Text("\(person.order_no)")
}
}
}
}
}
As mentioned in comments, you need to fix your Combine syntax:
class Order_Manager: ObservableObject {
#Published var fetchedSongsResults = [orders_List]
}
You need to remove var objectWillChange = ObservableObjectPublisher()