Do Cocoa bindings retain their own values?

  • Hi everybody,

    During my latest hunt for irreproducible crashes, I've run into lots
    of thread-safety issues with a dialog that displays the progress of a
    worker thread.

    Cocoa bindings are not thread-safe, so you have to be extra careful
    about memory management, retain/release cycles and autorelease pools.

    I think I've pretty much fixed the problem, but now I'm in full
    paranoia mode and every single line of code looks like a potential
    crashing bug..

    From the worker thread I call the method updateStageText directly:

    - (void) updateStageText: (NSString*) text;{

    [self performSelectorOnMainThread:
    @selector(internalUpdateStageText:) withObject: text waitUntilDone:
    YES];

    }

    This calls a private method but on the main thread:

    - (void) internalUpdateStageText: (NSString*) text;{

    id old = paramStageText;
    [self willChangeValueForKey: @"stageText"];
    paramStageText = [text copy];
    [self didChangeValueForKey: @"stageText"];
    [old release];
    }

    All this is to make sure that KVC notifications go into the main
    thread and that the allocation itself is safe.

    As you notice, however, I call performSelectorOnMainThread with
    waitUntilDone: YES, which is extra safe but also extra slow.

    Now for the question: can I call it with waitUntilDone: NO !?

    The code as it stands wouldn't be thread safe because the NSString
    parameter might already have been de-allocated by the worker thread by
    the time [text copy] is executed on the main thread.

    This could be solved by retaining the text parameter like this:

    - (void) updateStageText: (NSString*) text;{

    [text retain];
    [self performSelectorOnMainThread:
    @selector(internalUpdateStageText:) withObject: text waitUntilDone:
    YES];
    [text release];
    }

    Is this safe? I don't know whether the retain/release mechanism itself
    is thread-safe, but I presume it is.

    More worrying is the original

    [old release];

    line. This is perfectly fine if the Cocoa bindings NSTextField retains
    its value, but does it?

    I hope I’m only paranoid, but I would appreciate the insights from the
    Cocoa threading gurus :-)

    Best regards,

    Frank
  • On 19 Nov 2007, at 21:42, Frank Reiff wrote:

    > Hi everybody,
    >
    > During my latest hunt for irreproducible crashes, I've run into lots
    > of thread-safety issues with a dialog that displays the progress of
    > a worker thread.
    >
    > Cocoa bindings are not thread-safe, so you have to be extra careful
    > about memory management, retain/release cycles and autorelease pools.
    >
    > I think I've pretty much fixed the problem, but now I'm in full
    > paranoia mode and every single line of code looks like a potential
    > crashing bug..
    >
    > From the worker thread I call the method updateStageText directly:
    >
    >
    > - (void) updateStageText: (NSString*) text;{
    >
    > [self performSelectorOnMainThread:
    > @selector(internalUpdateStageText:) withObject: text waitUntilDone:
    > YES];
    >
    > }
    >
    > This calls a private method but on the main thread:
    >
    > - (void) internalUpdateStageText: (NSString*) text;{
    >
    > id old = paramStageText;
    > [self willChangeValueForKey: @"stageText"];
    > paramStageText = [text copy];
    > [self didChangeValueForKey: @"stageText"];
    > [old release];
    > }
    >
    > All this is to make sure that KVC notifications go into the main
    > thread and that the allocation itself is safe.
    >
    > As you notice, however, I call performSelectorOnMainThread with
    > waitUntilDone: YES, which is extra safe but also extra slow.
    >
    > Now for the question: can I call it with waitUntilDone: NO !?
    >
    > The code as it stands wouldn't be thread safe because the NSString
    > parameter might already have been de-allocated by the worker thread
    > by the time [text copy] is executed on the main thread.

    Using waitUntilDone:NO is perfectly acceptable. From the documentation:

    The receiver and arg are retained until the perform is finished.

    i.e. the "text" object will be retained by Cocoa for you.
    >
    >
    > This could be solved by retaining the text parameter like this:
    >
    > - (void) updateStageText: (NSString*) text;{
    >
    > [text retain];
    > [self performSelectorOnMainThread:
    > @selector(internalUpdateStageText:) withObject: text waitUntilDone:
    > YES];
    > [text release];
    > }
    >
    > Is this safe? I don't know whether the retain/release mechanism
    > itself is thread-safe, but I presume it is.
    >
    > More worrying is the original
    >
    > [old release];
    >
    > line. This is perfectly fine if the Cocoa bindings NSTextField
    > retains its value, but does it?
    >
    > I hope I’m only paranoid, but I would appreciate the insights from
    > the Cocoa threading gurus :-)
    >
    > Best regards,
    >
    > Frank
  • On Nov 19, 2007 1:42 PM, Frank Reiff <reiff...> wrote:

    > Now for the question: can I call it with waitUntilDone: NO !?

    Yes, assuming no other inter-thread dependencies exist.

    > The code as it stands wouldn't be thread safe because the NSString
    > parameter might already have been de-allocated by the worker thread by
    > the time [text copy] is executed on the main thread.

    The performSelectorOnMainThread:withObject: method retains the object
    you supply until the target object has processed the selector.

    -Shawn
previous month november 2007 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    
Go to today