开发者

iPhone: Calling [NSBundle mainbundle] Crashes on the Device But not Simulator

开发者 https://www.devze.com 2022-12-18 19:59 出处:网络
Basically the problem is exactly what the title says. My app works smoothly on the simulator, with no crashes whatsoever.

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.


Turn on NSZombieEnabled and you'll see where the problem really is.


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 the NSBundle class has "forgotten" it has a mainBundle 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];

NSLog(@"responds to selector mainBundle=%@",[NSBundle respondsToSelector:@selector(mainBundle)]?@"YES":@"NO");

This will tell you if it really is suddenly losing the mainBundle selector.

Edit01:

Thanks for your answer. It seems Nsbundle states it can respond to mainbundle: "responds to selector mainBundle=YES", just before the crashing call to [NSBundle mainBundle]

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.


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.


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

 [imagePath stringByAppendingString:imageName]; 

you should be using

 [imagePath stringByAppendingPathComponent:imageName];

stringByAppendingPathComponent is suited especially for dealing with paths and filenames.


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.


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:

if (imageName != s) {
    [imageName release];
    imageName = [s retain]; 
}
0

精彩评论

暂无评论...
验证码 换一张
取 消