iPhone:调用 [NSBundle mainbundle] 在设备上崩溃,但在模拟器上不会崩溃
基本上问题就是标题所说的。
我的应用程序在模拟器上运行顺利,没有任何崩溃。 事实上,以前的版本已经在应用商店里了。我到处做了一些小的改变,突然它开始在一个非常奇怪的地方崩溃。
我在代码中的各个位置使用 [NSBundle mainBundle] resourcespath]
来访问 plist 文件、图像等。对 NSBundle mainBundle]
的前几次调用完全正常,因为预期的 - 然而,在某些时候它会返回...
-[NSBundle < null selector>]: unrecognized selector sent to instance 0x10a0e0
...并在设备上崩溃。这是确切的代码片段:
-(void) setImageName:(NSString *)s
{
[imageName release];
imageName = [s copy];
NSLog(@"last line before crash");
NSString *imagePath =[[NSBundle mainBundle] resourcePath];
NSLog(@"Why would it crash before here???");
imagePath = [imagePath stringByAppendingString:imageName];
imageUI = [[UIImage alloc] initWithContentsOfFile:imagePath];
[self setNeedsDisplay];
}
为了检查该调用是否确实是问题所在,我在项目中第一次调用 [NSBundle mainbundle]
时将 resourcePath
保存到一个字符串中(正如我上面所说,前几次调用完全正常)并在我需要 [NSbundle mainbundle] 的任何地方都使用了 resourcePath
字符串,瞧!没有崩溃/泄漏,什么都没有...
我完全困惑了..为什么这个调用会使我的应用程序在设备上崩溃而不是模拟器上崩溃?
编辑:使用...
NSArray *array = [NSBundle allBundles];
NSBundle *bundle = [array objectAtIndex:0];
NSString *imagePath = [bundle bundlePath];
...而不是[[NSBundle mainBundle] resourcePath]
也可以。我想不知何故我正在做一些只影响这个特定呼叫的事情。
编辑2:这是我在 -[NSObject doesNotRecognizeSelector:] 中设置断点时的回溯:
#0 0x30e27b98 in -[NSObject doesNotRecognizeSelector:]
#1 0x30dacb18 in ___forwarding___
#2 0x30da3840 in __forwarding_prep_0___
#3 0x0000bcfe in -[CustomTableViewCell setImageName:] at CustomTableViewCell.m:93
#4 0x0000499e in -[RootTableViewController tableView:willDisplayCell:forRowAtIndexPath:] at RootTableViewController.m:469
#5 0x3364d5d0 in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:]
#6 0x3364cde0 in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:]
#7 0x335f832c in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow]
#8 0x335f6514 in -[UITableView layoutSubviews]
#9 0x335f22d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#10 0x32bac1c0 in -[CALayer layoutSublayers]
#11 0x32babedc in CALayerLayoutIfNeeded
#12 0x32bab844 in CA::Context::commit_transaction
#13 0x32bab474 in CA::Transaction::commit
#14 0x32bb35dc in CA::Transaction::observer_callback
#15 0x30da1830 in __CFRunLoopDoObservers
#16 0x30de9346 in CFRunLoopRunSpecific
#17 0x30de8c1e in CFRunLoopRunInMode
#18 0x332e7374 in GSEventRunModal
#19 0x335adc30 in -[UIApplication _run]
#20 0x335ac230 in UIApplicationMain
...其中 #3 - CustomTableViewCell.m:93 是 NSString *imagePath =[[NSBundle mainBundle] resourcePath ];在我上面发布的代码部分。
Basically the problem is exactly what the title says.
My app works smoothly on the simulator, with no crashes whatsoever.
In fact, the previous version is on the app store. I made minor changes here and there and suddenly it started to crash in a very odd place.
I use [NSBundle mainBundle] resourcepath]
in various places in the code to access plist files, images, etc. The first few calls to NSBundle mainBundle]
are totally normal-as expected-, however, at some point it returns...
-[NSBundle < null selector>]: unrecognized selector sent to instance 0x10a0e0
...and crashes on the device. Here is the exact code snippet:
-(void) setImageName:(NSString *)s
{
[imageName release];
imageName = [s copy];
NSLog(@"last line before crash");
NSString *imagePath =[[NSBundle mainBundle] resourcePath];
NSLog(@"Why would it crash before here???");
imagePath = [imagePath stringByAppendingString:imageName];
imageUI = [[UIImage alloc] initWithContentsOfFile:imagePath];
[self setNeedsDisplay];
}
To check if that call is really the problem, I saved resourcePath
into a string in the first ever call to [NSBundle mainbundle]
in the project (the first few calls were totally normal as I stated above) and used that resourcePath
string everywhere I needed [NSbundle mainbundle] and voila! no crashes/ leaks, nothing...
I'm totally confused.. Why would that call crash my app on the device but not the simulator?
Edit: using...
NSArray *array = [NSBundle allBundles];
NSBundle *bundle = [array objectAtIndex:0];
NSString *imagePath = [bundle bundlePath];
...instead of [[NSBundle mainBundle] resourcePath]
works too. I guess somehow I'm doing something affecting this particular call only.
Edit 2: Here is the backtrace when I set a breakpoint in -[NSObject doesNotRecognizeSelector:] :
#0 0x30e27b98 in -[NSObject doesNotRecognizeSelector:]
#1 0x30dacb18 in ___forwarding___
#2 0x30da3840 in __forwarding_prep_0___
#3 0x0000bcfe in -[CustomTableViewCell setImageName:] at CustomTableViewCell.m:93
#4 0x0000499e in -[RootTableViewController tableView:willDisplayCell:forRowAtIndexPath:] at RootTableViewController.m:469
#5 0x3364d5d0 in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:]
#6 0x3364cde0 in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:]
#7 0x335f832c in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow]
#8 0x335f6514 in -[UITableView layoutSubviews]
#9 0x335f22d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#10 0x32bac1c0 in -[CALayer layoutSublayers]
#11 0x32babedc in CALayerLayoutIfNeeded
#12 0x32bab844 in CA::Context::commit_transaction
#13 0x32bab474 in CA::Transaction::commit
#14 0x32bb35dc in CA::Transaction::observer_callback
#15 0x30da1830 in __CFRunLoopDoObservers
#16 0x30de9346 in CFRunLoopRunSpecific
#17 0x30de8c1e in CFRunLoopRunInMode
#18 0x332e7374 in GSEventRunModal
#19 0x335adc30 in -[UIApplication _run]
#20 0x335ac230 in UIApplicationMain
... Where #3 - CustomTableViewCell.m:93 is NSString *imagePath =[[NSBundle mainBundle] resourcePath]; in the part of the code I posted above.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
打开 NSZombieEnabled,您就会看到问题到底出在哪里。
Turn on NSZombieEnabled and you'll see where the problem really is.
设备崩溃而不是模拟器崩溃(反之亦然)通常是由为一个硬件平台编译的编译库/框架引起的,但不是为另一个硬件平台编译的。由于模拟器在 Intel 上运行而设备在 Arm 上运行,这会导致奇怪的崩溃。检查您可能添加的任何内容,尤其是最近未编译的内容。
错误
-[NSBundle < null 选择器>]:无法识别的选择器发送到实例 0x10a0e0
表明,无论出于何种原因,NSBundle
类“忘记”了它有一个mainBundle
方法。请注意,选择器为空,而不是我们在内存相关错误中所期望的对象。这表明某处存在高层腐败。我会将以下日志放在对
[NSBundle mainBundle];
的任何调用之前,这将告诉您它是否真的突然丢失了
mainBundle
选择器。编辑01:
嗯,崩溃一定严重到足以导致错误的错误代码返回。这表明问题可能出在调用 mainBundle 之前或之后的行中。
鉴于崩溃发生在 CustomTableViewCell 中,我猜测这是笔尖中的问题。您是否在笔尖中定义了 UITableViewCell 的子类?您在笔尖中定义了图像吗?它是什么类型的文件?使用不同的图像或不同的笔尖是否会出现相同的错误?
我确实认为关键线索是它可以在模拟器上运行,但不能在设备上运行。您需要寻找根据硬件而表现不同的东西。
你在这里肯定遇到了困难。
A crash on device but not the simulator (and vice versa) is usually caused by a compiled library/framework that is complied for one hardware platform but not the other. Since the simulator runs on intel and the device on arm, this causes odd crashes. Check anything you may have added, especially anything you didn't compile recently.
The error
-[NSBundle < null selector>]: unrecognized selector sent to instance 0x10a0e0
suggest that for whatever reason theNSBundle
class has "forgotten" it has amainBundle
method. Note that it is the selector which is null and not the object as we would expect in a memory related error. That suggest some high level corruption somewhere.I would put the following log before any calls to
[NSBundle mainBundle];
This will tell you if it really is suddenly losing the
mainBundle
selector.Edit01:
Hmmm, the crash must be bad enough to cause the wrong error code return. That suggest that the problem might be in the lines immediately before or after the call to mainBundle.
Given that the crash occurs in CustomTableViewCell, I'm going to guess it's a problem in a nib. Do you have a subclass of UITableViewCell defined in a nib? Do you have an image defined in the nib? What file type is it? Does the same error occur with a different image or a different nib?
I do think that the key clue is that it works on the simulator but not on the device. You need to look for things that would behave differently based on the hardware.
You've certainly got a hard one here.
基本上问题正如标题所说。 - 不,不是。我可以向您保证
[NSBundle mainBundle]
不是崩溃的原因。崩溃是您在代码的另一部分做错了什么的症状。例如糟糕的内存管理。Basically the problem is exactly what the title says. - No it is not. I can guarantee you that
[NSBundle mainBundle]
is not the reason for the crash. The crash is a symptom of something you are doing wrong in another part of your code. Like for example bad memory management.请注意,将路径字符串硬编码到文档中并不是一个好主意。您的路径会发生变化(通常随着每次构建而变化)。就您的崩溃而言,如果不查看更多代码就很难知道。但看看这个建议:
而不是
你应该使用
stringByAppendingPathComponent 特别适合处理路径和文件名。
Be aware that hard coding path strings into your document is not a good idea. Your path changes (ususally with each build). As far as your crash goes, it's hard to know without seeing more code. But take a look at this suggestion:
instead of
you should be using
stringByAppendingPathComponent is suited especially for dealing with paths and filenames.
您应该可以随时执行
[NSBundle mainBundle]
。如何将它分散在您的代码中以捕获它第一次中断的时间,希望接近破坏内存管理的东西(即发生内存损坏),正如 St3fan 所说的那样可能是问题所在。You should be able to do
[NSBundle mainBundle]
just about anytime. How about putting it scattered about your code to catch the first time it breaks, hopefully close to something that break the memory management (ie a memory corruption happening) as St3fan states can be the problem.一个可能的问题是,如果由于某种原因,您碰巧传递了相同的 imageName 两次,那么您将在保留它之前释放它。您可能需要将前两行更改为:
One possible problem is that if, for some reason, you happen to pass the same imageName twice, you'll release it before you retain it. You might want to change the first two lines to: