Re: MyShadow was deallocated while key value observers...
Re: MyShadow was deallocated while key value observers...
- Subject: Re: MyShadow was deallocated while key value observers...
- From: Leonardo <email@hidden>
- Date: Sat, 28 Jun 2014 10:24:08 +0200
- Thread-topic: MyShadow was deallocated while key value observers...
I have found the origin of the trouble.
Shortly, when I add a second shadow to a second word and the second shadow
has the same values as the first one (e.g. offset, blur...), the textStorage
*automatically* replaces the second shadow with the first one. So at the end
I get *one* shadow on two different words. But if I add the second shadow
with different values (e.g. offset, blur...), it doesn't get replaced. That
sounds weird. It must be a kind of textStorage's optimization.
I run some test. I created a brand new project. I didn't use any pointer,
but just added a couple of shadows to two different words.
I firstly create a brand new shadow.
I print the shadow pointer with (NSInteger)shadow and I get e.g. 11111.
Then I add this shadow to the first word and I verify it has been properly
added, using shadowTest = [textStorage attributesAtIndex:...
I print the shadowTest pointer with (NSInteger)shadow and I get e.g. 11111.
Correct.
Then I create a brand new shadow.
I print the shadow pointer with (NSInteger)shadow and I get e.g. 22222.
Then I add this shadow to the second word and I verify it has been properly
added, using shadowTest = [textStorage attributesAtIndex:...
I print the shadowTest pointer with (NSInteger)shadow and I still get e.g.
11111. Wrong!!!
So, I tried to create the second shadow using different values, e.g.
the offsetX.
CGFloat offsetX = 1;
- (id)init
{
if((self = [super init]))
{
[self setShadowOffset:NSMakeSize(offsetX++, -1)];
}
return self;
}
Now I add the second shadow to the second word and I properly find that the
shadowTest pointer is 22222. Fine.
So, someway, when the textStorage feels the same shadow values, it replaces
the second shadow with the first one. The problem is that if the user
modifies the second shadow, the 2 shadows get modified together. Too bad.
In facts, when the users modifies the second shadow, I do not replace the
shadow within the textStorage using removeAttribute: and addAttribute:, but,
since - I thought - I can get the shadow pointer, I just modify the shadow
values then I just call
[layoutManager invalidateGlyphsOnLayoutInvalidationForGlyphRange:range];
So, now I know that doesn't work. But on the other hand if I dismiss
invalidateGlyphsOnLayoutInvalidationForGlyphRange:range
and replace the shadows all the time with removeAttribute: and
addAttribute:, when the user modifies the second shadow on the UI, I lose my
pointer "textShadow" just during the change. In facts the IBOutlets are
bound to the textShadow this way ("selection" is the textView):
oObjsArrayController.selection.textShadow.offsetX
How I fixed the trouble:
I changed scheme and bound the oulets to some brand new textView's
variables, as offsetX, offsetY, offsetBlur and offsetColor. E.g.
oObjsArrayController.selection.offsetX
where "selection" is my textView. Then in the textView I do
- (void)setOffsetX:(CGFloat)value
{
offsetX = value;
NSRange selRange = [self selectedRange];
[self.textStorage removeAttribute:NSShadowAttributeName range:selRange];
MyShadow *newShadow = [[MyShadow alloc] init];
[newShadow setShadowOffset:NSMakeSize(offsetX ,
newShadow.shadowOffset.height)];
[self.textStorage addAttribute:NSShadowAttributeName value:[newShadow
autorelease] range:selRange];
}
I replace the whole shadow even when I zoom the view. A lot of work, just
because that pointer changes.
Anyway that works and I don't get longer that bug. Thank you everybody.
Regards
-- Leonardo
> Da: Ken Thomases <email@hidden>
> Data: Fri, 27 Jun 2014 23:25:33 -0500
> A: Leonardo <email@hidden>
> Cc: <email@hidden>
> Oggetto: Re: MyShadow was deallocated while key value observers...
>
> On Jun 27, 2014, at 3:21 PM, Leonardo wrote:
>
>> While the user moves the selection within an NSTextView, I show on the UI
>> the values of the current textShadow: offsetX, offsetY and blur. In each
>> textField on IB, I bind, e.g.
>>
>> oObjsArrayController.selection.textShadow.offsetX
>>
>> So, in the textView's method textViewDidChangeSelection I do
>> attr = [self.textStorage attributesAtIndex:loc effectiveRange:effRange];
>> self.textShadow = [attr objectForKey:MyShadowAttributeName];
>>
>>
>> textShadow is never retained. It's just a pointer that I set to nil or to
>> the current selected shadow, as above, just to show the current selected
>> shadow values. On the header, it looks
>>
>> @property (nonatomic, assign) MyShadow *textShadow;
>>
>> Sometimes, when I create a new shadow or I release the textView I get this
>> bug:
>>
>> MyShadow was deallocated while key value observers were still registered
>> with it...
>>
>> Why? I can't find a solution to this bug.
>
> Why don't you make the property retain? What harm would it cause?
>
> Anyway, the problem is that the object pointed to by your textShadow property
> can be deallocated while you're still pointing to it (precisely because your
> reference is __unsafe_unretained).
>
> You get told that the attributes have potentially changed after the fact. In
> the case where the text view removed the MyShadowAttribute (perhaps because
> that range of text was deleted), it has presumably been deallocated before the
> call to -textViewDidChangeSelection:.
>
> Since your property hasn't been changed to no longer point to it, the
> key-value observers implicit in the binding have not been told to update their
> observations.
>
> Regards,
> Ken
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden