Save Data to .Plist File in Swift

Save Data to .plist File in Swift

Apparently the file is not in a writable location, so I created it in the documents directory.

var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var path = paths.stringByAppendingPathComponent("data.plist")
var fileManager = NSFileManager.defaultManager()
if (!(fileManager.fileExistsAtPath(path)))
{
var bundle : NSString = NSBundle.mainBundle().pathForResource("data", ofType: "plist")
fileManager.copyItemAtPath(bundle, toPath: path, error:nil)
}
data.setObject(object, forKey: "object")
data.writeToFile(path, atomically: true)

Then, it has to be read from the documents directory.

var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var path = paths.stringByAppendingPathComponent("data.plist")
let save = NSDictionary(contentsOfFile: path)

Save data to .plist file in Swift 3

you can try this code:

class SavedTracks: NSObject,NSCoding {
var name: String
var location: String

required init(name:String="", location:String="") {
self.name = name
self.location = location
}

required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "Name") as? String ?? ""
self.location = decoder.decodeObject(forKey: "location") as? String ?? ""
}

func encode(with coder: NSCoder) {
coder.encode(name, forKey:"Name")
coder.encode(location, forKey:"location")
}
}
class DataModel: NSObject {

var saveTrack = [SavedTracks]()

override init(){
super.init()
print("document file path:\(documentsDirectory())")
print("Data file path:\(dataFilePath())")
}

//save data
func saveData() {
let data = NSMutableData()
let archiver = NSKeyedArchiver(forWritingWith: data)
archiver.encode(saveTrack, forKey: "userList")
archiver.finishEncoding()
data.write(toFile: dataFilePath(), atomically: true)
}

//read data
func loadData() {
let path = self.dataFilePath()
let defaultManager = FileManager()
if defaultManager.fileExists(atPath: path) {
let url = URL(fileURLWithPath: path)
let data = try! Data(contentsOf: url)
let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
saveTrack = unarchiver.decodeObject(forKey: "userList") as! Array
unarchiver.finishDecoding()
}
}

func documentsDirectory()->String {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask, true)
let documentsDirectory = paths.first!
return documentsDirectory
}

func dataFilePath ()->String{
return self.documentsDirectory().appendingFormat("/userList.plist")
}
}
class ViewController: UIViewController {
var dataModel = DataModel()

override func viewDidLoad() {
super.viewDidLoad()
onCreateData()
}

//create data
func onCreateData(){
dataModel.saveTrack.append(SavedTracks(name: "jack", location: "xxx"))
dataModel.saveTrack.append(SavedTracks(name: "tom", location: "yyyy"))
dataModel.saveTrack.append(SavedTracks(name: "rose", location: "zzz"))
}

@IBAction func saveData(_ sender: UIButton) {
dataModel.saveData()
print("succeed")
}

@IBAction func printData(_ sender: UIButton) {
dataModel.loadData()
print("succeed!", dataModel.saveTrack)
}
}

How can i save, retrieve, delete & update my data in Plist file in ios?

I am going through with screenshot and step by step. Please follow this and you will get your answer.

First you have to create Property List through your Xcode.

Step:1

Sample Image

Step:2

Sample Image

Step:3

Save data on your save button action :

   // Take 3 array for save the data .....

-(IBAction)save_Action:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"manuallyData.plist"];

[self.nameArr addObject:self.nameField.text];
[self.countryArr addObject:self.countryField.text];
[self.imageArr addObject:@"image.png"];

NSDictionary *plistDict = [[NSDictionary alloc] initWithObjects: [NSArray arrayWithObjects: self.nameArr, self.countryArr, self.imageArr, nil] forKeys:[NSArray arrayWithObjects: @"Name", @"Country",@"Image", nil]];

NSError *error = nil;
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];

if(plistData)
{
[plistData writeToFile:plistPath atomically:YES];
alertLbl.text = @"Data saved sucessfully";
}
else
{
alertLbl.text = @"Data not saved";
}
}
// Data is saved in your plist and plist is saved in DocumentDirectory

Step:4

Retrieve Data from plist File:

    NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"manuallyData.plist"];

if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:@"manuallyData" ofType:@"plist"];
}

NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.nameArr = [dict objectForKey:@"Name"];
self.countryArr = [dict objectForKey:@"Country"];

Step:5

Remove data from plist file:

    NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"manuallyData.plist"];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:(NSString *)plistPath];

self.nameArr = [dictionary objectForKey:@"Name"];
self.countryArr = [dictionary objectForKey:@"Country"];

[self.nameArr removeObjectAtIndex:indexPath.row];
[self.countryArr removeObjectAtIndex:indexPath.row];

[dictionary writeToFile:plistPath atomically:YES];

Step:6

Update your data on Update click Action:

    NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"manuallyData.plist"];

if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:@"manuallyData" ofType:@"plist"];
}

self.plistDic = [[NSDictionary alloc] initWithContentsOfFile:plistPath];

[[self.plistDic objectForKey:@"Name"] removeObjectAtIndex:self.indexPath];
[[self.plistDic objectForKey:@"Country"] removeObjectAtIndex:self.indexPath];
[[self.plistDic objectForKey:@"Image"] removeObjectAtIndex:self.indexPath];

[[self.plistDic objectForKey:@"Name"] insertObject:nameField.text atIndex:self.indexPath];
[[self.plistDic objectForKey:@"Country"] insertObject:countryField.text atIndex:self.indexPath];
[[self.plistDic objectForKey:@"Image"] insertObject:@"dhoni.jpg" atIndex:self.indexPath];

[self.plistDic writeToFile:plistPath atomically:YES];

Write and Read a plist in swift with simple data

Update for Swift 4

I have created SwiftyPlistManager. Take a look at it on GiHub and follow these video instructions:

YouTube Documentation

https://www.youtube.com/playlist?list=PL_csAAO9PQ8bKg79CX5PEfn886SMMDj3j

Update for Swift 3.1

let BedroomFloorKey = "BedroomFloor"
let BedroomWallKey = "BedroomWall"
var bedroomFloorID: Any = 101
var bedroomWallID: Any = 101

func loadGameData() {

// getting path to GameData.plist
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
let documentsDirectory = paths.object(at: 0) as! NSString
let path = documentsDirectory.appendingPathComponent("GameData.plist")

let fileManager = FileManager.default

//check if file exists
if !fileManager.fileExists(atPath: path) {

guard let bundlePath = Bundle.main.path(forResource: "GameData", ofType: "plist") else { return }

do {
try fileManager.copyItem(atPath: bundlePath, toPath: path)
} catch let error as NSError {
print("Unable to copy file. ERROR: \(error.localizedDescription)")
}
}

let resultDictionary = NSMutableDictionary(contentsOfFile: path)
print("Loaded GameData.plist file is --> \(resultDictionary?.description ?? "")")

let myDict = NSDictionary(contentsOfFile: path)

if let dict = myDict {
//loading values
bedroomFloorID = dict.object(forKey: BedroomFloorKey)!
bedroomWallID = dict.object(forKey: BedroomWallKey)!
//...
} else {
print("WARNING: Couldn't create dictionary from GameData.plist! Default values will be used!")
}
}

func saveGameData() {

let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
let documentsDirectory = paths.object(at: 0) as! NSString
let path = documentsDirectory.appendingPathComponent("GameData.plist")

let dict: NSMutableDictionary = ["XInitializerItem": "DoNotEverChangeMe"]
//saving values
dict.setObject(bedroomFloorID, forKey: BedroomFloorKey as NSCopying)
dict.setObject(bedroomWallID, forKey: BedroomWallKey as NSCopying)
//...

//writing to GameData.plist
dict.write(toFile: path, atomically: false)

let resultDictionary = NSMutableDictionary(contentsOfFile: path)
print("Saved GameData.plist file is --> \(resultDictionary?.description ?? "")")
}

Here's what I use to read/write a plist file in swift:

let BedroomFloorKey = "BedroomFloor"
let BedroomWallKey = "BedroomWall"
var bedroomFloorID: AnyObject = 101
var bedroomWallID: AnyObject = 101

func loadGameData() {

// getting path to GameData.plist
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths[0] as String
let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")

let fileManager = NSFileManager.defaultManager()

//check if file exists
if(!fileManager.fileExistsAtPath(path)) {
// If it doesn't, copy it from the default file in the Bundle
if let bundlePath = NSBundle.mainBundle().pathForResource("GameData", ofType: "plist") {

let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
println("Bundle GameData.plist file is --> \(resultDictionary?.description)")

fileManager.copyItemAtPath(bundlePath, toPath: path, error: nil)
println("copy")
} else {
println("GameData.plist not found. Please, make sure it is part of the bundle.")
}
} else {
println("GameData.plist already exits at path.")
// use this to delete file from documents directory
//fileManager.removeItemAtPath(path, error: nil)
}

let resultDictionary = NSMutableDictionary(contentsOfFile: path)
println("Loaded GameData.plist file is --> \(resultDictionary?.description)")

var myDict = NSDictionary(contentsOfFile: path)

if let dict = myDict {
//loading values
bedroomFloorID = dict.objectForKey(BedroomFloorKey)!
bedroomWallID = dict.objectForKey(BedroomWallKey)!
//...
} else {
println("WARNING: Couldn't create dictionary from GameData.plist! Default values will be used!")
}
}

func saveGameData() {

let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as NSString
let path = documentsDirectory.stringByAppendingPathComponent("GameData.plist")

var dict: NSMutableDictionary = ["XInitializerItem": "DoNotEverChangeMe"]
//saving values
dict.setObject(bedroomFloorID, forKey: BedroomFloorKey)
dict.setObject(bedroomWallID, forKey: BedroomWallKey)
//...

//writing to GameData.plist
dict.writeToFile(path, atomically: false)

let resultDictionary = NSMutableDictionary(contentsOfFile: path)
println("Saved GameData.plist file is --> \(resultDictionary?.description)")
}

The plist file is this:





BedroomFloor
101
BedroomWall
101
XInitializerItem
DoNotEverChangeMe


How to read and save data from a remote plist file

No, there isn't a native way to read and write to an external .plist using just Swift without downloading the file, making changes and re-uploading it. Alternatively, you'd need to set up your own API on a server in order to carry out the read / write actions for you.

As @Scott H stated in the comments, theres a better way to do this:

If you want to go this route, download the file locally, change it
locally, and then upload to the server. However, there are many
alternatives available to you for remote configuration like CloudKit,
Parse, or similar.

Learn more about 3rd party options:

  • CloudKit
  • Parse

How to write data in plist?

I don't know if I understand your question, but if you want to write into a .plist within your .app bundle you are probably doing something wrong. If you want to store preferences, you should consider using NSUserDefaults.

If you really want to modify a bundled .plist - here is some code:

NSString *plistPath = nil;
NSFileManager *manager = [NSFileManager defaultManager];
if (plistPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Info.plist"])
{
if ([manager isWritableFileAtPath:plistPath])
{
NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
[infoDict setObject:[NSNumber numberWithBool:hidden] forKey:@"LSUIElement"];
[infoDict writeToFile:plistPath atomically:NO];
[manager changeFileAttributes:[NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate] atPath: [[NSBundle mainBundle] bundlePath]];
}
}

Update:

Nate Flink pointed out that some of the NSFileManager methods used above are deprecated.
He posted an answer with the replacement methods below:
https://stackoverflow.com/a/12428472/100848



Related Topics



Leave a reply



Submit