Seeking debugging advice

  • Hello all,

    I've been fighting with a strange bug for the last 3 days and I'm not
    sure what to do now - I'm completely stuck (http://
    www.cocoabuilder.com/archive/message/cocoa/2006/10/25/173378). I'm
    gonna need all your help cocoa wizards. So here's the basic algorithm
    in ause:
    1. I have a location object which has an address property (NSString)
    2. Locations are displayed in a table
    3. Clicking on a table row updates a NSTextView with the address

    So the actual problem is that the address property of the previous
    selected location object changes to the empty string in a mysterious
    way. So here's a timeline of the events which happen:
    1. When the text changes in the NSTextView its delegate updates the
    address property of the current selected location (Works)
    2. When the user clicks on another row the action method fetches the
    address property of the newly selected location and tries to set it

    Now here's the strange thing: calling NSTextView's setString: somehow
    modifies the address property of the previous location object to the
    empty string! So before the call is executed the address property is
    intact and after the call it's gone. Now how that happens... I dunno
    but I find it real strange how a NSTextView method modifies an
    object's property.

    So up until now I've tried setting up a watchpoint for the variable.
    Now the strange behavior here is that it's value only changes once,
    the first time the property setter is called. I thought that
    everytime I set a new string as the property it should change but for
    some reason it doesn't... So what I've done is find out the address
    of the property (e.g. 0x3234fa5) and then use "po 0x3234fa5" to print
    out the string. Just before the call to setString: executing the po
    command outputs the correct address string and after the setStrung:
    call the po reports an empty string. I've been after this problem for
    several days now and I can't continue developing until I resolve
    that... so any advice is greatly appreciated.

    Regards,
    David
  • On Oct 26, 2006, at 4:34 PM, David Aames wrote:

    > Now here's the strange thing: calling NSTextView's setString:
    > somehow modifies the address property of the previous location
    > object to the empty string!

    Have you tried running your program in Guard Malloc?

    Nick Zitzmann
    <http://www.chronosnet.com/>
  • Hey David,

    I've written several programs that heavily use NSTextView. In all of
    them I've had to do this:

    NSString *text = [NSString stringWithContentsOfFile: @"/…"];
    [textView setString: @""];
    [textView setString: text];

    The part you should take note of is where I set the string to a blank
    string. I would have a whole files worth of text in the view and then
    change it to the contents of another file. If I didn't have that line
    that first set the string to a blank one I would get some funky bugs.
    The text on screen wouldn't change and when I tried to edit it I would
    get weird errors.

    Hope this helps, Alan

    --
    // Quotes from yours truly -------------------------
    "You don't forget, you just don't remember."
    "Maturity resides in the mind."
    "Silence is the Universe's greatest gift."
    "When the World realizes that religion really is unimportant, then it
    shall evolve."
  • Hey Alan,

    Thanks for that. On my way to work today it suddenly hit me what the
    problem was - NSTextView's storage. NSTextView uses a NSMutableString
    so all address locations we using the same string and that's why the
    watchpoint was called only once. So the solution is to copy the
    string before assigning it as the property of your custom object.

    On 27 Oct 2006, at 15:19, Alan Smith wrote:

    > Hey David,
    >
    > I've written several programs that heavily use NSTextView. In all of
    > them I've had to do this:
    >
    > NSString *text = [NSString stringWithContentsOfFile: @"/…"];
    > [textView setString: @""];
    > [textView setString: text];
    >
    > The part you should take note of is where I set the string to a blank
    > string. I would have a whole files worth of text in the view and then
    > change it to the contents of another file. If I didn't have that line
    > that first set the string to a blank one I would get some funky bugs.
    > The text on screen wouldn't change and when I tried to edit it I would
    > get weird errors.
    >
    > Hope this helps, Alan
    >
    > --
    > // Quotes from yours truly -------------------------
    > "You don't forget, you just don't remember."
    > "Maturity resides in the mind."
    > "Silence is the Universe's greatest gift."
    > "When the World realizes that religion really is unimportant, then it
    > shall evolve."
  • I don't understand. Would you mind explaining it more thoroughly?

    It should be as clear as possible for anyone searching the archives.

    Congratulations!
    Peace, Alan

    --
    // Quotes from yours truly -------------------------
    "You don't forget, you just don't remember."
    "Maturity resides in the mind."
    "Silence is the Universe's greatest gift."
    "When the World realizes that religion really is unimportant, then it
    shall evolve."
  • Okay, I'm gonna try to illustrate the point with example code. Let's
    say that the general architecture of your data model & controller is
    something similar to the following:

    1. You have class which has a string property
    2. You have an array (NSMutableArray) which holds instances of this
    class
    3. The class another single property which is used as an identifier
    to the user (eg name, id, etc)
    4. The identifier property is used in a table to represent the object
    5. When the user clicks on a row additional user elements are used to
    display the other attributes of the current selected object (eg a
    checkbox NSButton could be used to visualize a BOOL property, etc)
    6. In this particular case we assume that one of our string
    properties (outlined in 1) is going to be displayed using a NSTextView

    Now let us consider our general algorithms for getting this setup
    running. Firstly we need to update the current selected object's
    property whenever the user modifies the NSTextView - so we're going
    to use a delegate and implement - (void)textDidChange:(NSNotification
    *)aNotification which is called everytime the contents of the text
    view change.

    We also need to provide an implementation for the action method of
    the table - obviously the controls need to be updated when the user
    clicks on another row. So let's write down the general algorithm for
    these two methods.

    - (void)textDidChange:(NSNotification *)aNotification
    1. Retrieve the NSText object
    2. Retrieve the current selected object
    3. Update the relevant property

    - Action method
    1. Check if the user clicked on a row
    2. If a row was clicked retrieve the object representing the just
    selected row
    3. Update the relevant GUI objects representing the respective
    properties

    Because the actual logic bug which I was investigating for 4 days
    lies in the delegate method of the text view I'm gonna first provide
    some sample code for the table action method. So here it goes:

    if([self currentSelectedLocation])
    {
    NSLog(@"Clicked on a valid row");
    [self enableLocationEditboxes];
    DALocation* loc = [self currentSelectedLocation];
    NSLog(@"Current clicked location object is: %@", loc);
    [tagsLocsLocationView setString:[loc locationAddress]];
    }
    else
    [self disableLocationEditboxes];

    The method is pretty straightforward. [self currentSelectedLocation]
    returns the current selected object or nil if no row is selected.
    [tagsLocsLocationView setString:[loc locationAddress]]; updates the
    view to display the address of the current object.

    Now onto the implementation of the delegate method. My first
    implementation was something similar to the following:

    NSLog(@"Address changed");
    NSText* t = [aNotification object];
    DALocation* loc = [self currentSelectedLocation];
    NSLog(@"Setting the address to %@", [t string]);
    [loc setLocationAddress:[t string]];

    Now imagine that we have two instances of our objects. When you type
    something in the text view the address property is set to the address
    of the mutable string which acts as a storage for the text view. So
    when you select the other row this statement - [tagsLocsLocationView
    setString:[loc locationAddress]]; is executed so it updates the text
    storage of the current object - BUT because the storage is mutable
    both objects' properties point to the same string address! So your
    custom objects' property share the same object consequently modifying
    one of them modifies all of them (due to the mutable nature of the
    text view's storage). So the proper way to implement the delegate
    method is something similar to this:

    NSLog(@"Address changed");
    NSText* t = [aNotification object];
    DALocation* loc = [self currentSelectedLocation];
    NSLog(@"Setting the address to %@", [t string]);
    NSString* str = [NSString stringWithUTF8String:[[t string] UTF8String]];
    [loc setLocationAddress:str];

    This implementation uses a copy of the string so modifying the view's
    text storage doesn't affect the other object. I hope this post clears
    things up.

    Regards,
    David

    On 27 Oct 2006, at 21:56, Alan Smith wrote:

    > I don't understand. Would you mind explaining it more thoroughly?
    >
    > It should be as clear as possible for anyone searching the archives.
    >
    > Congratulations!
    > Peace, Alan
    >
    > --
    > // Quotes from yours truly -------------------------
    > "You don't forget, you just don't remember."
    > "Maturity resides in the mind."
    > "Silence is the Universe's greatest gift."
    > "When the World realizes that religion really is unimportant, then it
    > shall evolve."
  • Hi, Alan.  Have you tried this, instead?  The following has worked
    flawlessly in all of my own programs.  Note the call to -
    didChangeText, which was designed, AFAIK, for times such as these:

    NSString *text = [NSString stringWithContentsOfFile: @"/…"];
    [textView setString: text];
    [textView didChangeText];

    Cheers,
    Andrew

    On 27 Oct 2006, at 07:19, Alan Smith wrote:

    > Hey David,
    >
    > I've written several programs that heavily use NSTextView. In all of
    > them I've had to do this:
    >
    > NSString *text = [NSString stringWithContentsOfFile: @"/…"];
    > [textView setString: @""];
    > [textView setString: text];
    >
    > The part you should take note of is where I set the string to a blank
    > string. I would have a whole files worth of text in the view and then
    > change it to the contents of another file. If I didn't have that line
    > that first set the string to a blank one I would get some funky bugs.
    > The text on screen wouldn't change and when I tried to edit it I would
    > get weird errors.
    >
    > Hope this helps, Alan
    >
    > --
    > // Quotes from yours truly -------------------------
    > "You don't forget, you just don't remember."
    > "Maturity resides in the mind."
    > "Silence is the Universe's greatest gift."
    > "When the World realizes that religion really is unimportant, then it
    > shall evolve."
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/andrew.merenbach%
    > 40ucla.edu
    >
    > This email sent to <andrew.merenbach...>
previous month october 2006 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today