
命令行程序.如果,在我的程序中,我采用现有的捆绑包
制作它的副本然后尝试使用pathForResource来查找
在Resources文件夹中的某些内容,除非是,否则始终返回nil
捆绑我在程序启动之前就已经存在了.我创造了一个
复制问题的示例应用程序和相关代码是:
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]; } 出于此测试应用程序的目的,我们假设TestApp.app
已存在于与我的测试应用程序相同的目录中.如果我运行这个,
第二个NSLog调用将输出:copY:(null)
现在,如果我在if中注释掉最后的removeItemAtPath调用
声明,以便当我的程序退出TestAppcopy.app时仍然存在
然后重新运行,程序将按预期工作.
我在普通的Cocoa应用程序中试过这个,但是我无法重现
行为.它只发生在shell工具目标中.
谁能想到这个失败的原因?
顺便说一句:我在10.6.4尝试这个,我没有尝试过其他任何一个
Mac OS X的版本.
对应于[NSBundle pathForResource:ofType:inDirectory:]的CoreFoundation调用是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包含用于刷新CFBundle缓存的SPI函数.公共API在CoreFoundation中调用它们的唯一位置是__CFBundleDeallocate().这将刷新有关bundle目录本身的所有缓存信息,但不刷新其父目录:_CFBundleFlushContentsCacheForPath(),它实际上从缓存中删除数据,仅删除与锚定匹配的键,不区分大小写的搜索包路径.
这似乎是CoreFoundation的客户端可以刷新有关TestApp.app的父目录的错误信息的唯一公共方式,即将父目录设为捆绑目录(因此TestApp.app与Contents一起存在),为父捆绑目录创建CFBundle,然后释放CFBundle.但是,似乎如果你在刷新它之前错误地尝试使用TestAppcopy.app包,那么关于TestAppcopy.app的错误数据将不会被刷新.
总结以上是内存溢出为你收集整理的objective-c – NSBundle pathForResource在shell工具中失败全部内容,希望文章能够帮你解决objective-c – NSBundle pathForResource在shell工具中失败所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)