bindings from threads

  • I have an app that's using bindings and an array controller to manage
    data in an NSTableView. It's a networked app that brings in data from
    the net and tosses it into the array, which should then be
    automatically reflected in the view.

    First question is, I tend to get seemingly random crashes when it does
    the refresh. Some of the time it'll work, some of the time it won't.
    I'm manually handling the binding notifications here, along these
    lines:

    [self willUpdateValueForKey:@"myArray"];
    //interesting things, receive data, add on to myArray
    [self didUpdateValueForKey:@"myArray"];

    I've found that I can eliminate these crashes by instead accumulating
    into a new array, then adding on those array elements to my master
    array and sending my notifications from the main thread, instead of my
    watcher thread.

    Is this expected behavior? Should I not be able to do this from a
    secondary thread and only from the main thread? Or does this indicate
    that something else is going on?

    Secondly, is this the best way to do something like this? I don't want
    to fall back to the old way of using the data source and doing it all
    manually, but I would be interested in other binding approaches.
    Alternatively, I know that I can add an IBOutlet to my array
    controller and use that to just add the objects and not worry about
    the bindings notes. Would one way be preferrable to another? Which
    would be a more common approach?

    Thanks,

    -Jim....
  • The approach to take has two parts.  Since bindings are typically
    used to update UI widgets, the update notifications need to be called
    on the main thread.  A typical update may look something like this:

    [self performSelectorOnMainThread:@selector(willUpdateValueForKey:)
    withObject:@"someKey" waitUntilDone:YES];
    //Update the value for someKey
    [self performSelectorOnMainThread:@selector(didUpdateValueForKey:)
    withObject:@"someKey" waitUntilDone:YES];

    That handles the first part.  For the second part you need to make
    sure your accessors are threadsafe.  You can either accomplish this
    with locks or any of the other various thread safety directives or
    ensure that values are only updated on the main thread.

    On Oct 5, 2006, at 10:47 AM, Jim Thomason wrote:

    > I have an app that's using bindings and an array controller to manage
    > data in an NSTableView. It's a networked app that brings in data from
    > the net and tosses it into the array, which should then be
    > automatically reflected in the view.
    >
    > First question is, I tend to get seemingly random crashes when it does
    > the refresh. Some of the time it'll work, some of the time it won't.
    > I'm manually handling the binding notifications here, along these
    > lines:
    >
    > [self willUpdateValueForKey:@"myArray"];
    > //interesting things, receive data, add on to myArray
    > [self didUpdateValueForKey:@"myArray"];
    >
    > I've found that I can eliminate these crashes by instead accumulating
    > into a new array, then adding on those array elements to my master
    > array and sending my notifications from the main thread, instead of my
    > watcher thread.
    >
    > Is this expected behavior? Should I not be able to do this from a
    > secondary thread and only from the main thread? Or does this indicate
    > that something else is going on?
    >
    > Secondly, is this the best way to do something like this? I don't want
    > to fall back to the old way of using the data source and doing it all
    > manually, but I would be interested in other binding approaches.
    > Alternatively, I know that I can add an IBOutlet to my array
    > controller and use that to just add the objects and not worry about
    > the bindings notes. Would one way be preferrable to another? Which
    > would be a more common approach?
    >
    > Thanks,
    >
    > -Jim....
    > _______________________________________________
    > 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/<enigma0...>
    >
    > This email sent to <enigma0...>
  • Hi,

    You dont do any updating on thread not the main thread, do you?
    I'm quite sure cocoa drawing isnt thead safe...

    Am Oct 5, 2006 um 7:47 PM schrieb Jim Thomason:

    > I have an app that's using bindings and an array controller to manage
    > data in an NSTableView. It's a networked app that brings in data from
    > the net and tosses it into the array, which should then be
    > automatically reflected in the view.
    >
    > First question is, I tend to get seemingly random crashes when it does
    > the refresh. Some of the time it'll work, some of the time it won't.
    > I'm manually handling the binding notifications here, along these
    > lines:
    >
    > [self willUpdateValueForKey:@"myArray"];
    > //interesting things, receive data, add on to myArray
    > [self didUpdateValueForKey:@"myArray"];
    >
    > I've found that I can eliminate these crashes by instead accumulating
    > into a new array, then adding on those array elements to my master
    > array and sending my notifications from the main thread, instead of my
    > watcher thread.
    >
    > Is this expected behavior? Should I not be able to do this from a
    > secondary thread and only from the main thread? Or does this indicate
    > that something else is going on?
    >
    > Secondly, is this the best way to do something like this? I don't want
    > to fall back to the old way of using the data source and doing it all
    > manually, but I would be interested in other binding approaches.
    > Alternatively, I know that I can add an IBOutlet to my array
    > controller and use that to just add the objects and not worry about
    > the bindings notes. Would one way be preferrable to another? Which
    > would be a more common approach?
    >
    > Thanks,
    >
    > -Jim....
    > _______________________________________________
    > 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/<dominik...>
    >
    > This email sent to <dominik...>
    >
  • On Oct 5, 2006, at 10:47 AM, Jim Thomason wrote:

    > I've found that I can eliminate these crashes by instead accumulating
    > into a new array, then adding on those array elements to my master
    > array and sending my notifications from the main thread, instead of my
    > watcher thread.
    >
    > Is this expected behavior?

    Yes.  The Key-Value Observing notifications are being delivered in the
    thread in which they are posted, not in some other thread (such as, in
    this case, the main thread).  You will need to accumulate your changes
    into a unit of work in your other thread, and pass that work to the
    main thread for it to use in making the change.

      -- Chris
  • On Oct 5, 2006, at 11:33 AM, Ryan Britton wrote:

    > The approach to take has two parts.  Since bindings are typically
    > used to update UI widgets, the update notifications need to be
    > called on the main thread.  A typical update may look something like
    > this:
    >
    > [self performSelectorOnMainThread:@selector(willUpdateValueForKey:)
    > withObject:@"someKey" waitUntilDone:YES];
    > //Update the value for someKey
    > [self performSelectorOnMainThread:@selector(didUpdateValueForKey:)
    > withObject:@"someKey" waitUntilDone:YES];
    >
    > That handles the first part.  For the second part you need to make
    > sure your accessors are threadsafe.  You can either accomplish this
    > with locks or any of the other various thread safety directives or
    > ensure that values are only updated on the main thread.

    The above is not what you should do.  In particular, you should not be
    using main-thread performs to post KVO change notifications that are
    distinct from the actual change to your object.

    To see why the above is broken, consider this scenario:

    (1) Thread 2 asks the main thread to perform the following, which it
    does:

      [self willChangeValueForKey:@"someKey"];

    Then there's a random context switch.

    (2) Something on the main thread also changes that object, which
    invokes the following:

      [self willChangeValueForKey:@"someKey"];
      _someKey = @"foo";

    Then there's a random context switch.

    (3) Thread 2 happens to be chosen to run again, which does the
    following:

      _someKey = @"bar";

    and then asks the main thread to perform the following:

      [self didChangeValueForKey:@"someKey"];

    Then there's a random context switch.

    (4) The main thread finally executes:

      [self didChangeValueForKey:@"someKey"];

    Congratulations!  The state of your object is all messed up now, and
    that corruption is propagating to the observers of the key "someKey"
    -- especially if they were interested in the old and/or new values of
    the key for some purpose.

    Also, "thread-safe" accessors are almost *never* what you want;
    typically an object has enough state that thread safety needs to be
    treated as a way of delineating *transactions* on an object or even
    the entire graph of related objects.  This is necessary to prevent the
    object graph from becoming inconsistent when there can be multiple
    clients performing operations on it.

    As I've said before, if you're considering doing *anything* with
    threads, you should follow well-established patterns of use such as
    producer/consumer work queues.  You cannot just dive in to creating
    multithreaded applications by throwing a thread in here and a thread
    in there to "make things faster."  It not only doesn't work, it can be
    harmful to both the stability and performance of your application.

      -- Chris
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