How do I programmatically find the user's logging directory? - objective-c

Given an app called ExampleApp, I want to find "~/Library/Logs/ExampleApp" basically without using hard coded paths. There exists NSSearchPathForDirectoriesInDomains, which you can use to find things like "~/Library/Application Support/ExampleApp" using the NSApplicationSupportDirectory search term, but there doesn't seem to be a search term for logging.
I don't think ~/Library/Logs is non-standard, since CrashReporter puts its logs there.

Try this :
NSString* libraryPath = [NSHomeDirectory stringByAppendingPathComponent:#"Library/Logs"];
Update (~/Library/Logs/AppName) :
NSString* bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleName"];
NSString* logsPath = [NSString stringWithFormat:#"Library/Logs/%#",bundleName];
NSString* libraryPath = [NSHomeDirectory stringByAppendingPathComponent:logsPath];

Cocoa doesn't provide a means for finding all of the standard directories. The old FSFindFolder() function can provide many more, but does involve converting from an FSRef back to a path or URL. Apple discourages its use, but it's still the only way to get certain standard directories without hard-coding. That said, it won't ever incorporate your app name. You have to append that.
Edited to add: the link to the legacy docs.

Related

Does NSSearchPathForDirectoriesInDomains (NSSearchPathDirectory directory, NSSearchPathDomainMask ); ever return multiple values on iOS

Does the following method ever return multiple values when used on iOS, and if so, do you have an example of when this happens and how to know which element is the one you asked for?
NSArray* NSSearchPathForDirectoriesInDomains (NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde );
I am wondering because I am calling it with the parameters for getting a path to the Documents directory (see below), and assuming it returns an array with only one element. It is working just fine, but it occurred to me that I might need to make sure I will never get more than one element back. And if I do get more than one, I wondered how I would know which one is the one I asked for?
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = paths[0];
It's my understanding that on iOS you'll only ever get a single element in the returned array.
I believe it returns an array rather than a single value as it's used by OS X too and tries to be as general purpose as possible. On OS X it can potentially return multiple elements, representing the user's documents directory, the computer's documents directory, and so on, according to the domain mask.
As an aside, note that Apple recommends using the NSFileManager methods URLsForDirectory:inDomains: and URLForDirectory:inDomain:appropriateForURL:create:error: instead, stating that URLs are preferred over path strings.

Performance of sorting NSURLs with localizedStandardCompare

I need to sort a NSMutableArray containing NSURLs with localizedStandardCompare:
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSString *f1 = [(NSURL *)obj1 absoluteString];
NSString *f2 = [(NSURL *)obj2 absoluteString];
return [f1 localizedStandardCompare:f2];
}];
This works fine, but I worry a bit about the performance: the block will be evaluated n log n times during the sort, so I'd like it to be fast (the array might have up to 100,000 elements). Since localizedStandardCompare is only available on NSString, I need to convert the URLs to strings. Above, I use absoluteString, but there are other methods that return a NSString, for example relativeString. Reading the NSURL class reference, I get the impression that relativeString might be faster, since the URL does not need to be resolved, but this is my first time with Cocoa and OS-X, and thus just a wild guess.
Additional constraint: in this case, all URLs come from a NSDirectoryEnumerator on local storage, so all are file URLs. It would be a bonus if the method would work for all kinds of URL, though.
My question: which method should I use to convert NSURL to NSString for best performance?
Profiling all possible methods might be possible, but I have only one (rather fast) OS-X machine, and who knows - one day the code might end up on iOS.
I'm using Xcode 4.5.2 on OS-X 10.8.2, but the program should work on older version, too (within reasonable bounds).
You may need to use Carbon's FSCatalogSearch, which is faster than NSDirectoryEnumerator. As for getting the path, I see no choice.
The only thing you may consider for speeding up the sorting is that the paths are partially sorted, because the file system will return all the files of the same folder in alphabetical order.
So you may want to take all the path of the same directory and merge them with the other results.
For example the home contents may be:
ab1.txt
bb.txt
c.txt
The documents directory may contain:
adf.txt
fgh.txt
So you just merge them with a customized algorithm, which just applies the merge part of a mergesort.
I benchmarked the sort. It turned out that absoluteString and relativeString are much faster that path or relativePath.
Sorting about 26000 entries:
relativeString 550ms
absoluteString 580ms
path 920ms
relativePath 960ms
field access 480ms
For field access, I put the value of absoluteString into a field prior to the sort and access that. So, the ...String accessors are almost as fast as field access, and thus a good choice for my use case.

NSBundle returning NULL

I have been using pathForResource for a while but suddenly its giving up on me.
I have added an additional file to my resources called untitled.obj and untitled.mtl.
And following two lines of code:
NSString *path = [[NSBundle mainBundle] pathForResource:#"untitled" ofType:#"obj"];
NSLog(#"thePath = %#", path);
All other *.obj files work fine, except untitled.obj.
The output from NSLog is nothing when i use that file, so i assume its unable to find it for some reason.
The resource is also located in the temp. simulation library:
Delete the app from your device and reset contents and settings in the simulator. Also delete Derived Data of the project. After you do that, test again and it should work.
Everything looks correct to me. Have you checked that you haven't accidentally named the file with a trailing space or other invisible character? Try naming it something entirely different (including changing the extension) and then renaming it back.
I think you need the .plist file. There you have the Bundle name and identifier.

Listing localized files

Konichiwa folks,
I'm banging my head over a non-standard procedure to read a bunch of localized xml located in my project.
My purpose is to read recursively all these files in order to feed a coredata sqlite db to create various lang-based versions of the same DB.
In the first place, I've tried an old school technique, like:
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bundleRoot error:nil];
NSArray *onlyXMLs = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self ENDSWITH '.xml'"]];
for (NSString *tString in onlyXMLs) {
/* stuff */
}
with no luck at all, because it pops out all the non-localized xmls in my project and nothing more.
so I was wondering if there would be a way to get those damn't localized xmls out there.
thanks in advance.
If u got doubts or questions don't be a stranger, drop me a line.
-k-
ok, solved it!
for the ones who are seeking for an answer to the problem, here's the solution:
NSArray *onlyXMLs = [[NSBundle mainBundle] pathsForResourcesOfType:#"xml" inDirectory:nil forLocalization:#"English"];
remember that the parameter that carries the desired language
must always be the same of the .plist directory containing the desired files in your project.
so if you've got a English.plist with the stuff you need in it, that must also be the name string to pass (like shown in the above example), otherwise if you're dealing with a en.plist, #"en" shall be the string.
that's it, that's all.

Get text after certain point using NSString

I am getting a url of a file when a user opens one from an NSOpenPanel for example like so:
/Users/Name/Documents/MyFile.png
So I just want this bit:
MyFile.png
However the user could have a file name of any length so how can I say, only get the string after the last forward slash (/)? I just want to get the file name.
NSString *fileName = [someStringContainingAPath lastPathComponent];
More general advice: spend a little time reading through the reference pages for NSString and NSString(UIStringDrawing). There are a lot of useful methods in there that you might not otherwise know to look for. In addition to -lastPathComponent demonstrated above, there's -pathComponents, -componentsSeparatedByString:, and many other handy tools.