Does using a path from system, while calling a file, cause crashes? - ios

I've a text file that stores my app's data for me.
If I use system path (/Users/username/Desktop/ProjectFile/data.txt), can it cause errors when application compiled into .ipa file?

open the file in your project, and check the target membership, as shown in following image. If target membership icon is checked for your corresponding target, then it will not make any problem during compilation(creating ipa). But if target membership is unchecked for your target build, then it will make the problem.

Using path form system like in the question causes crash when tested on a real iOS device.
Instead of using system path, using the code below will be more advantageous. It prevents crashes on real device.
let path = NSBundle.mainBundle().pathForResource("file", ofType: "txt")
let fileMgr = NSFileManager.defaultManager()
var array: [String] = []
if fileMgr.fileExistsAtPath(path!) {
do {
let text = try! String(contentsOfFile: path!, encoding: NSASCIIStringEncoding)
array = text.componentsSeparatedByString("|#|")
}
}

Related

is the temporaryDirectory of FileManager automatically removed by iOS? if so when?

I am adding an option in my App to backup everything to a file.
For that, I am serializing all my objects to a dictionary that I save in a single file in the path provided by FileManager.default.temporaryDirectory. Then I ask the user for a path to save this file using a UIDocumentPickerViewController.
Everything works fine, but I wonder what happens with the temporal file that I created in the temporaryDirectory. Is this automatically removed by the operating system? should I take care of removing it by myself?
This is how I get the path of the temporary directory for my file:
private var exportURL: URL {
let documentURL = FileManager.default.temporaryDirectory
let fileName = "archive"
let filePath = "\(fileName).backup"
return documentURL.appendingPathComponent(filePath)
}

File Not Created in iPhone Documents

I'm trying to save a bunch of GPS locations in a text file on an iPhone. I've been following suggestions that I've gleaned from the web, but, while the app runs fine, no file is being created. At least, nothing is visible under XCode Window -> Devices and Simulators -> (app name).
The goal is to create a file named "1" in a folder called "position" under a folder named after the date/time the app is launched, which is in turn under the Document folder. Example: 2018-07-21-16-35-43/position/1
I'm writing this in Swift 4.2 in XCode 9.(latest)
I get the Document folder as follows (rideStart = Date()):
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let docUrl = urls.first {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd-HH-mm-ss"
let dateText = dateFormatter.string(from: rideStart)
positionUrl = docUrl.appendingPathComponent(dateText)
}
When I'm ready to write out some lines of text I do the following (locationCache is an array of CLLocation objects, and textForFile is an extension property that formats the information I want as a comma-separated set of values, terminated with \r\n):
try? FileManager.default.createDirectory(at: positionUrl, withIntermediateDirectories: true)
let curUrl = positionUrl.appendingPathComponent("\(fileNumber)")
for loc in locationCache {
do {
let line = loc.textForFile
print(line)
try line.write(to: curUrl, atomically: true, encoding: .utf8)
}
catch {
print(error)
}
}
No errors are thrown when the code runs, and the text lines print to the console in the expected format.
I'm new to iOS and to Swift, the vast majority of my experience being in C# under Windows, along with javascript. I'm obviously missing something simple and/or basic. What am I doing wrong?
Additional Info
Based on feedback, I ran the app in a simulator. After figuring out where the iPhone 6 simulator was located in my Library folder, I determined that the file I was trying to create was, in fact, created (note: I'm currently using a FileHandle based approach to writing the file, as opposed to what's in the code shown in this posting -- but I've tested that FileHandle approach against the physical iPhone hardware, and it still doesn't create any file visible from within XCode's Devices and Simulators window.
Which brings up a point raised in the comments: is it even possible to examine the files on a connected/paired iPhone from within XCode? I thought from what I've read in various places that it should be possible...but that may not be the case.

Using an existing database in an iMessage app (Swift)

Currently building an iMessage app, and would like to experiment with using a database. I have a database that I would like to use in the app, and have included it in my project, and verified the target membership is correct. Using SQLite.Swift.
Whenever I try opening the connection to the database in simulator, I always get an error (unexpected nil) for the path of the database.
I've tried an image file the same way with no avail.
let imagePath = Bundle.main.path(forResource: "db", ofType: ".sqlite")
do {
let db = try Connection(imagePath!, readonly: true)
} catch {
}
I believe the issue is more related to what an iMessage "app" is - which is actually an extension, not a true app. There's no initial VC, thus no real Bundle.main to get to.
One (maybe soon a second) app of mine has a Photo Editing Extension - basically what I always have called a "shell connection" to an Apple app. You really have either a "do nothing" app with a connection to one of their apps, or you have a stand-alone app an share the code with the extension.
My solution for sharing code is to use a Framework target. Yes, a third project. (App, extension, shared code.) I found a technique that I think should work for you - basically, for images, scripts (my apps use .cikernel files) you add them into the framework project and return what you need in a function call.
You may be able to streamline this with a need for a Framework target. YMMV. The basics are this:
Someplace in Xcode you have a "Bundle Identifier". Something like *"com.company.projectname".
Put your files into a folder, maybe on your desktop. Add an extension to this folder called ".bundle". macOS will give you a warning, accept it. All you are really doing is creating your bundle.
Drag this into your Xcode project.
Code to get to this bundle, and the files inside it. (I'm not sure if need a framework here - try to drag this into your "MessagesExtension" target first.
So lets say you have images you wish to share between projects, extensions, whatever. After moving them into a folder called "images", andrenaming the folder with a ".bundle" at the end, and finally dragging it into your Xcode project, you pretty much need to add this function:
public func returnImage(_ named:String) -> UIImage {
let myBundle = Bundle.init(identifier: "com.company.project")
let imagePath = (myBundle?.path(forResource: "images", ofType: "bundle"))! + "/" + named
let theImage = UIImage(contentsOfFile: imagePath)
return theImage!
}
For a text file you want:
public func returnKernel(_ named:String) -> String {
let myBundle = Bundle.init(identifier: "com.company.project")
let kernelPath = (myBundle?.path(forResource: "cikernels", ofType: "bundle"))! + "/" + named + ".cikernel"
do {
return try String(contentsOfFile: kernelPath)
}
catch let error as NSError {
return error.description
}
}
Usage, for an image called "Camera.png" which is part of a bundle called "images.bundle":
let cameraImage = returnImage("Camera")
Since I don't work with SQLite files I don't have the exact code, but I think this should work. Remember to change "com.company.project" to what you have for the bundle identifier.

How to access a computer file on a phone

I am using
let data = try?
NSString(contentsOfFile: "/Users/BenA**** 1/Desktop/textFile.txt",
encoding: String.Encoding.utf8.rawValue)
to access a file on my computer. When I test put the app on my phone, it obviously didn't work because it didn't have access to the file. How could I put this file on my phone and be able to access it from there? Thanks.
Include your "textFile.txt" in main bundle by drag and drop file in to xcode project, then access it by
class testViewController: UIViewController{
var data:String = ""
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("textFile", ofType: "txt")
data = try? NSString(contentsOfFile: path!, encoding: ENCODING)
}}
Try this way to access 'data' in rest of code.
Hope this help.
To simulate the behavior of iOS enable the sandbox on macOS.
Now you can access files only in the container of the app.
Nevertheless the predefined folders like Documents, Library etc. still exist.
To have access to that directories there a method of NSFileManager. For example one of the most important directories in iOS is the Documents directory.
let documentsFolderURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomain: .UserDomainMask).first!
You have to use that method each time you need to get the URL of that particular directory because for security reasons the absolute path will change.

Application ID of NSSearchPathForDirectoriesInDomains Changes per Simulator Run & Update App on Real Device

I'd like to persist images to user domain of iPhone so I write the following code.
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
print(path)
It shows like: /Users/xxx/Library/Developer/CoreSimulator/Devices/1312F880-6BDC-45D2-B3B3-4D2374313C67/data/Containers/Data/Application/A2850237-5E71-4373-81A6-B443032E1951/Documents/
In this case, Application ID is A2850237-5E71-4373-81A6-B443032E1951
And the problem is when I run on simulator again WITHOUT REMOVING THE APP, it shows like: /Users/xxx/Library/Developer/CoreSimulator/Devices/1312F880-6BDC-45D2-B3B3-4D2374313C67/data/Containers/Data/Application/1F9B5B0A-5A6C-4098-BF40-C978C60C93AF/Documents/
In this case, Application ID is 1F9B5B0A-5A6C-4098-BF40-C978C60C93AF
So there are Application ID difference between previous and current install although I just did update the app and didn't remove the app. Why it is caused and how to fix it?
It causes Xcode 7.2, 7.1, 7.0. And it causes with not only simulator install but also actual device install. So if iOS users update the app from app store, the Application ID will be changed and app sandbox will also be changed and finally users cannot refer their images.
Similar Situations:
Xcode 6.3 seems to change the path to the Documents directory per app run
xcode 6.2 create a new simulator path every time when run the app
Related Guidelines:
File System Basics
Thanks in advance.
EDIT
It seems I have to persist path as relative not absolute.
Application folder name changes every time i run in simulator [duplicate]
Xcode 6 keeps renaming my app's directory in iOS8 simulator after each run.
I'll try the approach and if I solved my problem, I'll update the question.
I have to persist path relative not absolute. And I also can salvage old run images by fetching with NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] + "persisted relative path".
A better solution is to save a bookmark data
https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html
A bookmark is an opaque data structure, enclosed in an NSData object,
that describes the location of a file. Whereas path- and file
reference URLs are potentially fragile between launches of your app, a
bookmark can usually be used to re-create a URL to a file even in
cases where the file was moved or renamed
First you must use NSURL instead of String
Convert an NSURL to NSData
let data: NSData? = try? url.bookmarkDataWithOptions(.SuitableForBookmarkFile, includingResourceValuesForKeys: nil, relativeToURL: nil)
Read an NSURL from bookmark NSData
var isStale: ObjCBool = false
let url = try? NSURL(
byResolvingBookmarkData: bookData,
options: [],
relativeToURL: nil,
bookmarkDataIsStale: &isStale)
guard let fullURL = url else {
return nil
}
You can fill relativeToURL to your document directory url
Alternatively you can use FileKit : path.bookmarkData and Path(bookmarkData: ..)
try to persist your file just with the name.extension
to save document
let pathDocument = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let fullPath = let fullPath = pathDocument+"/"+"fileName.ext"
//...add some code to save document at `fullPath`...
to get document
let pathDocument = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let fullPath = let fullPath = pathDocument+"/"+"fileName.ext"
//... add code to get data at path : `fullPath`....

Resources