NSHomeDirectory in iPhone unit test - iphone

When using NSHomeDirectory() inside a unit test I get:
/Users/hgpc/Library/Application Support/iPhone Simulator/5.0
I expected the actual home directory of the current application. Something like:
/Users/hgpc/Library/Application Support/iPhone Simulator/5.0/Applications/6D1091C6-02AE-4803-A7DF-D623D0F89579
What am I doing wrong?

To solve this, set the value of Bundle Loader within your Unit Test target build settings to:
$(BUILT_PRODUCTS_DIR)/MyAppName.app/MyAppName
and also your Test Host to:
$(BUNDLE_LOADER)
you should then find NSHomeDirectory() returns the right value.

Unfortunately, while in a unit-test (or logic test) - you're not really "in your app" (i.e. its sandbox). That's why stuff like NSDocumentDirectory or [NSBundle mainBundle] will not work.
If it works for you, I'd just go ahead and create a "Documents" folder in
/Users/hgpc/Library/Application Support/iPhone Simulator/5.0
You might want to do this in your test's setUp, that way you can delete it in tearDown.
If that doesn't work because your tests depend on stuff already being in your app's NSDocumentDirectory, you might want to re-think your test a little, as they should all be self-contained (i.e. install all resources from your bundle in setUp)
You could also use NSLibraryDirectory instead of NSDocumentDirectory, depending on what it is that you want to test.

If you'd like to customised your test target to Application test you should add params mentioned by Andrew Ebling:
$(BUILT_PRODUCTS_DIR)/MyAppName.app/MyAppName
and also your Test Host to:
$(BUNDLE_LOADER)
If you don't have this params that means your tests is logic. But if you add this params you change tests to Application tests and notice that AppDelegate will start did you run tests.
see link for more information.
So you can use NSHomeDirectory( for Application tests only.

On an iOS device you should use
NSArray *path = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirPath = [paths objectAtIndex:0];

Related

Path to mobile documents folder?

To get to my application documents folder, I use this code:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
I want to access this folder, however:
~/Library/Mobile Documents
How can i easily access this as a path value? Can I do this in a similar way?
The benefit of using the constants to access system provided directories is that if Apple decide to change the structure, your application will still work. Hardcoding in something like ~/Library/Mobile Documents is brittle.
However, you can access the Library directory with the same NSSearchPathForDirectoriesInDomain with the NSLibraryDirectory constant. Then, you should just append the Mobile Documents directory path.
// Set the NO to YES to get the full path, not the ~ version.
NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, NO) lastObject];
path = [path stringByAppendingPathComponent:#"Mobile Documents"];
Looking at the constant values in http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/Reference/reference.html#//apple_ref/doc/c_ref/NSSearchPathDirectory, it appears there is no specific constant for the Mobile Documents directory, so the hardcoding approach might be your only option.
Mobile Documents are iCloud documents. So you want to store documents in iCloud.
On OS X they are definitely in ~/Library/Mobile Documents (10.7 and 10.8), but on iOS you should not look.
"All documents of an application are stored either in the local sandbox or in an iCloud container directory."...
"A user should not be able to select individual documents for storage in iCloud. "
http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/DocumentBasedAppPGiOS/ManageDocumentLifeCycle/ManageDocumentLifeCycle.html
So if your user picks iCloud then you should use iCloud.
How long the iCloud document model will last is anyones guess, but that's the way it works today. The whole thing seems a masterpiece of poor UI design, as this direct answer to your question shows:
-(NSURL*)ubiquitousContainerURL {
return [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
}
In my recent macOS app I had the same need: how to gain access to the root folder of your iCloud directory.
IMPORTANT!
This is written for an unsandboxed version, since the app is only intended for myself. If you plan to release an app on the Mac App Store, do not turn off sandboxed version.
I turn off sandbox in the app's entitlements file.
This code will access your iCloud root folder:
let pathToiCloudFolder = NSString(string: "com~apple~CloudDocs").expandingTildeInPath
let backUpFolderUrl = FileManager.default.urls(for: .libraryDirectory, in:.userDomainMask).first!
let backupUrl = backUpFolderUrl.appendingPathComponent("Mobile Documents/" + pathToiCloudFolder)
print("Backup Folder:", backupUrl)

file path in iOS 6 gives me null

I'm using iPhone6 simulator, I'm trying to get a file (any extension pdf of html) by using any of this codes:
NSString *file = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%#.pdf", documentName] ofType:nil];
or
NSString *file2 = [[NSBundle mainBundle] pathForResource:documentName ofType:#"pdf"];
I'm sure that the file in exists in Resources folder and I'm not add the file, I download it from web programmatically and see it in this path
( /Users/myMac/Library/Application Support/iPhone Simulator/6.9/Applications/E60F22DD-7301-48EF-AB25-B9D42FA6AD49/myApp.app) I see the file, but the code does not see it
but this codes sometimes gives me null and some other times gives me the file.
Why is this happen and how to prevent this and make it always gives me the file.
consider that I uses
if(file != nil)
and want to make if file == nil try to open it by using any way.
Thanks in Advance.
Make sure your file is added to project's target. Choose your target then Build Phases->Copy Bundle Resources. The file should be there.
Sometimes it's worth cleaning your project and building from scratch. I have seen cases when file added wasn't copied to simulator/device until clean was performed.
a) If you download anything from the web then the content goes to the document directory of your application.
b) No other application can interact with the your application doc directory.
c) The Bundle path i.e. the groups and files section of your application is read only.
d) No one can sneak your applications PDF unless and until you have allowed access to the document directory of your application.
Hope this helps

Unit testing of static library that involves NSDocumentDirectory and other iOS App specific calls

I'm attempting to run unit tests for a static library that attempts to create/write/read a file in the document directory. Since this is a static library and not an application for the iOS, attempts to reference the NSDocumentDirectory is returning me directory for the form
"/Users//Library/Application Support/iPhone Simulator/Documents"
This directory does not exist. When attempting to access a directory from an actual application, the NSDocumentDirectory returns something of the form:
"/Users//Library/Application Support/iPhone Simulator/4.2/FEDBEF5F-1326-4383-A087-CDA1B865E61A/Documents"
(Please note the simulator version as well as application ID as part of the path)
How can I overcome this shortcoming in the unit test framework for static libraries that implement tests that require iOS app specific calls?
Thanks in advance.
You could also solve this by mocking your file access so that the test verifies that your code attempted to write the expected data to the path given by NSDocumentsDirectory without ever actually hitting the file system.
I solve this for myself. In my unit test setup phase, I am creating the Document directory if it does not exist and removing it after the test finishes. This effectively gets me past the blockage and continues my logic tests without having to worry about iOS app specificity.
Use NSLibraryDirectory instead of NSDocumentDirectory for tests only by defining a TEST preprocessor macro.
Then, remove the file in tearDown with:
[[[NSFileManager alloc] init] removeItemAtURL:fileURL error:NULL]
The gh-unit framework can run unit tests in the simulator or on your device. This will not only solve your problem, but let you debug your application (something I've been missing from other unit testing frameworks).
Download gh-unit
How to install gh-unit

Downloading image into bundle?

I display text and images in a UIWebView. Content isn't always the same. I access images within the content using the bundle path. For an inbetween versions update of content, I'd like to allows users the ability to download new content (text & images). This new content will also display in a UIWebView. The problem is I will have to use a disk path rather than my common pattern of using the bundle path. Unless there is a way to repackage the image at runtime into the bundle.
Once the next app store update for the app is availble, all of the previously downloaded images will be in the app bundle. On this update, I'll write overwrite the previous content and use the bundle path for images. Content will be exactly the same minus the image path.
Can anyone give some insight into how this might work or a better approach?
So far as I know you cannot repackage the bundles on the iPhone once your app has been released to the App Store. So go the other way, and put the data from the bundle on the filesystem so you can change it at runtime.
My usual technique for this stuff is:
bundle up the initial data
have a routine that checks for the presence of a versioned file on the iPhone's filesystem at startup
if that routine doesn't find the current version of the file, copy all the data into the iPhone's filesystem
reference the data from the filesystem in my app, rather than using the bundle path
So, essentially your bundle is just a delivery mechanism, a way to preload the filesystem with the stuff you are going to need. Once it's on the filesystem you can change anything you wish.
Agree with Benjamin - you cannot change your bundle contents.
Instead you can (and should) save your downloaded contents to Documents folder of your application sandbox. You can get the path to it this way:
// Look in Documents for an existing plist file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
Moreover contents of this folder persists during updates so it may be not necessary to put downloadable optional contents to the application bundle.

How do I fix Cocoa error 513?

I have an iPhone application in which a number of domain objects are populated with user-entered data. In order to restore state after being interrupted, these objects implement the NSCoding protocol and are written to disk (the Documents directory) in the applicationWillTerminate message. Then, when the application is launched again, the bytes of data are loaded up and the domain objects are repopulated. Code to get the documents directory is as follows:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
This worked great in the simulator but once I deployed the app to the iPhone it stopped working. The reason why is iPhone error code 513 - which apparently means "permission denied." There is a note in the iPhone dev docs that explain a little bit more -
On the device, the returned path
(documentsDirectory) is similar to the
following:
/var/mobile/Applications/30B51836-D2DD-43AA-BCB4-9D4DADFED6A2/Documents
However, on the Simulator, the
returned path takes the following
form:
/Volumes/Stuff/Users/johnDoe/Library/Application
Support/iPhone
Simulator/User/Applications/118086A0-FAAF-4CD4-9A0F-CD5E8D287270/Documents
This is the exact behavior that I'm seeing. I'm not really sure how this relates to getting a permission denied error and what I can do to fix it. It does say below -
To read and write user preferences,
use the NSUserDefaults class or the
CFPreferences API. These interfaces
eliminate the need for you to
construct a path to the
Library/Preferences/ directory and
read and write preference files
directly. For more information on
using these interfaces, see “Adding
the Settings Bundle.”
If your application contains sound,
image, or other resources in the
application bundle, you should use the
NSBundle class or CFBundle opaque type
to load those resources. Bundles have
an inherent knowledge of where
resources live inside the application.
In addition, bundles are aware of the
user’s language preferences and are
able to choose localized resources
over default resources automatically.
For more information on bundles, see
“The Application Bundle.”
I don't see how I can use the Application Bundle to load bytes of data though. Any help or examples?
Not sure how this works, but apparently using stringByAppendingPathComponent instead of stringByAppendingString for path creation fixed the problem.
The paragraph related to the application bundle refers to:
NSString *path = [[NSBundle mainBundle] pathForResource:#"somefile" ofType:#"png"];
This and other methods from NSBundle allow you to refer resources from inside the application bundle without actually knowing where the application bundle is located.
Disclaimer: I haven't worked with the iPhone.
With the disclaimer in mind, in plain OS X it's considered bad form to write stuff inside the application bundle. You save stuff under the user's Application Support directory -> see NSApplicationSupportDirectory.
I got this error (513) because the path was wrong. Double checking my path fixed the problem :)