Question

I am semi-new to cocoa programming, however I have worked quite a bit in C++;

I am having some issues with the NSSavePanel class. Whenever I use it (as shown below), I can see (by using breakpoints) that the code tries to execute the ending bracket. I then get a BAD_ACCESS message from Xcode in the main.h file. I cannot for the life of me figure out what I am doing wrong. Here is the code:

- (void)scannerDevice:(ICScannerDevice*)scanner didCompleteScanWithError:(NSError*)error;
{
    NSLog( @"scannerDevice: \n%@\ndidCompleteScanWithError: \n%@\n", scanner, error );
    [mProgressIndicator setHidden:YES];

    NSSavePanel *savePopup = [[NSSavePanel alloc]init];
    [savePopup runModal];

    NSMutableString *saveString = [[NSString alloc] init];
    saveString = [[savePopup URL] absoluteString];
    [saveString deleteCharactersInRange:NSMakeRange(0, 16)];
    [saveString appendString:@".jpeg"];

    NSLog(@"[[ADDRESS: %@", saveString); //Outputs /Users/tannerdsilva/Documents/TestFolder/NewName.jpeg
    NSError *errorSave = [[NSError alloc] init];

    [manager moveItemAtPath:[@"~/Foo.jpeg" stringByExpandingTildeInPath] toPath:[[savePopup URL] absoluteString] error:&errorSave]; // ~/Foo.jpeg does exist

    NSLog(@"ERROR: %@", errorSave);
    [saveString dealloc];
    [savePopup dealloc];

}

When I hard code the new destination and remove the NSSavePanel, I don't get any crashes.

Thank you ahead of time, and I apologize if this is a simple fix.

Was it helpful?

Solution

There are a couple of issues with your code.

  • You declare saveString as an NSMutableString but initialize it as an (immutable) NSString.
  • You're then not using that string at all but replace it with the autoreleased (and immutable) NSString that's returned from absoluteString, causing the original string to leak.
  • NSString responds to neither deleteCharactersInRange: nor to appendString (those are methods of NSMutableString).
  • You're leaking errorSave which you should initialize as nil anyway.
  • You should never ever call dealloc yourself, use release instead. But don't release saveString because it's already autoreleased (see above), you're over-releasing it here which will cause a crash when the autorelease pool is drained.

OTHER TIPS

Ok, there's a couple problems with your code:


Method signature has a trailing semi-colon

(void)scannerDevice:(ICScannerDevice*)scanner didCompleteScanWithError:
    (NSError*)error;

EDIT: Per @omz and @Rudy Velthuis, a trailing semi-colon on an implementation method signature is allowed by Objective-C. So you can ignore this 'problem'.


You should use the class instance for getting handle to save panel

NSSavePanel * savePanel = [NSSavePanel savePanel];

You should check the result of running the save panel modally

if ([savePanel runModal] == NSOKButton) {
    //...
}

*You are creating an instance of NSString * and leaking it, totally unnecessary*

NSMutable * saveString = [NSMutableString stringWithString: 
   [[savePopup URL] absoluteString]];

Once you correct the problems outlined above, you will want to remove the two dealloc lines, since the objects will now be autoreleased. Note that you normally want to call release in your code anyway, not dealloc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top