2
votes

I'm coding in Cocoa, on OS X.

I'm trying to receive a file that is dragged and dropped onto my NSView subclass - which I can do; and get its contents and filename and display them - which I can do for any type of file first time, but on the second time, when I try and drag another file on, I can only set the title setTitle:, but not the main body text setText:

The errors I am getting are:

Canceling drag because exception 'NSInternalInconsistencyException' (reason 'Invalid parameter not satisfying: aString != nil') was raised during a dragging session

and

Assertion failure in -[NSTextFieldCell _objectValue:forString:errorDescription:], /SourceCache/AppKit/AppKit-1187/AppKit.subproj/NSCell.m:1532

My code (sorry, it's quite long!):

- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
NSPasteboard *pboard;
NSDragOperation sourceDragMask;

sourceDragMask = [sender draggingSourceOperationMask];
pboard = [sender draggingPasteboard];

if ([[pboard types] containsObject:NSFilenamesPboardType]) {

    NSURL *file = [NSURL URLFromPasteboard:pboard];
    //NSData *data = [NSData dataWithContentsOfURL:file];

    NSError *error;
    NSStringEncoding encoding;
    NSString *contentString = [[NSString alloc] initWithContentsOfURL:file usedEncoding:&encoding error:&error];

    NSLog(@"Error: %@",error);

    NSString *last = [[file path] lastPathComponent];
    NSArray *parts = [last componentsSeparatedByString:@"."];
    NSString *filename = [parts objectAtIndex:0];
    NSString *fileType = [parts objectAtIndex:1];

    NSLog(@"FILETYPE: %@", fileType);

    if ([fileType isEqualToString:@"txt"] || [fileType isEqualToString:@"md"]) {
        [self setTitle:filename];

        if (self.textViewString == (id)[NSNull null] || self.textViewString.length == 0) {
            [self setText:contentString];
        } else {
            BOOL whatToDo = (NSRunCriticalAlertPanel(@"What do you want to do?", nil, @"Append", @"Replace", nil) == NSAlertDefaultReturn);

            if (whatToDo) {
                //Append
                [self setText:[NSString stringWithFormat:@"%@\n%@",self.textViewString,contentString]];
            } else {
                //Replace
                [self setText:contentString];
            }
        }
        return YES;
    } else {
        return NO;
    }
} else if ([[pboard types] containsObject:NSPasteboardTypeString]) {
    NSString *draggedString = [pboard stringForType:NSPasteboardTypeString];

    if (self.textViewString == (id)[NSNull null] || self.textViewString.length == 0) {
        [self setText:draggedString];
    } else {
        [self setText:[NSString stringWithFormat:@"%@\n%@",self.textViewString,draggedString]];
    }
    return YES;
}
else {
    return NO;
}

}

Thanks in advance! :)

2

2 Answers

2
votes

Sounds like Cocoa is canceling the drag when any exception is raised, and an exception is getting raised when something internally is expecting a string and is getting a nil value instead.

It's just a guess without having more information, but I would predict that stringWithFormat: is raising the exception, as it looks like the only really potentially fragile bit of what you have written.

You are doing a couple ill-advised things. First, you are assuming that -initWithContentsOfURL:usedEncoding:error: is succeeding. You should not do this. Instead, you need to pass an NSError ** that can be filled in on error, test whether contentString is nil, and, if so, check the error accordingly. I have a feeling that you will find you are getting nil, and the error will explain why.

Possibly unrelated, but your if (whatToDo) is not doing what you probably think it is. Since whatToDo is a pointer to an autoreleased NSNumber instance your conditional will always evaluate to true, since the pointer is non-zero. What you likely meant to do was something like the following:

 BOOL whatToDo = (NSRunCriticalAlertPanel(@"What do you want to do?", nil, @"Append", @"Replace", nil) == NSAlertDefaultReturn);

    if (whatToDo) {
        //Append
        [self setText:[NSString stringWithFormat:@"%@\n%@",self.textViewString,contentString]];
    } else {
        //Replace

        [self setText:contentString];
    }
0
votes

Lots of thanks for the many tips and pieces of advice from this answer by Conrad Shultz! I've followed the advice and tips there.

However, my problem turned out to be very, very basic. It lied in the line BOOL whatToDo = (NSRunCriticalAlertPanel(@"What do you want to do?", nil, @"Append", @"Replace", nil) == NSAlertDefaultReturn);

It turns out a string must be passed to the second parameter, but I was passing nil. Fixed!