I´m on Mac OS X and Xcode 4.5.2
When executing these lines:
NSString *asSrcFileName = #"chromebar.png"
NSString *asSrcExtName = #".png"
NSString *asTempName = [asSrcFileName stringByReplacingOccurrencesOfString:asSrcExtName withString:#""];
I get a strange view of my variables in the debugger. See rectangle:
I expected asTmp to be #"chromebar" after line three.
I´ve been using stringByReplacingOccurrencesOfString pretty often so far and have no idea what´s wrong. Somehow it looks like there is a unicode issue.
Anyone out there to shed some light on me?
Are you inspecting asSrcTempName after the variable has been initialized (the green line showing the current execution point is below the initialization)?
Otherwise it's probably only uninitialized memory and lldb is showing garbage from a previous run.
I could not reproduce your problem in Xcode 4.5.1.
Related
Ok. So I had this extremely weird SIGABRT error on a complex Objective-C iOS program that I'm working on, and after one day of tracking I found the culprit.
Let's say we have the following code:
NSArray *a = [NSArray arrayWithObjects:#"a", #"b", #"c", nil];
NSLog(#"tada: %#", [a objectAtIndex:-1]);
Why the hell will this terminate the program with Program received signal: SIGABRT and the debugger not even pointing to my code (but rather in some assembly part) instead of a nicer 'index out of bounds' and 'hey, this line of code here be wrong' error?
I thought I messed up the project config, so I reproduced this on a brand new project: same result.
Is there a way to configure XCode to be more nice and indicate this kind of errors in a more human understandable way ?
As the documentation says:
If index is beyond the end of the array (that is, if index is greater
than or equal to the value returned by count), an NSRangeException is
raised
And the default action, when no exception handler is defined, is to... well... you can see what the default behaviour is.
You can use #try/#catch to trap the exception, but that's not really Objective-C-ish. You know how many elements are in the array; there's no real need for you to be accessing elements that don't exist.
Exceptions like this normally have a stack trace, so you can go back to the line of code causing the error. (It might be worth switching between LLDB and GDB if it's not working correctly. LLDB is faster and smaller but not completely reliable.(
You should see something along the lines of "index of out range" if you look in the console log in Xcode. SIGABRT is the result of an assertion being fired. Sometimes you have to hit "Continue" after the crash in order to get the message to print.
The debugger tells you where the crash actually happened. It doesn't know what the original cause was. If the debugger leaves you looking at the assembler, just move up the stack until you reach your code.
I load a sound like so:
sound = [[NSSound alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"alert" ofType:#"mp3"] byReference:NO];
Also I have "all exceptions" break point turned on in xCode. The above line throws an exception twice in a row before the code continues and my sound plays. all i see is that the code stops with Thread1: "breakpoint 4.3"
Could someone explain to me what's going on here and what 4.3 means? is there any reference for these numbers?
I've tried to use just:
sound = [NSSound soundNamed:#"alert"];
with exactly the same result...
thank you.
You are the first who noticed this problem with the System Sound…. I have the same issue in Xcode with the System Sound of the iPhone (iOS). If I turn on the "all exceptions" break point I get the same message you have. I went crazy today with this…. but probably is an Apple's issue and anyway is not dangerous maybe…..
Is there any way to disable this exception from "all exceptions" in Xcode?
… well if you enable exceptions only for "Objective-C" in the options, you do not get this message anymore. It mean that it is a C++ exception (more apple / framework related).
A friend of mine discovered some strange behaviour with NSDictionary, and I'm curious as to why it happens. Consider the following code:
NSDictionary *dict = [[NSDictionary alloc] init];
// Oops, we can't mutate an NSDictionary
[dict setObject:[[NSNull alloc] init] forKey:#"test"];
NSLog(#"Set");
The code produces a warning upon compilation that "'NSDictionary' may not respond to 'setObject:forKey:'". That's all well and good, and if you run it anyway, you'll get this output in the console:
-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Again, exactly what you'd expect to happen. However, at this point the app does not crash or terminate due to an uncaught exception. The setObject:forKey: method simply never returns, and the app appears to hang; the following NSLog is never executed. If you try to step over or into the method using GDB, debugging just seems to end, but without any explicit error message. The app continues to run, but the debugger provides no clue as to where in the code the execution is "stuck."
What's going on here? What is the app actually doing in this case, and why doesn't it crash with an NSInternalInconsistencyException or something of the like?
Edit: For those who have asked, I'm running XCode 4.1 on OS X Lion (10.7.2), building with "Apple LLVM compiler 2.1." I'm using all of the default settings you get with a new Cocoa project in XCode 4. I experience the same non-crashing behaviour regardless of whether I debug the program or just "Run" it. Changing from Debug building to Release building makes no difference. I can even locate the .app file manually in Finder and double click on it to execute it outside of XCode, and it still does not crash.
Exceptions do not crash AppKit programs. NSApplication installs a default exception handler that catches exceptions that your code doesn't. Then you just go back into the runloop as normal.
Lots of apps exhibit this behaviour. It's a common cause of inexplicable blank views/windows. If an exception happens before a view manages to finish drawing, the view will be blank, but the app won't crash. Exceptions only cause a crash if you deliberately change the default exception handler to crash.
I have written this trivial action method associated to a textfield.
Every time I enter text into a textfield a search in a PDF is performed and PDFView automatically scroll to selection:
- (IBAction) search:(id)id
{
NSString *query = [self.searchView stringValue]; // get from textfield
selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch];
if (selection != nil)
{
[self.pdfView setCurrentSelection:selection];
[self.pdfView scrollSelectionToVisible:self.searchView];
}
}
Problem is that after 3 or 4 searches I get EXC_BAD_ACCESS on row (i).
If I debug I see that query contains an NSCFString and not an NSString.
I think it is a memory management problem..but where?
I replicated the same issue inside a trivial testcase:
#interface PDFRef_protoTests : SenTestCase {
#private
PDFDocument *document;
}
........
- (void)setUp
{
[super setUp];
document = [[PDFDocument alloc] initWithURL: #"a local url ..."];
}
- (void)test_exc_bad_access_in_pdfdocument
{
for (int i =0 ;i<100; i++)
{
NSString *temp;
if (i % 2 == 0) temp = #"home";
else if (i % 3 ==0) temp = #"cocoa";
else temp=#"apple";
PDFSelection *selection = [document findString: temp
fromSelection:nil
withOptions:NSCaseInsensitiveSearch];
NSLog(#"Find=%#, iteration=%d", selection, i);
}
}
Update:
1) It seems that it happens also if I use asynchronous search (method beginFindString: withOptions) every time I perform second search.
2) I found a similar problem to mine in MacRuby Issue Tracking: http://www.macruby.org/trac/ticket/1029
3) It seems that if I disable temporarily garbage collection it works but memory goes up.
I wrote something like:
[[NSGarbageCollector defaultCollector] disable];
[[NSGarbageCollector defaultCollector] enable];
surrounding search code
Another Update
Very weird thing is that sometimes all works. Than I clean and Rebuild and problem arises again. From a certain point of view is is not 100% reproducible. I suspect a bug in PDFKit or some compiler setting I have to do
Update Again
Dears it seems very crazy. I'd concentrate on testcase which is very trivial and which replicates easily the problem. What's wrong with it? This testcase works only if I disable (by code or by project setting) GC
Another Update
Boys it seems a bug but I downloaded an example called PDFLinker from Apple website (http://developer.apple.com/library/mac/#samplecode/PDFKitLinker2/Introduction/Intro.html#//apple_ref/doc/uid/DTS10003594). This example implements a PDFViewer. Code of my app and this example are quite similars. For the same search action on same PDF, my memory rises at 300/400 MB while PDFLinker rises at 190MB. Clearly there is something wrong in my code. But I am comparing it bit by bit and I don't think I am inserting memory leaks (and Instrument doesn't give me any evidence). Maybe is there some project-wide setting ?
Update Yet
Changing from 64 bit to 32 bit memory consumption lowered. Surely there is a problem with 64bit and PDFKit. BTW still EXC_BAD_ACCESS on second search
SOLUTION
Crucial point is that PDFKit with Garbage collection is bugged.
If I disable GC all works correctly.
I had another issue that had complicated my analysis: I disabled GC on Project Setting but GC remained enabled on Target Settings. So Apple's example PDFLinked2 worked while mine not.
I agree you have found a bug in PDFKit.
I got various forms of errors (segmentation fault, selector not understood, etc) running your test case. Wrapping the code in #try/#catch doesn't prevent all errors associated with this method.
I also got errors printing the log message.
To work around the bug(s), I suggest you disable GC during your invocation of -findString:fromSelection:, as you've already discovered.
Also, be sure to make copies of the values of interest from selection before re-enabling GC. Don't just copy selection either.
If you conduct searches from multiple places in your code I also suggest you extract a separate method to perform the search. Then you can invoke that one to conduct the searches for you without duplicating the GC disable/enable nesting.
This sort of thing is usually evidence that you're hanging onto a pointer to an object that has been destroyed. Turn on zombie objects (with NSZombieEnabled) to see exactly where and when you're accessing a bad object.
Judging from your screen shot it doesn't seem like you have NSZombie turned on. Probably the reason why it doesn't help you. Here's how you turn it on:
How to enable NSZombie in Xcode?
The screenshot you provided was otherwise very useful, but you really need NSZombie to figure out this kind of errors. Well, unless it's obvious, which it isn't from the code you posted.
EDIT: I read the comment that you're using garbage collection. I'm an iOS developer, so I have very limited experience with garbage collection in Objective-C, but as far as I understand NSZombie doesn't work in a garbage collected environment.
I'm not sure it should be possible to get EXC_BAD_ACCESS in a garbage collected environment, unless you create your own pointer and try to call methods on it without having created an object and I don't see why you would do that.
I've heard that some frameworks doesn't work well with garbage collection, but I wouldn't think PDFKit was among them. Anyway, the solution might be to not use garbage collection. Perhaps you should file a bug report with Apple.
keep PDFSelection *selection as a member variable and pass it in fromSelection: instead of nil.
It is possible that PDFDocument keeps the returned PDFSelection instance to improve the performance.
Did you try retaining the searchview stringvalue object before using it?
As you say it happens when you type fast and it happens for async calls, it is possible that the object stringValue is pointing to is being released between the time your query object is pointing to it, and the time you use it int the search.
You could try something like this to see if the problem persists:
- (IBAction) search:(id)id
{
NSString *query = [[self.searchView stringValue] retain]; // get from textfield
selection = [document findString: query fromSelection:NULL withOptions:NSCaseInsensitiveSearch];
if (selection != nil)
{
[self.pdfView setCurrentSelection:selection];
[self.pdfView scrollSelectionToVisible:self.searchView];
}
[query release];
}
Of course there is also the possibility that document is relased. How do you declare it? is it a property with retain? Can it be released by the time you are searching?
EDIT:
I see that you posted the code with the second parameter as NULL, but in your screenshot, this value is nil.
The documentation says you should use NULL when you want to start the search from the beginning.
http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/QuartzFramework/Classes/PDFDocument_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003873-RH2-DontLinkElementID_1
And as the compiler interprets nil and NULL differently, this could be leading to some weird behavior internally.
I'm following this tutorial, attempting to learn a bit about iPhone development, and there come a point where the author uses the stringWithContentsofURL method but xcode is telling me that there is no stringWithContentsofURL method found. I've done some searching and I've not been able to come up with a solution. This is a screen shot of the xcode window displaying the error:
alt text http://mywebprogrammer.com/so/obj-c%20problem%200.png
stringWithContentsofURL: is a class method, not an instance method, so you have to use it as
[NSString stringWithContentsOfURL:myURL]
or if you want to allocate it yourself, you would do:
[[NSString alloc] initWithContentsOfURL:myURL]
but then you would have to release it later
Its [NSString stringWithContentsOfURL]. Note: its the capital 'O' (in Of) not small 'o' as given by you. Also Its a static method so cannot be used against an object.