Re: Voice Over Performance for Complex Custom View
Re: Voice Over Performance for Complex Custom View
- Subject: Re: Voice Over Performance for Complex Custom View
- From: Xiang Cao <email@hidden>
- Date: Thu, 17 Sep 2009 14:49:54 -0700
- Thread-topic: Voice Over Performance for Complex Custom View
I'm right. I finally solved my performance problem. It is the
NSAccessibilityUnignoredChildren.
I create and retain a list of unignored children for the first time with
NSAccessibilityUnignoredChildren. I will just simply return it without
searching again for the rest of time. So the children fetch looks like this:
if(mUnignoredChildren == nil)
{
mUnignoredChildren = NSAccessibilityUnignoredChildren(mChildren);
[mUnignoredChildren retain];
}
return mUnignoredChildren;
Now it's blindly fast. The only thing I need to take care of now is to
update this unignored children list once the UI structure is changed. And
this is fairly easy.
Thanks for all your help. Without your help, I cannot figure this out.
BTW: Yes, I do have a lot of ignored/junk elements.
Xiang
On 9/17/09 2:11 PM, "James Dempsey" <email@hidden> wrote:
>
> On Sep 17, 2009, at 2:06 PM, Xiang Cao wrote:
>
>> Thanks for the explanation. I think the only way for me to improve the
>> performance is to create and retain the unignored children list for
>> the
>> first time. So every time when voice over ask for children, I can just
>> return a list of prepared unignored children instead of calling
>> "NSAccessibilityUnignoredChildren" to do this everytime. With the
>> help of
>> Instruments test tool, I think the NSAccessibilityUnignoredChildren
>> is the
>> most time consuming part because of it's recursive nature and my
>> huge UI
>> structure.
>>
>> My question is: what does NSAccessibilityUnignoredChildren do? Does
>> it only
>> return the unignored children or it also return unignored
>> grandchildren? In
>> another word, when voice over ask for children, does it mean all the
>> unignored children below the current level? Or it means the unignored
>> children from the next level only?
>
> NSAccessibilityUnignoredChildren is recursive. You can think of an
> 'ignored' element as being 'passed through'.
>
> If you had something like:
>
> Element A --children--> Element B (ignored) --children--> Element C
> (ignored) --children--> Element D.
>
> Then Element A would report Element D as a child.
>
> -James
>
>>
>> On 9/17/09 11:25 AM, "James Dempsey" <email@hidden> wrote:
>>
>>> Xiang,
>>>
>>>> My question is when they ask about children's count, subarray or
>>>> index, do they mean their unignored children or the direct children?
>>>
>>> The methods deal with unignored children. You should never return an
>>> ignored element from any NSAccessibility method.
>>>
>>> If you already have the children arrays built, and you are not
>>> creating new accessibility objects every time, I would not expect you
>>> to see much performance improvement from these three methods because
>>> your implementations are essentially doing what AppKit does by
>>> default
>>> anyway. Since you are not creating the children new every time they
>>> are asked for, there won't be much savings.
>>>
>>> The methods tend to improve performance most when you have enough
>>> internal information to avoid the array operation. For instance, if
>>> your faux object stored its child index, such that - (NSUInteger)
>>> accessibilityIndexOfChild:(id)child was not an array lookup, but you
>>> could just pull the index out of the child and return it, you would
>>> probably see a performance boost.
>>>
>>> Note that another reason why the methods may not be working is that
>>> accessibilityArrayAttributeCount: does not call super, so if
>>> VoiceOver
>>> checks to see the size of anything but children, it will be told
>>> there
>>> are zero items.
>>>
>>> -James
>>>
>>> On Sep 17, 2009, at 10:38 AM, Xiang Cao wrote:
>>>
>>>> Thanks for the hint.
>>>>
>>>> I changed the hash to return the pointer of real view instead of
>>>> recursive.
>>>> But the performance does not become better. To answer your question,
>>>> my real
>>>> GUI object are in C++, not Object C. That's why I have to create a
>>>> fake
>>>> structure for accessibility.
>>>>
>>>> About the three new functions, I still cannot get it work. My
>>>> question is
>>>> when they ask about children's count, subarray or index, do they
>>>> mean their
>>>> unignored children or the direct children? You mentioned for the sub
>>>> array
>>>> you have to always return the unignored children, but what about the
>>>> count
>>>> and the index? What are the target objects they are asking?
>>>>
>>>> My full code of that three functions:
>>>>
>>>> - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
>>>> {
>>>> if([attribute isEqualToString:NSAccessibilityChildrenAttribute])
>>>> {
>>>> if(mChildren) return [mChildren count]; else return 0;
>>>> }else 0;
>>>> }
>>>>
>>>> - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute
>>>> index:(NSUInteger)index maxCount:(NSUInteger)maxCount
>>>> {
>>>> if([attribute isEqualToString:NSAccessibilityChildrenAttribute])
>>>> {
>>>> if(index+maxCount>[mChildren count]) maxCount = [mChildren
>>>> count] -
>>>> index;
>>>> NSRange range = NSMakeRange(index, maxCount);
>>>> NSArray* subarray = [NSAccessibilityUnignoredChildren
>>>> (mChildren)
>>>> subarrayWithRange:range];
>>>> //I changed this from direct children's subarray to unigored
>>>> children's sub
>>>> array, there is no error anymore, but it still does not work
>>>> properly.
>>>> NSLog(@"subarray count %d", [subarray count]);
>>>> return subarray;
>>>> }else return [super accessibilityArrayAttributeCount:attribute];
>>>> }
>>>>
>>>> - (NSUInteger)accessibilityIndexOfChild:(id)child
>>>> {
>>>> DFW_Accessibility* dfwchild = (DFW_Accessibility*)child;
>>>>
>>>> if(dfwchild->mParent && dfwchild->mParent->mChildren)
>>>> {
>>>> NSUInteger index = [dfwchild->mParent->mChildren
>>>> indexOfObject:child];
>>>> if(index == NSNotFound)
>>>> {
>>>> NSLog(@"NSNotFound");
>>>> return NSNotFound;
>>>> }else NSLog(@"child index %d", index);
>>>> return index;
>>>> }else
>>>> {
>>>> return NSNotFound;
>>>> }
>>>> }
>>>>
>>>> By the way, I have filed the bug about the double speak.
>>>>
>>>> Do you know any performance checking tool beside shark on snow
>>>> leopard which
>>>> can check which part of code is consuming the time? Because shark
>>>> does not
>>>> work on our app under snow leopard.
>>>>
>>>> Thanks.
>>>>
>>>>
>>>> On 9/16/09 5:36 PM, "Mike Engber" <email@hidden> wrote:
>>>>
>>>>>
>>>>> On Sep 16, 2009, at 4:11 PM, Xiang Cao wrote:
>>>>>
>>>>>> Thanks for the reply.
>>>>>>
>>>>>> My isEqual is implemented as the following:
>>>>>>
>>>>>> - (BOOL)isEqual:(id)object {
>>>>>> if ([object isKindOfClass:[DFW_Accessibility self]]) {
>>>>>> DFW_Accessibility* other = object;
>>>>>> return mTView == other->mTView;
>>>>>> } else {
>>>>>> return NO;
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> - (unsigned)hash {
>>>>>> return [mRole hash] + [mParent hash]; //mRole is NSString* and
>>>>>> mParent
>>>>>> is another DFW_Accessibility object
>>>>>> }
>>>>>>
>>>>>> Because each of my custom access object has an linked Tview
>>>>>> pointer
>>>>>> which
>>>>>> points to one of the real element in our GUI library. I think it
>>>>>> should be
>>>>>> correct to compare their pointer to see if they are the same
>>>>>> accessibility
>>>>>> object. For hash, I'm not sure if I'm doing it correctly or not.
>>>>>
>>>>> You hash function will return the same value for all siblings with
>>>>> the
>>>>> same role. While this is OK since equal object will hash the
>>>>> same, it
>>>>> could be improved.
>>>>>
>>>>> Plus it will be fairly expensive since it recurs up the hierarchy
>>>>> calling hash on all its ancestors.
>>>>>
>>>>> I suggest simply returning mTView (i.e. the address).
>>>>>
>>>>>> I forgot to mention. I didn't generate all the children
>>>>>> everytime on
>>>>>> the
>>>>>> fly. They are allocated only when children attributes are asked
>>>>>> for
>>>>>> the
>>>>>> first time. Then the array is retained as a member variable for
>>>>>> later use. I
>>>>>> did this to improve the performance, but it's still a little slow.
>>>>>
>>>>> Are the "real elements" in your GUI libray ObjC objects? If so, it
>>>>> would be cheapest to just make those classes implment the
>>>>> accessibility protocol.
>>>>>
>>>>> When I don't have ObjC object I can accessorize, I generally create
>>>>> UI
>>>>> Elements on the fly and it performs well enough. One advantage of
>>>>> this
>>>>> approach is the UI Elements are never out of sync with the actual
>>>>> UI.
>>>>> I guess if your hierarchy is big enough, all the allocations
>>>>> could be
>>>>> slowing you down. You should measure and test.
>>>>>
>>>>> As for your original problem:
>>>>>> But I saw errors from console said like: !!! Failed to find
>>>>>> child 2
>>>>>>>
>>>>>> (index 2) for AX specifier: <NSWindow: 0x21eb1e90>{32}.
>>>>>
>>>>> It seems like you're returning a ui element that's the second child
>>>>> of
>>>>> the window's third child. But, somehow later when we go to use this
>>>>> ui
>>>>> element its parent is reporting that it has no children.
>>>>>
>>>>> Did you implement all three methods:
>>>>> (NSUInteger)accessibilityArrayAttributeCount:(NSString *)
>>>>> attribute
>>>>> - (NSArray *)accessibilityArrayAttributeValues:(NSString *)
>>>>> attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
>>>>> - (NSUInteger)accessibilityIndexOfChild:(id)child
>>>>>
>>>>> Your email only showed code for the last method.
>>>>>
>>>>> If you did implement all these methods, I'm going to guess that the
>>>>> problem is accessibilityArrayAttributeValues is returning an empty
>>>>> array when passed a maxCount of one.
>>>>>
>>>>> -ME
>>>>>
>>>>
>>>
>>> --------------------------------------------------
>>> James Dempsey
>>> AppKit Engineering
>>> Apple
>>> email@hidden
>>>
>>>
>>>
>>
>
> --------------------------------------------------
> James Dempsey
> AppKit Engineering
> Apple
> email@hidden
>
>
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Accessibility-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden