Swift .writeToFile does not update JSON file in mainBundle - ios

I am trying a simple dictionary retrieve, update key value and write back to file. For some reason the writeToFile does not update the file in the main bundle.
the code reads:
let filename = "testFile"
if let path = NSBundle.mainBundle().pathForResource(filename, ofType: "json") {
var error: NSError?
let InputData: NSData? = NSData(contentsOfFile: path, options: NSDataReadingOptions(), error: &error)
var jsonDictionary: NSMutableDictionary = NSJSONSerialization.JSONObjectWithData(InputData!, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSMutableDictionary
jsonDictionary.setValue(1, forKey: "levelRow")
let options = NSJSONWritingOptions.PrettyPrinted
var outputData : NSData? = NSJSONSerialization.dataWithJSONObject(jsonDictionary, options: options, error: &error)
outputData?.writeToFile(path, atomically: true)
}
the file looks like this:
{
"levelColumn" : 0,
"levelRow" : 0,
}
the read and update work fine... but the file doe not update levelRow to 1?
thanks in advance.

You cannot write to the main bundle. All files in the bundle are read-only. Copy your file into the application documents directory before modifying it.
If you need a different file in the bundle to include in your application, you can update it in the documents directory during development and then manually copy it to the bundle before shipping your app.

Related

SWIFT 3 access JSON that is within a folder

I have a lot of JSON files that all of them are in a new folder called assets. How can I access some of the JSON files that are in a folder within the assets folder. Here is a screenshot of the file I want to work with. http://prntscr.com/eiv7p4
UPDATE:
here is the code with which I access the file "mc-summer-0.json"
if let path = Bundle.main.path(forResource: "mc-summer-0", ofType: "json") {
do {
let jsonData = try NSData(contentsOfFile: path, options: NSData.ReadingOptions.mappedIfSafe)
do {
let jsonResult: NSDictionary = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
if let times_to : [String] = jsonResult["times_to"] as? [String] {
for (value) in times_to {
print("\(value)")
}
}
} catch {}
} catch {}
}
but if I want to access a file that is in the "assets" folder I change the line into if let path = Bundle.main.path(forResource: "assets/mc-summer-1", ofType: "json") {
but unfortunately it doesnt work.
Those files are in groups in your project, not in separate folders. Very likely they will be in the root level of your app bundle, but we can't be sure based on what you've shown. I suggest building your app for the simulator and then opening the resulting bundle in the Finder and examining it.
alright, in case somebody get stuck just like me the real solution is to remove the assets "folder" and re add it and select to add them as reference instead as a group

Invalid filename/path when getting JSON

In my project Navigator I have this structure
-MyApp
--ViewController.swift
--AppDelegate.Swift
--Main.StoryBoard
--info.plist
--JSONFiles
---test.json
-MyAppUITests
As you can see, this is the very basic structure that happens when you create a new single view application.
I created a new group called JSONFiles and added in a JSON files called test.
When I try to get the file using:
if let path = Bundle.main.path(forResource: "JSONFiles/test", ofType: "json") {
do {
let data = try NSData(contentsOf: URL(fileURLWithPath: path), options: NSData.ReadingOptions.mappedIfSafe)
let jsonData : NSData = NSData(contentsOfFile: path)!
allEntries = (try! JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers)) as! NSArray
print(allEntries)
} catch let error as NSError {
print(error.localizedDescription)
}
} else {
print("Invalid filename/path.")
}
I get the error:
Invalid filename/path.
If I move the JSON file our of the group folder and change the forResource to just "test" it works fine and prints in the console.
Can anyway tell me how to make it read from the folder? I could have all my JSON files in the root but I am wanting to tidy it up slightly.
Thanks
You must include your json file into "Copy Bundle Ressources". Go to your project target -> Build phases -> Copy Bundle ressources and there, add your json file.
Then, you should be able to retrieve the path using the function: Bundle.main.path(forResource: "test", ofType: "json") .

Adding JSON as asset and reading it

I'm trying to load some JSON data from a local file.
In this Apple doc it says:
Manage the data files for your app using the asset catalog. A file can
contain any sort of data except device executable code generated by
Xcode. You can use them for JSON files, scripts, or custom data types
So I added a new data set and dropped the JSON file inside. Now I can see it under Assets.xcassets folder (Colours.dataset folder with colours.json and Contents.json inside it)
I found this SO answer that shows how to read a JSON file and I'm using this code to read the file:
if let filePath = NSBundle.mainBundle().pathForResource("Assets/Colours", ofType: "json"), data = NSData(contentsOfFile: filePath) {
print (filePath)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
print(json)
}
catch {
}
} else {
print("Invalid file path")
}
But this code is printing "Invalid file path" and not reading the file. I also tried "Colours" and "Colours.json" but to no avail.
Could anyone please tell me how to properly add a local JSON file and read it?
Thanks.
You can't access data asset files in the same way you access a random file using NSBundle.pathForResource. Since they can only be defined within Assets.xcassets, you need to initialize a NSDataAsset instance in order to access the contents of it:
let asset = NSDataAsset(name: "Colors", bundle: NSBundle.mainBundle())
let json = try? NSJSONSerialization.JSONObjectWithData(asset!.data, options: NSJSONReadingOptions.AllowFragments)
print(json)
Please note that NSDataAsset class was introduced as of iOS 9.0 & macOS 10.11.
Swift3 version:
let asset = NSDataAsset(name: "Colors", bundle: Bundle.main)
let json = try? JSONSerialization.jsonObject(with: asset!.data, options: JSONSerialization.ReadingOptions.allowFragments)
print(json)
Also, NSDataAsset is surprisingly located in UIKit/AppKit so don't forget to import the relevant framework in your code:
#if os(iOS)
import UIKit
#elseif os(OSX)
import AppKit
#endif
objC
#ifdef use_json_in_bundle
NSString * path = [mb pathForResource:json_path ofType:#"json" inDirectory:#"JSON"];
NSString * string = [NSString stringWithContentsOfUTF8File:path];
NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding];
#else
NSDataAsset * asset = [[NSDataAsset alloc] initWithName:path];
NSLog(#"asset.typeIdentifer = %#",asset.typeIdentifier);
NSData * data = [asset data];
#endif
NSError * booboo = nil;
id blob = [NSJSONSerialization JSONObjectWithData:data options:0 error:&booboo];
for either branch, 'path' is just the json file name.

Uploading a file from AVCapture using AFNetworking

I have a video that is captured with AVCapture, and I'm trying to upload with AFNetworking with Swift.
Code:
let manager = AFHTTPRequestOperationManager()
let url = "http://localhost/test/upload.php"
var fileURL = NSURL.fileURLWithPath(string: ViewControllerVideoPath)
var params = [
"familyId":locationd,
"contentBody" : "Some body content for the test application",
"name" : "the name/title",
"typeOfContent":"photo"
]
manager.POST( url, parameters: params,
constructingBodyWithBlock: { (data: AFMultipartFormData!) in
println("")
var res = data.appendPartWithFileURL(fileURL, name: "fileToUpload", error: nil)
println("was file added properly to the body? \(res)")
},
success: { (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
println("Yes thies was a success")
},
failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
println("We got an error here.. \(error.localizedDescription)")
})
The code above fails, I keep getting
was file added properly to the body? false"
note that ViewControllerVideoPath is a string containing the location of the video which is:
"/private/var/mobile/Containers/Data/Application/1110EE7A-7572-4092-8045-6EEE1B62949/tmp/movie.mov"
using println().... The code above works when I'm uploading a file included in the directory and using:
var fileURL = NSURL.fileURLWithPath(NSBundle.mainBundle().pathForResource("test_1", ofType: "mov")!)
So definitely my PHP code is fine, and the problem lies with uploading that file saved on the device, what am I doing wrong here?
Comments don't allow a full explanation so here is more info;
NSBundle.mainBundle() refers to a path in the bundle file The path in the simulator differs from that of the application ... this is not what you want. There are a number of "folders" you can access based on your needs (private or sharable/files that can get backed up to the cloud). NSPathUtils.h gives a breakdown of the paths available. In keeping with conventions used by most, you should probably create a private path under your application path by doing something like;
- (NSURL *) applicationPrivateDocumentsDirectory{
NSURL *pathURL = [[self applicationLibraryDirecory]URLByAppendingPathComponent:#"MyApplicationName"];
return pathURL;
}
- (NSURL *) applicationLibraryDirecory{
return [[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
}
You can test if it exists, if not, create it ... then store your video files in this path, and pass this to your AVCapture as the location to store the file.
Here are the code that can do following functionality in swift.
1 : Check weather directory exist or not. if not exist then create directory(Directory has given application name) in document directory folder.
2 : Now we have application directory. so all file that from application will write/read in/from this directory.
let file = "file.txt"
let directoryName = “XYZ” // Here “XYZ” is project name.
var error : NSError?
let filemgr = NSFileManager.defaultManager()
let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,
.UserDomainMask, true)
let documentsDirectory = dirPaths[0] as! String
var dataPath = documentsDirectory.stringByAppendingPathComponent(directoryName)
if !NSFileManager.defaultManager().fileExistsAtPath(dataPath) {
NSFileManager.defaultManager().createDirectoryAtPath(dataPath, withIntermediateDirectories: false, attributes: nil, error: &error)
} else {
println("not creted or exist")
}
Now we have Directory so only need to write/read data from directory.
how to write file in document directory in swift
let filePath = dataPath.stringByAppendingPathComponent(file);
let text = "some text"
//writing
text.writeToFile(filePath, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
How to read file from document directory.
let filePath = dataPath.stringByAppendingPathComponent(file);
// Read file
let text2 = String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding, error: nil)
Output :
Hope this will help you.

How to find a correct path in Swift

I got this code from the documentation, I can't find the path to my file, I need to copy the "contacts.db" file from Supporting Files Folder to the app in the device not in the simulator for offline use.
func copyItemAtPath(_ srcPath: String,
toPath dstPath: String,
error error: NSErrorPointer) -> Bool
srcPath = The path to the file or directory you want to move. This parameter must not be nil.
dstPath = The path at which to place the copy of srcPath. This path must include the name of the file or directory in its new location. This parameter must not be nil.
error = On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing the error information. You may specify nil for this parameter if you do not want the error information.
Any help is highly appreciated. :)
You can just drag and drop "contacts.db" into Project Navigator and after that you can find a path of that file this way:
let sourcePath = NSBundle.mainBundle().pathForResource("contacts", ofType: "db")
after that you can copy that file into document folder of your app and for that you need that document folder path:
let doumentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as! String
let destinationPath = doumentDirectoryPath.stringByAppendingPathComponent("contacts1.db")
now you have sourcePath and destinationPath so you can copy that file into document folder:
NSFileManager().copyItemAtPath(sourcePath!, toPath: destinationPath, error: &error)
and if you want to check for error you can do it this way:
var error : NSError?
NSFileManager().copyItemAtPath(sourcePath!, toPath: destinationPath, error: &error)
if let error = error {
println(error.description)
}
If you are getting your sourcePath nil then goto Targets->YouApp->Build Phases->copy Bundle Resources and add your file there.
Hope this will help.

Resources