NSBundle pathForResource error in shell tool

I noticed some strange behavior with NSBundle when using it on the command line. If in my program I take an existing package and make a copy of it, and then try to use pathForResource to search for something in the Resources folder, nil always returns, if only I found that it existed before the start of my program. I created an example application that replicates the problem, and the corresponding code:

int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSString *exePath = [NSString stringWithCString:argv[0]
                                           encoding:NSASCIIStringEncoding]; 
    NSString *path = [exePath stringByDeletingLastPathComponent]; 
    NSString *templatePath = [path stringByAppendingPathComponent:@"TestApp.app"];

    // This call works because TestApp.app exists before this program is run 
    NSString *resourcePath = [NSBundle pathForResource:@"InfoPlist" 
                                                ofType:@"strings"
                                           inDirectory:templatePath]; 
    NSLog(@"NOCOPY: %@", resourcePath); 

    NSString *copyPath = [path stringByAppendingPathComponent:@"TestAppCopy.app"]; 
    [[NSFileManager defaultManager] removeItemAtPath:copyPath 
                                               error:nil]; 
    if ([[NSFileManager defaultManager] copyItemAtPath:templatePath 
                                                toPath:copyPath 
                                                 error:nil]) 
    { 
        // This call will fail if TestAppCopy.app does not exist before 
        // this program is run
        NSString *resourcePath2 = [NSBundle pathForResource:@"InfoPlist"
                                                     ofType:@"strings"
                                                inDirectory:copyPath]; 
        NSLog(@"COPY: %@", resourcePath2); 
        [[NSFileManager defaultManager] removeItemAtPath:copyPath 
                                                   error:nil]; 
    } 
    [pool release]; 
} 

For this test application, let's say TestApp.app already exists in the same directory as my test application. If I run this, a second NSLog call is issued: COPY: (null)

, removeItemAtPath if , TestAppCopy.app, , , .

Cocoa, . . - , ?

: 10.6.4, Mac OS X.

+5
2

, CoreFoundation, Foundation. CFBundle, , . , -, , , .

CoreFoundation, +[NSBundle pathForResource:ofType:inDirectory:], CFBundleCopyResourceURLInDirectory(), . ( , -pathForResource:ofType:inDirectory: .)

_ CFBundleCopyDirectoryContentsAtPath(). . , contentsCache.

: TestAppCopy.app, , TestApp.app, TestAppCopy.app. , TestAppCopy.app. TestAppCopy.app , " " :

__CFSpinLock(&CFBundleResourceGlobalDataLock);
if (contentsCache) dirDirContents = (CFArrayRef)CFDictionaryGetValue(contentsCache, dirName);
if (dirDirContents) {
    Boolean foundIt = false;
    CFIndex dirDirIdx, dirDirLength = CFArrayGetCount(dirDirContents);
    for (dirDirIdx = 0; !foundIt && dirDirIdx < dirDirLength; dirDirIdx++) if (kCFCompareEqualTo == CFStringCompare(name, CFArrayGetValueAtIndex(dirDirContents, dirDirIdx), kCFCompareCaseInsensitive)) foundIt = true;
    if (!foundIt) tryToOpen = false;
}
__CFSpinUnlock(&CFBundleResourceGlobalDataLock);

, , , . ( ) TestAppCopy.app, , . , , , en.lproj, , .

CoreFoundation SPI CFBundle. , API CoreFoundation, __CFBundleDeallocate(). , : _CFBundleFlushContentsCacheForPath(), , , , .

, , CoreFoundation TestApp.app, ( TestApp.app Contents), CFBundle , CFBundle. , , , TestAppCopy.app , TestAppCopy.app .

+3

. , , Cocoa - . :

@interface Foo:NSObject
@end
@implementation Foo
- (void) doIt { .... your code from main() here .... }
@end

... main(...) {
    Foo *f = [Foo new];
    [f performSelector: @selector(doIt) withObject: nil afterDelay: 0.1 ...];
    [[NSRunLoop currentRunLoop] run];
    return 0; // not reached, I'd bet.
}

, . . ( , ). , , http://bugreport.apple.com/ # .

+1

All Articles