67

I'm trying to get an NSString for the user's Application Support folder.

I know I can do NSString *path = @"~/Library/Application Support"; but this doesn't seem very elegant. I've played around with using NSSearchPathForDirectoriesInDomains but it seems to be quite long-winded and creates several unnecessary objects (at least, my implementation of it does).

Is there a simple way to do this?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Jack James
  • 5,252
  • 6
  • 36
  • 38

8 Answers8

78

This is outdated, for current best practice use FileManager.default.urls(for:in:) as in the comment by @andyvn22 below.

the Best practice is to use NSSearchPathForDirectoriesInDomains with NSApplicationSupportDirectory as "long winded" as it may be.

Example:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *applicationSupportDirectory = [paths firstObject];
NSLog(@"applicationSupportDirectory: '%@'", applicationSupportDirectory);

NSLog output:

applicationSupportDirectory: '/Volumes/User/me/Library/Application Support'
zaph
  • 111,848
  • 21
  • 189
  • 228
  • That looks a LOT cleaner than what I had. Thank you. – Jack James Dec 08 '11 at 12:36
  • 4
    For swift it's not preferred method. From docs: `You should consider using the FileManager methods urls(for:in:) and url(for:in:appropriateFor:create:). which return URLs, which are the preferred format.` – surfrider Nov 02 '17 at 11:43
  • how to create folder in /Library/Application Support of system instead of users /Library/Application Support – Sangram Shivankar May 21 '18 at 09:01
  • No because that would be horribly insecure. – zaph May 21 '18 at 17:16
  • 2
    This is outdated--the preferred method now is to use `FileManager.default.urls(for:in:)`. In general, Apple is moving towards replacing all string paths with URLs. – andyvn22 Aug 16 '18 at 01:18
  • but every time I use fileManager with "applicationSupportDirectory" and "userDomainMask" I get no results, but I do get results with this "outdated" method – noone392 Nov 05 '20 at 20:29
  • Still the best available method for getting the path in C and C++ projects. – Alexander Revo May 08 '21 at 10:48
42

Swift:

print(NSHomeDirectory())

or

print(FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first)

and

let yourString = String(FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first)
Juan Boero
  • 6,281
  • 1
  • 44
  • 62
  • 3
    `NSHomeDirectory()` doesn't seem to point to the Application Support directory, but rather the outer application sandbox directory. https://developer.apple.com/documentation/foundation/1413045-nshomedirectory – Jeremy Wiebe May 31 '18 at 17:19
  • 1
    thanks a bunch. the answer worked, mostly - just wanted to say the URL needs .absoluteString - otherwise you get the error : "Cannot invoke initializer for type 'String' with an argument list of type '(URL?)'" – sdailey Jun 29 '18 at 20:26
  • Note that I used the .url (singular) form, and found the 'Application Support' folder did not exist, at least not in the Xcode simulator. So I set the create: true, and it worked fine. – Dave Hubbard Nov 01 '18 at 02:25
  • @MaksimKniazev yes, that was the question asked. – Juan Boero Apr 22 '19 at 14:55
28

Swift 3:

FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
Andreas Ley
  • 9,109
  • 1
  • 47
  • 57
  • This is the answer - simple. – hmedia1 Feb 13 '19 at 11:55
  • How to force it to create App folder inside /Application Support ? Using your command it creates /Users//Library/Application Support/config.json But I need /Users//Library/Application Support/AppName/config.json – StNickolay Dec 29 '20 at 09:04
7

Just to be sure people will start using the recommended way of doing this:

- (NSArray<NSURL *> * _Nonnull)URLsForDirectory:(NSSearchPathDirectory)directory
                                      inDomains:(NSSearchPathDomainMask)domainMask

Expanded example from documentation:

- (NSURL*)applicationDataDirectory {
    NSFileManager* sharedFM = [NSFileManager defaultManager];
    NSArray* possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory
                                 inDomains:NSUserDomainMask];
    NSURL* appSupportDir = nil;
    NSURL* appDirectory = nil;

    if ([possibleURLs count] >= 1) {
        // Use the first directory (if multiple are returned)
        appSupportDir = [possibleURLs objectAtIndex:0];
    }

    // If a valid app support directory exists, add the
    // app's bundle ID to it to specify the final directory.
    if (appSupportDir) {
        NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
        appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID];
    }

    return appDirectory;
}

Proof link: https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html#//apple_ref/doc/uid/TP40010672-CH3-SW3

Ivan Karpan
  • 1,554
  • 15
  • 20
  • Most use the CFBundleExecutable name for the final directory, but you are probably right to advise the use of the bundle ID since it's more unique. However you have to weigh up wether you might change either the executable or the bundle ID in the future so you can maintain access to the data. – malhal Feb 04 '16 at 18:24
3

This works for me:

NSError *error;
NSURL* appSupportDir = [[NSFileManager defaultManager]     
         URLForDirectory:NSApplicationSupportDirectory
                inDomain:NSUserDomainMask
       appropriateForURL:nil
                  create:YES
                   error:&error];
Jeff Pearce
  • 343
  • 2
  • 7
  • I tried above all of the methods people talked, I always get "/var/root/Application Support" instead of current user, my system is 10.15.7, anyone has the same issue? – Steven Oct 06 '20 at 19:05
1

iOS 16 update: URL.applicationSupportDirectory, they've also added a static property for documentsDirectory

James Wolfe
  • 340
  • 5
  • 18
  • also in macOS 13, tvOS 16 and watchOS 9. additionally, check out https://github.com/MarcoEidinger/URLCompatibilityKit for backport! – freya Mar 19 '23 at 16:50
0

Create separate objective C class for reading and writing into documents directory. I will avoid code re-writing. Below is my version of it.

//Directory.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#define PATH (NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES))
#define BASEPATH (([PATH count] > 0)? [PATH objectAtIndex:0] : nil)

@interface DocumentsDirectory : NSObject

//Here you can also use URL path as return type and file path.
+(void)removeFilesfromDocumentsDirectory:(NSString*)filename;
+(NSString*)writeFiletoDocumentsDirectory:(NSString*)filename;
@end


#import "Directory.h"

@implementation DocumentsDirectory

UIAlertView *updateAlert;

+(void)removeFilesfromDocumentsDirectory:(NSString*)filename
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *filePath = [BASEPATH stringByAppendingPathComponent:filename];

    NSError *error;
    BOOL success = [fileManager removeItemAtPath:filePath error:&error]; //Remove or delete file from documents directory.

    if (success)
    {
        updateAlert= [[UIAlertView alloc] initWithTitle:@"Congratulations:" message:@"File is updated successfully" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [updateAlert show];
    }
    else
    {
        NSLog(@"Could not delete file -:%@ ",[error localizedDescription]);
        updateAlert= [[UIAlertView alloc] initWithTitle:@"Try again:" message:[error localizedDescription] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [updateAlert show];
    }
}

+(NSString*)writeFiletoDocumentsDirectory:(NSString*)filename
{
    NSString *foldDestination = BASEPATH;
    NSString *filePath = [foldDestination stringByAppendingPathComponent:filename];

    return filePath;
}

@end
WasimSafdar
  • 1,044
  • 3
  • 16
  • 39
0

This is what I use to get the database. Got it from the Stanford class. It might help somebody.

NSURL *url = [[[NSFileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:@"database_name"];
NSLog(@"Database URL: %@",url);
Flaviu
  • 6,240
  • 4
  • 35
  • 33