Xcode and iOS app data file placements defaults - ios

Is my understanding correct for iOS7-iOS9:
1)
"built-in" app cache path is NSHomeDirectory() + "/Library/Caches/"
2)
app launch images and icons are placed NSBundle.mainBundle().resourcePath! (where does this map down to?)
3) a "blue" folder I have added in "xcode - build phases - copy bundle resources called "ownassets"" is placed in...? NSHomeDirectory() + "/Library/"
I am just tying to make 100% sure if I understood correctly where files are placed, so I can read and load them during app execution (and write in my cache)
Note: I realize that release code should use system calls to get paths since Apple may changes paths in future iOS versions.
Note For hose looking on how to get normal IO file read access to folders and content you added in "Build phases > Copy Bundle Resources" this is how: NSBundle.mainBundle().resourcePath! + "/" + nameoffolder

You should not think much about the actual locations on disk, but use the higher-level system APIs to find files/paths:
Caches directory:
let cacheURL = try NSFileManager.defaultManager().URLForDirectory(.CachesDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
App resources in the bundle:
let image = UIImage(named: "imageName")
let path = NSBundle.mainBundle().pathForResource("image", ofType: "png")
App resources in subdirectories:
let path = NSBundle.mainBundle().pathForResource("info", ofType: "dat", inDirectory: "AdditionalResources")
For more info, see the File System Programming Guide.

Related

Referencing the bundle inside CocoaPod framework fails

I have created a Swift framework and I'm trying to make it into a CocoaPod.
These are all the files in the framework.
I add all the source files plus the .json file in the podspec like so.
spec.source_files = "CountryPicker"
spec.resource = "CountryPicker/countries.json"
The files do get added.
Or so it seems. Because when I try to load the json file within the framework code like this
let path = Bundle(for: Self.self).path(forResource: "countries", ofType: "json")!
it keeps failing because it's returning nil every time.
I tried all the methods described here but it's not having any effect. Any idea what I'm doing wrong here?
I am able to do this for other assets, assume it will be the same for you.
First, find the name of your Pod's bundle. I have redacted a lot of this, but if you follow the arrows, you can see how to get it via Xcode.
The order would be:
Select the Pods project
Select the target associated with your pod
With General selected, locate the Bundle Identifier
Once you have that, you can then instantiate the Bundle:
let yourPodBundle = Bundle(identifier: "org.cocoapods.your_pod_sname_here")
Now, pull it all together
let path = yourPodBundle?.path(forResource: "countries", ofType: "json")!

can't access ios bundle resource

I am adding my first .wav file to my iOS project using XCode 11.3.1. I have tried various ways to access this resource:
let fileURL = Bundle.main.url(forResource: "greetings.wav", withExtension: nil)
let fileURL = Bundle.main.url(forResource: "greetings", withExtension: "wav")
let fileURL = Bundle.main.path(forResource: "greetings", ofType: "wav")
In all of these cases, fileURL is nil. Other things I have tried:
When I click on the .wav in Project Navigator, I see that Target Membership is checked for my target.
I have ensured greetings.wav is in the same folder as my ViewController which is executing the above statement.
I have also tried both the "Copy to Group" and "Copy to Folder Reference" when adding this resource
Nothing as of yet has produced a non-nil fileURL. Any help/additional troubleshooting so that I can get a valid URL for my .wav file would be greatly appreciated! Thanks.
Check whether your file is available in Copy Bundle Resources under build settings
Just offering possible suggestions here:
Check if you have imported the AVFoundation Module
Check if your resource is called "greetings.wav"

How to find Apple App Group shared directory

We are currently developing an iOS10 app, including "Messages Extension".
To share CoreDatas persistant store.sqlite inbetween App and Extension, we are using a shared "Apple App Group" directory, which is working fine.
Now we have to get our hands on the store for debug reasons and are unable to find the directory. The Apps container directories are completely empty, which makes sense. But how to download our database? Do we have to somehow copy it programmatically to a reachable place?
To sum it up:
We already use CoreData which stores model.sqlite in our shared directory.
Everything is up and running.
What we want to archive is to download the database to our computer.
Without a shared directory we can simply download the App container from the device, using Xcode->Devices. But as we do use a shared directory, the .sqlite database is not within the container.
Question:
How can we download the .sqlite database from the device to our computer?
EDIT on 2018-10-12: Updated code for Swift 4.x (Xcode 10). (Older version retained for reference.)
In Swift 4.x:
let sharedContainerURL :URL? = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.etc.etc")
// replace "group.etc.etc" above with your App Group's identifier
NSLog("sharedContainerURL = \(String(describing: sharedContainerURL))")
if let sourceURL :URL = sharedContainerURL?.appendingPathComponent("store.sqlite") {
if let destinationURL :URL = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("copyOfStore.sqlite") {
try! FileManager().copyItem(at: sourceURL, to: destinationURL)
}
}
In older version of Swift (probably Swift 2.x):
let sharedContainerURL :NSURL? = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.etc.etc") // replace "group.etc.etc" with your App Group's identifier
NSLog("sharedContainerURL = \(sharedContainerURL)")
if let sourceURL :NSURL = sharedContainerURL?.URLByAppendingPathComponent("store.sqlite")
{
if let destinationURL :NSURL = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0].URLByAppendingPathComponent("copyOfStore.sqlite")
{
try! NSFileManager().copyItemAtURL(sourceURL, toURL: destinationURL)
}
}
Something like the above will get a file from the app group's shared container to the app's Documents directory. From there, you could use Xcode > Window > Devices to get it to your computer.
You could also use iTunes file sharing to retrieve the file from the app's Documents directory after setting UIFileSharingEnabled to YES in the Info.plist file, but bear in mind that this will expose the directory's contents to the user as well. Should be okay for development/debugging purposes, though.

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`....

Valid file path for archiverootobject and unarchiverootobject

I am making an iPhone app and in a previous question I was told that I needed a valid file path for archiverootobject and unarchiverootobject but I don't know how to make one. So what is a valid file path to save arrays of custom classes?
Follow up question: On the linked question I have set up my methods to use invalid saves but it still works would anyone know why?
You can save it to a subdirectory folder named with your bundleID inside the application support folder or you can also save it to the preferences folder located inside the library directory:
let preferencesDirectoryURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.appendingPathComponent("Preferences", isDirectory: true)
let fileURL = preferencesDirectoryURL.appendingPathComponent("fileName.plist")
print(fileURL.path) // "/var/folders/.../Library/Preferences/fileName.plist

Resources