Copying NSTextStorage

  • This used to work.  No more.  Has something changed in NSTextStorage?

        In my Shape object, I have a dictionary of parameters, one being key =
    "text" with value NSTextStorage*, similar to what is done in Sketch (without
    the dictionary).  My copyWithZone duplicated the dictionary and called
    "copy" for each value.  My "Duplicate" method simply used "[shape copy]" and
    used to work.  Now the only way I can get it to work is to intercept the
    "text" key in Shape's copyWithZoneand and create a newly initialized
    NSTextStorage object.

        Apparently, NSTextStorage does not conform to NSCopying, even though its
    superclass (NSAttributedString) does.  Has something changed recently with
    NSTextStorage that makes "copy" not work?
  • On 29 May '08, at 11:03 AM, Gordon Apple wrote:

    > Apparently, NSTextStorage does not conform to NSCopying, even
    > though its
    > superclass (NSAttributedString) does.  Has something changed
    > recently with
    > NSTextStorage that makes "copy" not work?

    Is there a reason you need to use NSTextStorage instead of
    NSAttributedString? Generally the only place NSTextStorage is used is
    in the innards of NSTextViews.

    I'm not sure what -copy would do with an NSTextStorage, since it
    inherits from NSMutableAttributedString, and copying an
    NSMutableAttributedString returns an NSAttributedString. In other
    words, copying mutable objects returns immutable ones. Have you tried
    using -mutableCopy instead?

    —Jens
  • Yes, I did try mutable copy (which still required intercepting the
    "text" key when copying the shape).  It didn't help.

        I inserted some test code to try to figure out why it was crashing my
    program.  The NSTextStorage, when copied, would blow up when asking for
    layoutManagers.  (I was trying to see if it had one by default.)  So
    something is not getting initialized in the copy.

        Why NSTextStorage?  Because that is what Sketch uses, and I lifted as
    much code from there as I could, although I use my own Bezier text container
    when rendering it.  The floating NSTextView uses it directly.  I suppose I
    could change it to store NSMutableAttributedString and create the
    NSTextStorage on-the-fly when rendering (and for the floating edit view).

        Anyway, like I said, creating a new NSTextStorage, initialized with the
    old storage, seems to have solved that problem, although I don't understand
    why the problem just surfaced now.

    >
    > On 29 May '08, at 11:03 AM, Gordon Apple wrote:
    >
    >> Apparently, NSTextStorage does not conform to NSCopying, even
    >> though its
    >> superclass (NSAttributedString) does.  Has something changed
    >> recently with
    >> NSTextStorage that makes "copy" not work?
    >
    > Is there a reason you need to use NSTextStorage instead of
    > NSAttributedString? Generally the only place NSTextStorage is used is
    > in the innards of NSTextViews.
    >
    > I'm not sure what -copy would do with an NSTextStorage, since it
    > inherits from NSMutableAttributedString, and copying an
    > NSMutableAttributedString returns an NSAttributedString. In other
    > words, copying mutable objects returns immutable ones. Have you tried
    > using -mutableCopy instead?
    >
    > ‹Jens
  • On Fri, May 30, 2008 at 11:13 AM, Gordon Apple <ga...> wrote:
    > Why NSTextStorage?  Because that is what Sketch uses, and I lifted as
    > much code from there as I could, although I use my own Bezier text container
    > when rendering it.  The floating NSTextView uses it directly.  I suppose I
    > could change it to store NSMutableAttributedString and create the
    > NSTextStorage on-the-fly when rendering (and for the floating edit view).

    IIRC, NSTextStorage is actually just a front for a private subclass of
    NSMutableAttributedString.  For all I know they could actually be the
    same thing -- certainly wouldn't surprise me.

    --Kyle Sluder
  • New attempt.  Instead of intercepting the "text" key in my shape
    CopyWithZone, I tried the obvious thing of subclassing NSTextStorage, adding
    the copying/mutablecopying protocols using the same copy technique of
    creating a new object initialized with the original.  Even without the
    protocols, this simply did not work. It wouldn't allow me to edit text at
    all.  Without even trying to make a copy, apparently NSTextView will accept
    nothing but the original NSTextStorage -- no subclasses allowed, even
    without any overrides.
  • On May 31, 2008, at 7:49 PM, Gordon Apple wrote:

    > apparently NSTextView will accept
    > nothing but the original NSTextStorage -- no subclasses allowed, even
    > without any overrides.

    Nope. To subclass NSTextStorage, see http://www.cocoabuilder.com/archive/message/cocoa/2002/2/5/14848
  • I tried exactly that.  It did nothing but a horrendous crash when I
    tried to type text.  I couldn't even trace it.  I never even got to the copy
    part.  I got the same result with a totally empty subclass. Shouldn't it
    have worked the same?s What gives with that?

    > On May 31, 2008, at 7:49 PM, Gordon Apple wrote:
    >
    >> apparently NSTextView will accept
    >> nothing but the original NSTextStorage -- no subclasses allowed, even
    >> without any overrides.
    >
    > Nope. To subclass NSTextStorage, see
    > http://www.cocoabuilder.com/archive/message/cocoa/2002/2/5/14848
  • On Tue, Jun 3, 2008 at 11:15 AM, Gordon Apple <ga...> wrote:
    > I tried exactly that.  It did nothing but a horrendous crash when I
    > tried to type text.  I couldn't even trace it.  I never even got to the copy
    > part.  I got the same result with a totally empty subclass. Shouldn't it
    > have worked the same?s What gives with that?

    It might have something to do with the fact that, according to the
    documentation, NSTextStorage is a "semiconcrete subclass of
    NSMutableAttributedString."  What confuses me about this is that the
    words "concrete" and "abstract" have very well-defined meanings...
    "semiconcrete" is bizarre and meaningless.  Doesn't that just mean
    it's abstract?

    --Kyle Sluder
  • On Jun 3, 2008, at 12:51 PM, Kyle Sluder wrote:

    > On Tue, Jun 3, 2008 at 11:15 AM, Gordon Apple <ga...> wrote:
    >> I tried exactly that.  It did nothing but a horrendous crash when I
    >> tried to type text.  I couldn't even trace it.  I never even got to
    >> the copy
    >> part.  I got the same result with a totally empty subclass.
    >> Shouldn't it
    >> have worked the same?s What gives with that?
    >
    > It might have something to do with the fact that, according to the
    > documentation, NSTextStorage is a "semiconcrete subclass of
    > NSMutableAttributedString."  What confuses me about this is that the
    > words "concrete" and "abstract" have very well-defined meanings...
    > "semiconcrete" is bizarre and meaningless.  Doesn't that just mean
    > it's abstract?
    >
    > --Kyle Sluder

    Gordon, if I understand correctly, the situation is this: you have
    created a class Shape that contains an NSDictionary object. You are
    using an instance of NSTextStorage as the object for the key "text".
    You need to copy the dictionary.

    First I will echo what Jens has said: there's a strong probability
    that NSAttributedString or NSMutableAttributedString will do what
    need. NSTextStorage adds two capabilities to
    NSMutableAttributedString: it communicates with one or more
    NSLayoutManagers that are involved in laying out the attributed string
    in one or more NSTextContainers, and it supports some scripting
    commands. If the NSTextStorage object resident in your dictionary has
    never had a layout manager added to it, and is not supporting
    scripting, then it's likely going about just acting like a
    NSMutableAttributedString, without doing any NSTextStorage tricks at
    all.

    As you say, Sketch uses a NSTextStorage object. It's in the SKTText
    class, which supports scripting, so it makes sense to use an
    NSTextStorage object. But "copy" or "mutableCopy" are never sent to
    that object. The copy withZone: method says:

    [[copy contents] setAttributedString:[self contents]];

    [copy contents] causes copy to init a new NSTextStorage object, and
    setAttributedString: is used to copy the text from the source. So you
    see that Sketch "copies" an NSTextStorage object by creating a new
    object and calling setAttributedString:. That's how you should copy
    your NSTextStorage, too, IMHO.

    The notion of copying an NSTextStorage object does not make much sense
    to me. A happy working NSTextStorage object is busy updating
    NSLayoutManager objects and sending notifications. If you were to copy
    it, would you want the copy to inherit those NSLayoutManager
    references, too? That would definitely muck things up, because a
    layout manager is emphatically monogamous: it wants one and only text
    storage. If you didn't want the copy to inherit the layout manager
    references, then you might as well just copy the text storage's
    attributedString. That's why I say that the notion of copying does not
    really apply to NSTextStorage.

    Kyle, AFAICT, NSTextStorage is the only Cocoa class deemed
    "semiconcrete." I guess it means that you can instantiate
    NSTextStorage objects as if they were concrete, but you can't subclass
    them without special effort. Maybe a documentation bug would be in
    order.

    Ross
  • On Tue, Jun 3, 2008 at 2:19 PM, Ross Carter <rosscarter...> wrote:
    > Kyle, AFAICT, NSTextStorage is the only Cocoa class deemed "semiconcrete." I
    > guess it means that you can instantiate NSTextStorage objects as if they
    > were concrete, but you can't subclass them without special effort. Maybe a
    > documentation bug would be in order.

    I filed one simultaneously with my bickering.  ;-)

    --Kyle Sluder
  • On 3 Jun 2008, at 19:19, Ross Carter wrote:

    > First I will echo what Jens has said: there's a strong probability
    > that NSAttributedString or NSMutableAttributedString will do what
    > need. NSTextStorage adds two capabilities to
    > NSMutableAttributedString: it communicates with one or more
    > NSLayoutManagers that are involved in laying out the attributed
    > string in one or more NSTextContainers, and it supports some
    > scripting commands.

    I think it also uses a different internal representation (probably a
    gap buffer) so that it can efficiently support editing.  My guess is
    that NSTextStorage is therefore a somewhat more expensive object to
    throw around than an NS[Mutable]AttributedString, but that it will be
    more efficient if e.g. you want to write a text editor.

    > The notion of copying an NSTextStorage object does not make much
    > sense to me.

    Well I think it does make sense in that I don't see why you
    *shouldn't* be able to copy one.  That's not to say that I think it's
    something that most applications would do on a regular basis though.

    Kind regards,

    Alastair.

    --
    http://alastairs-place.net
  • On Tue, Jun 3, 2008 at 12:51 PM, Kyle Sluder
    <kyle.sluder+<cocoa-dev...> wrote:
    > On Tue, Jun 3, 2008 at 11:15 AM, Gordon Apple <ga...> wrote:
    >> I tried exactly that.  It did nothing but a horrendous crash when I
    >> tried to type text.  I couldn't even trace it.  I never even got to the copy
    >> part.  I got the same result with a totally empty subclass. Shouldn't it
    >> have worked the same?s What gives with that?
    >
    > It might have something to do with the fact that, according to the
    > documentation, NSTextStorage is a "semiconcrete subclass of
    > NSMutableAttributedString."  What confuses me about this is that the
    > words "concrete" and "abstract" have very well-defined meanings...
    > "semiconcrete" is bizarre and meaningless.  Doesn't that just mean
    > it's abstract?

    I interpret it as meaning that NSTextStorage is concrete in the sense
    that you can instantiate it directly. But, you can't inherit its
    implementations of NSMutableAtributedString's primitive methods; so,
    when subclassing NSTextStorage it's considered an abstract superclass
    that requires you to implement the primitive methods.

    sherm--

    --
    Cocoa programming in Perl: http://camelbones.sourceforge.net
previous month may 2008 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