Storing / updating value in custom .plist - ios

Im starting to get really frustrated, as every example I can find is coded in swift versions older than 3..
But really what I want, is to store / update a value in my custom .plist file.
I managed to get my view to read my value from the .plist into a label like this:
if let path = Bundle.main.path(forResource: "DIREKT", ofType: "plist") {
if let dic = NSDictionary(contentsOfFile: path){
cityLabel.text = dic.object(forKey: "City") as! String?
}
}
but I also want to update the value in my "settings" view as well
I have no clue whatsoever as to how this should be done, so I could really use some help to get started. I tried to look for solutions here, and on YT as well, but all I get is errors. Now i have spend 7 hours trying to solve this.

Related

Get Reference to SceneKit Catalog Swift

I must be missing something simple - I'm trying to iterate through the
files in an .scnassets folder but can't seem to get a reference to the
folder/catalog.
Here's the organizer:
Models.scnassets contains one file. I tried this:
let fileManager = FileManager.default
let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let docsURL = urls.first
let assetFolderPath = docsURL?.appendingPathComponent("Models.scnassets").path
And I tried this and several other variants:
let modelPathString = "ARAds/Models.scnassets"
Then I attempted to count the files with both of the above paths:
do {
let modelPathDirectoryFiles = try fileManager.contentsOfDirectory(atPath: assetFolderPath!)
//or modelPathString
print(modelPathDirectoryFiles.count)
} catch {
print("error getting list of files")
}
I get the error message in all cases.
I assume there must be some special way to get a reference to a SceneKit
Catalog but I have not been able to find that in the Apple docs nor SO.
Any guidance would be appreciated. iOS 11.4 Xcode 10.0
Looking at your code, the first thing I see, is that you are referencing the Documents Directory which isn't actually where your folder is.
The Documents Directory is a folder on your actual device where you might save user data or other files which can be accessed at a latter date (for example via iTunes Sharing).
If you move your Models.scnassets folder under the yellow ArAds folder you should be able to access your content like so:
let myModelToLocate = SCNScene(named: "Models.scnassets/Phone_01.scn")
Hope it helps...
You've pointed me in a better direction, but I can already get the scn and make a node if I know the name. What I really want to do is populate a tableview with the options that are available - so I need to find the current list of scene files.
I think this will work:
let subdir = Bundle.main.resourceURL!.appendingPathComponent("Models.scnassets").path
do {
let modelPathDirectoryFiles = try fileManager.contentsOfDirectory(atPath: subdir)
print(modelPathDirectoryFiles.count) //this works
//then do my thing with the array
} catch {
print("error getting list of files")
}
This seems to work, whether I move the folder or not.

How to unarchive custom object to something other than custom class in Swift

I have an object where we used NSKeyedArchiver to archive as class Foo
Then I changed the target name from Apple to Orange. And it went into production and users started crashing on startup. But not all. And logs point to NSKeyedUnarchiver
I went and grabbed the archived Foo file from when the target was called Apple and when it was called Orange and converted to xml so I could read it. The main and only difference (I think) is that the classname key is Apple.Foo and Orange.Foo respectively.
How can I get one of the archived files and check it's archived class name?
If I do NSKeyedUnarchiver.unarchiveObject(withFile: path) as? Foo it will crash.
Ideally I'd so something like:
let object = NSKeyedUnarchiver.unarchiveObject(withFile: path) as? [String : Any]
let name = object!["classname"]!
if name == "Apple.Foo" {
//delete the cache and let it rebuild
}
But obviously it doesn't work like this. Any ideas on how I can check that I have a corrupted file and get it deleted without the app crashing?
Thanks for the help!
Over the last few days I learned that you can set two different class names for the unarchiver at the same time and they'll both work:
NSKeyedUnarchiver.setClass(Foo.classForKeyedUnarchiver(), forClassName: "Apple.Foo")
NSKeyedUnarchiver.setClass(Foo.classForKeyedUnarchiver(), forClassName: "Orange.Foo")
Now it doesn't matter what classname the file actually has at the time of unarchiving.

Accessing a Sound-File via NSBundle - pathForResource

So I'm just trying to get into iOS Programming by going through some Online-Video-Courses. The problem is, that those are not up-to-date with Swift 3.
In the project I am at the moment it is required to import a Sound-File via the NSBundle-Framework using the following:
let path = NSBundle.mainBundle().pathForResource(name, ofType:)
The problem is, that I won't get this running in Swift 3 and I'm not able to get the right pieces off the Apple Documentation. So my Code looks the following:
import AVFoundation
import Foundation //don't know if this is right by 100 per cent
let path = NSBundle.mainBundle().pathForResource("btn", ofType: "wav")
But it seems like It doesn't even know the Class NSBundle, because Auto-Completion isn't even offering me any functions of NSBundle. I can't seem to find the right pieces which changed in Swift 3 to get this thing working. Anybody here who's able to help me with this?
I believe this is the ticket:
let path = Bundle.main.path(forResource: "btn", ofType: "wav")

How to access information stored in the Root.plist Settings Bundle (Swift)

I did some searching yesterday, but I couldn't really find anything that satisfactorily answered my question. I was helping a friend of mine, and he had part of his information stored for the app in the Settings.app, with a Root.plist file in the settings bundle holding the information. I had no prior experience to working with this, so I was unsure how to get this information. I tried let bundle = NSBundle.mainBundle().pathforResource("Root", ofType: "plist") but this just returned nil. So what would be the proper way to access this information?
I am using Xcode 13.4.1 and Swift 5. Here are the codes to get Root.plist in the main bundle:
let settingsBundle = Bundle.main.path(forResource: "Settings", ofType: "bundle")
let url = URL(fileURLWithPath: settingsBundle!)
let rootPlist = url.appendingPathComponent("Root.plist").path
let dic = NSDictionary(contentsOfFile: rootPlist)
print(dic ?? "")
The first step is to get the path to the main bundle's "Settings.bundle". Next, build a URL for this path. The final step is to add "Root.plist" to the url. My print can get the content of my Root.plist content.
Here is another usage based on this finding. In my project, there are some user default settings defined in the Settings.bundle. Those user default setting names can be localized. The localization string files are within this Settings.bundle, not like the case of localized strings in the project or the main bundle path. Here is a case of getting the localized user default setting name: "Allow bulk delete".
let settingsBundle = Bundle.main.path(
forResource: "Settings",
ofType: "bundle")
let bdl = Bundle(path: settingsBundle!)
let s = NSLocalizedString(
"rkAllowBulkDelete",
tableName: "Root",
bundle: bdl!,
comment: "Localized name for setting \"Allow bulk delete\"")
print(s)
And this is the definition of rkAllowBulkDelete in en.lproj\Root.string file:
...
"rkAllowBulkDelete" = "Allow bulk deletion";
...
I think you are looking to access the standard user defaults, which could be done like this:
let userDefaults = NSUserDefaults.standardUserDefaults()
let example = userDefaults.boolForKey("mykey")
Check out NSUserDefaults documentation for more details.
EDIT:
You can get the keys in the standard user defaults like this:
for key in NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys {
println(key.description)
}
However this might give you more keys than what you have inside the Root.plist. Also you might want to edit your question and mention that you want to get a list of keys from the Root.plist, since nothing like this is mentioned there.

Swift Array size limit and Xcode compile limits

I have extracted OSX English language dictionary and want to use it in my Swift iPhone app. It has about 236,000 words which I have added to a swift string array.
When I try to run the build, it takes a long time to compile and then throws Segmentation Fault 11
Is this because the array is too big?
Am I going the correct path trying to add english dictionary in my project?
You should probably not store this as a single string. There are more efficient data structures that you can use, such as a trie. You should also consider not loading the entire content into memory at one point but be able to navigate it from the filesystem.
I was able to solve this problem by adding the actual dictionary text file into my xcode project. then utilize below code to fill words from the file to an array. it was pretty fast.
let path = NSBundle.mainBundle().pathForResource("dict2", ofType: "txt")
let dico = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)
let dict = dico!.componentsSeparatedByString("\n")
Hope it helps someone.

Resources