I'm trying to convert my own app from Objective-C to Swift 3.
Try is a sample of my plist:
elements.plist
I'm trying this code I found in another similar question:
//get the path of the plist file
guard let plistPath = Bundle.main.path(forResource: "elements", ofType: "plist") else { return }
print("plistPath:", plistPath)
//load the plist as data in memory
guard let plistData = FileManager.default.contents(atPath: plistPath) else { return }
print("plistData:", plistData)
//use the format of a property list (xml)
var format = PropertyListSerialization.PropertyListFormat.xml
//convert the plist data to a Swift Dictionary
guard let plistDict = try! PropertyListSerialization.propertyList(from: plistData, options: .mutableContainersAndLeaves, format: &format) as? [String : AnyObject] else { return }
print("plistDict:", plistDict)
//access the values in the dictionary
if let value = plistDict["DescrizioneEsercizio"] as? String {
//do something with your value
print(value)
}
Please, let me know how can I import data from plist and access a single field in Swift 3.
Have a look at the plist. It contains an array of dictionaries.
guard let plistDicts = try! PropertyListSerialization.propertyList(from: plistData, options: .mutableContainersAndLeaves, format: &format) as? [[String : AnyObject]]
else {
return
}
// See how it is casted to an Array of Dictionaries ([[String : AnyObject]]) here
Now you can iterate over your dicts and do what you need:
for dict in plistDicts {
if let value = plistDict["DescrizioneEsercizio"] as? String {
//do something with your value
print(value)
}
}
Related
This is a similar approach to Save dictionary to UserDefaults, however, it is intended for SwiftUI, not using a single line like set, so I want to store the value somewhere with a variable so I can call it easily. Also it's different because I'm asking for an initialization.
I have the following:
#Published var mealAndStatus: Dictionary
init() {
mealAndStatus = ["Breakfast": "initial", "Snack": "notSet", "Lunch": "notSet", "Snack2": "notSet", "Dinner": "notSet"]
if let storedDay = UserDefaults.standard.value(forKey: "mealAndStatus") {
mealAndStatus = storedDay as! Dictionary
}
}
1- How do I correctly store that dictionary in UserDefaults in SwiftUI?
2- That init, do I have to call it at the beginning of ContentView? Or can I leave it on the other swift file like that? Not sure how the init gets called.
I already made one with bool working:
#Published var startDay: Bool
init() {
startDay = true
if let storedDay = UserDefaults.standard.value(forKey: "startDay") {
startDay = storedDay as! Bool
}
}
but the dictionary doesn't seem to work. I need to initialize that dictionary and also store it in UserDefaults so I can access it later. Any help is appreciated.
This is the perfect solution I found for SwiftUI:
Store this somewhere, in my case I created a class just for UserDefaults:
#Published var mealAndStatus: [String: Date] =
UserDefaults.standard.dictionary(forKey: "mealAndStatus") as? [String: Date] ?? [:] {
didSet {
UserDefaults.standard.set(self.mealAndStatus, forKey: "mealAndStatus")
}
}
That above initializes the dictionary and also creates a variable to be easily called and use to update the value. This can be modified at lunch time and add new values, that way is initialized with whatever I want.
Furthermore, now on Apple Dev wwdc20 they announced a new way of handling UserDefaults with SwiftUI which may be even better than the above. The propery wrapper is called: #AppStorage.
Using JSONEncoder and JSONDecoder would help you convert to data any struct or dictionary that conforms to codable.
let arrayKey = "arrayKey"
func store(dictionary: [String: String], key: String) {
var data: Data?
let encoder = JSONEncoder()
do {
data = try encoder.encode(dictionary)
} catch {
print("failed to get data")
}
UserDefaults.standard.set(data, forKey: key)
}
func fetchDictionay(key: String) -> [String: String]? {
let decoder = JSONDecoder()
do {
if let storedData = UserDefaults.standard.data(forKey: key) {
let newArray = try decoder.decode([String: String].self, from: storedData)
print("new array: \(newArray)")
return newArray
}
} catch {
print("couldn't decode array: \(error)")
}
return nil
}
// You would put this where you want to save the dictionary
let mealAndStatus = ["Breakfast": "initial", "Snack": "notSet", "Lunch": "notSet", "Snack2": "notSet", "Dinner": "notSet"]
store(dictionary: mealAndStatus, key: arrayKey)
// You would put this where you want to access the dictionary
let savedDictionary = fetchDictionay(key: arrayKey)
On a side note, you probably shouldn't be using standard defaults for storing stuff like this. Storing it as a database, or saving it in a file especially with encryption on eith the database or the file might be a bit safer.
i am new to swift programming, i have spent considerable amount of time figuring out how to parse json response from alamofire server call. My Json response is
{"customer_info":[{"customer_id":"147","response_code":1}]}
and i want to access both variables. My swift code is
Alamofire.request(
URL_USER_REGISTER,
method: .post,
parameters: parameters,
encoding: JSONEncoding.default).responseJSON
{
if let json = response.result.value {
print (json)
}
if let result = response.result.value as? [String:Any] {
var names = [String]()
do {
if let data = data,
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let blogs = json["customer_info"] as? [[String: Any]] {
for blog in blogs {
if let name = blog["customer_id"] as? String {
names.append(name)
}
}
}
} catch {
print("Error deserializing JSON: \(error)")
}
print(names)
}
}
please help
Your code is parsing correctly. Add the following code to your blog loop and get the second variable out
if let response_code = blog["response_code"] as? Int {
//Do something here
}
So the complete code you are looking for is
let str = "{\"customer_info\":[{\"customer_id\":\"147\",\"response_code\":1}]}"
let data = str.data(using: .utf8)
do {
if let data = data,
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let blogs = json["customer_info"] as? [[String: Any]] {
for blog in blogs {
if let name = blog["customer_id"] as? String {
print(name)
}
if let response_code = blog["response_code"] as? Int {
print(response_code)
}
}
}
} catch {
print("Error deserializing JSON: \(error)")
}
i have modified the code and getting result now
if let jsonDict = response.result.value as? [String:Any],
let dataArray = jsonDict["customer_info"] as? [[String:Any]]
{
let nameArray = dataArray.flatMap { $0["customer_id"] as? String }
let nameArray2 = dataArray.flatMap { $0["response_code"] as? Int }
if(dataArray.count>0)
{
//store return customer id and response code
let customer_id_received = nameArray[0]
let response_code_received = nameArray2[0]
if(response_code_received==1)
{
//proceed with storing customer id in global variable
print(nameArray2[0])
}
Here's the code for a 'selection' button, where it passes the NSData to the global variable to be used later.
#IBAction func btnCCTV1(_ sender: Any) {
// Put Your Image URL
let url:NSURL = NSURL(string : "http://cctv-sg.com/images/sr/01.jpg")!
// It Will turn Into Data
let imageData : NSData = NSData.init(contentsOf: url as URL)!
// Data Will Encode into Base64
let str64 = imageData.base64EncodedData(options: .lineLength64Characters)
// Now Base64 will Decode Here
let data: NSData = NSData(base64Encoded: str64 , options: .ignoreUnknownCharacters)!
// turn Decoded String into Data
let dataImage = UIImage(data: data as Data)
// pass the data image to image View.:)
viewImage.image = dataImage
print("====64====")
print (str64)
print(imageData)
GlobalVar.data64 = imageData as NSData
GlobalVar.imageByte=dataImage
}
Inserting the images to the SQLite
#IBAction func btnSave(_ sender: Any) {
let imageDB = FMDatabase(path: databasePath as String)
print("==image====")
// print(GlobalVar.imageByte)
if (imageDB?.open())! {
let insertSQL = "INSERT INTO ImagesDB (images, photo) VALUES ('\(images)', '\(GlobalVar.data64)')"
let result = contactDB?.executeUpdate(insertSQL,
withArgumentsIn: nil)
if !result! {
lblResult.text = "Failed to add images"
print("Error: \(imageDB?.lastErrorMessage())")
} else {
lblResult.text = "Images Added"
}
} else {
print("Error: \(imageDB?.lastErrorMessage())")
}
}
How do I make the images just insert to SQLiteDB only? I am complete newbie in Swift 3, so having trouble to insert the images into the SQLite. Any suggestion or help is appreciated. If there are any similar swift 3 code which are able to insert images into SQLite without using FMDatabase is fine too.
I am trying to write data that is inputted by a user via UITextField to a text file. I am successfully able to do this by the code I have written below. However, when I tried to save more data it will replace the existing data in the textfile with the new data that is being saved. for example, if I save the string 'hello world' and then save another string saying 'bye'. I will only see the string 'bye' in the textfile. Is there a way I can modify my code so I can see 'hello world' on one line of the textile and 'bye' on another.
#IBAction func btnclicked(_ sender: Any) {
self.savedata(value: answer.text!)
}
func savedata (value: String){
let fileName = "Test"
let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = DocumentDirURL.appendingPathComponent(fileName).appendingPathExtension("txt")
print("FilePath: \(fileURL.path)")
let writeString = NSString(string: answer.text!)
do {
// Write to the file
try writeString.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8.rawValue)
} catch let error as NSError {
print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
}
}
Here is an example using FIleHandler, adapted to Swift 3, from here (of course you should add all the error handling code that's missing in my example) :
let dir = FileManager.default.urls(for: FileManager.SearchPathDirectory.cachesDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first!
let fileurl = dir.appendingPathComponent("log.txt")
let string = "\(NSDate())\n"
let data = string.data(using: .utf8, allowLossyConversion: false)!
if FileManager.default.fileExists(atPath: fileurl.path) {
if let fileHandle = try? FileHandle(forUpdating: fileurl) {
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
} else {
try! data.write(to: fileurl, options: Data.WritingOptions.atomic)
}
do {
let fileHandle = try FileHandle(forWritingTo:pathWithFileName)
fileHandle.seekToEndOfFile()
let oldData = try String(contentsOf: pathWithFileName,encoding: .utf8).data(using: .utf8)!
var data = periodValue.data(using: .utf8)!
fileHandle.write(data)
fileHandle.closeFile()
} catch {
print("Error writing to file \(error)")
}
Here is a Swift 4 version as an extension to String.
extension String {
func writeToFile(fileName: String) {
guard let dir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
return
}
let fileUrl = dir.appendingPathComponent(fileName)
guard let data = self.data(using: .utf8) else {
return
}
guard FileManager.default.fileExists(atPath: fileUrl.path) else {
try? data.write(to: fileUrl, options: .atomic)
return
}
if let fileHandle = try? FileHandle(forUpdating: fileUrl) {
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
}
}
let jsonResult = try JSONSerialization.jsonObject(with: jsonData!, options: .mutableContainers) as! NSDictionary
When debugger comes on above line, in debug console there is ->
jsonResult =(NSDictionary) 2 key/value pairs
>[0] = “CompanyList” : 140 elements
>[1] = “StatusTable” : 1 element
jsonResult contains 2 array
Now i wanna to traverse CompanyList using Loop
like
let arr_CompanyList = [CompanyList]()
for dictionary in json as! [[CompanyList]]
{
//arr_CompanyList.append(dictionary)
}
but is gives error
Here is CompanyList Class
public class CompanyList {
public var companyAlt_Key : Int?
public var company_Name : String?
public var tableName : String?
}
How should i do?
You cannot convert your JSON Array response to directly your Class objects array, you need to create your custom class object from the JSON response. Also instead of using NSDictionary in swift use native type Dictionary.
if let jsonResult = (try? JSONSerialization.jsonObject(with: jsonData!, options: [])) as? [String:Any] {
if let companyList = jsonResult["CompanyList"] as? [[String:Any]] {
//Now loop through the companyList array
let arr_CompanyList = companyList.flatMap(CompanyList.init)
//To get array of companyname
let companyNames = companyList.flatMap { $0["Company_Name"] as? String }
print(companyNames)
}
}
Now simply add one init with your CompanyList class like this way.
public class CompanyList {
public var companyAlt_Key : Int?
public var company_Name : String?
public var tableName : String?
init?(dictionary: [String:Any]) {
guard let companyAltKey = dictionary["CompanyAlt_Key"] as? Int,
let companyName = dictionary["Company_Name"] as? String,
let tableName = dictionary["TableName"] as? String else {
return nil
}
self.companyAlt_Key = companyAltKey
self.company_Name = companyName
self.tableName = tableName
}
}
Note: Inside init? method with dictionary you need to access your key that contains value according to your class property.