@property copy semantics explanation

Discussion in 'iOS Programming' started by daproject, Jun 6, 2013.

  1. daproject macrumors newbie

    Joined:
    May 29, 2013
    #1
    Hi Forum,

    I am not really understanding why it is good practice to use the copy semantic for use with properties whom classes have mutable and immutable types. I have read so many explanations, but for some reason I do not understand it. So I'm going to try to take a crack at it and if anyone can please tell me if I got it right.

    Lets take the following
    Code:
    @property (nonatomic, strong) NSString *str;
    and in a method we have:
    Code:
    NSMutableString *mutStr = [NSMutableString stringWithString:@"hello"];
    obj.str = mutStr;
    [mutStr appendString:@"there"];
    because both str and mutStr now both point to the same address lets say 0x01 due to the assignment operator, when we change the mutable string the immutable one uncontrollably will change. When we replace strong with copy when the setter is called the object is created but str will have address 0x02.

    Now this wont be anything to worry about in a program that DOES NOT have any MUTABLE strings

    did i get that right?
     
  2. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    Half right. You don't create all the strings in your app. System code creates strings that your app gets and uses. Third party code in any non-trivial app creates strings that your app gets and uses. You can't prove there are no mutable strings in your app.

    I assume the reason you're thinking this is for efficiency. Remember that for an immutable object a copy is a retain.

    Doing things right the first time saves you time later.

    Let's say there are two software developers. One of them decides not to wear underwear one day because he's not planning on riding in a car that day so he can't get in an accident and go to the hospital where they can see he doesn't wear underwear. The other one wears underwear every day regardless of whether he's planning on riding in a car that day. Lets say they get a phone call that there's a bug that needs to be fixed at work ASAP so they have to drive to work immediately or they'll lose their job. Let's say they get into a car accident on the way and have to go to the hospital. Which one of those developers do you want to be?

    Use the copy annotation on your @properties.
     
  3. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #3

    You are pretty close. However, this part isn't quite right: "...when we change the mutable string the immutable one uncontrollably will change."

    In the example above, there is only one string.

    The line


    Code:
    obj.str = mutStr;
    
    Tells obj to POINT TO mutStr. (Any time you need a string, look at this address and use the object you find there.) There is no immutable string to go along with the mutable string. There is only one string, and it can be changed. When it does change, everybody that reads the string sees the changes.

    Imagine you work at a newspaper, and you tell the guy in charge of setting the headlines to take whatever is on your whiteboard and use that as the headlines. You write down today's headlines and yell "headlines up!". You assume the copy setter has already done his job, so you make some playful changes to the headlines for the benefit of your coworkers. However, the copy setter did not make a copy of the headlines you wrote, he actually set the type using the words on your whiteboard, after you changed them.

    This is not an issue with immutable strings. With an immutable string, it never changes. It's like etching it on a stone tablet. If you need to change an immutable string, you have to throw it away and create another one.

    When you add the copy qualifier to a property, you tell the runtime to watch out for mutable strings.

    If you assign a mutable string to a copy property, the runtime makes an immutable copy of the string and keeps that, instead of just pointing ot the string you pass in.

    However, if you pass in an immutable string, the runtime is smart enough to notice the difference, and in that case it just retains the string object.

    (With ARC retains and releases still happen, but behind the scenes.) So when you pass in an immutable string, a copy property acts exactly the same as a strong (or retain for non-ARC projects) property.
     
  4. daproject thread starter macrumors newbie

    Joined:
    May 29, 2013
    #4
    Duncan, you mentioned there is only 1 string in my example, however isn't obj.str a string? since its a property of a class whom we made an obj of callled OBJ
     
  5. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #5
    That's the whole point. In Objective C an object variable is a pointer, not an object:

    Code:
    @interface SomeObject:
    
    @property (strong) NSString *str;
    @end
    
    The property str is a POINTER TO A STRING. It is not a string object. It starts out as nil (pointer to nothing.)

    When you say:

    Code:
    NSString *someString = @"foo";
    
    obj.str = someString;
    If the str property is not a copy property, then the obj.str assignment causes the SomeObject's str pointer to POINT TO the string @"foo" that was created above.

    str is not a string, it is a pointer to a string. The local variable someString from the line above is a second pointer to the same, single string object.

    If the code is


    Code:
    NSString *someString = @"foo";
    
    obj1.str = someString;
    obj2.str = someString;
    obj3.str = someString;
    obj4.str = someString;
    obj5.str = someString;
    
    then after it executes, someString, obj1.str, obj2.str, obj3.str, obj4.str, and obj5.str are all different pointers that point to the same, single string object. There is only one string object @"foo".


    If your code was like this:

    Code:
    NSMutableString *someString = [NSMutableString stringWithString: @"foo"];
    
    obj1.str = someString;
    obj2.str = someString;
    obj3.str = someString;
    obj4.str = someString;
    obj5.str = someString;
    
    [someString appendString: @"bar";
    
    Then, since the local variable and all 5 objects point to the same string object, all will see the new string value "foobar".

    ----------

    If, instead, you declared your class like this:

    Code:
    @interface SomeObject:
    
    @property (copy) NSString *str;
    @end
    
    And you ran the same code on a bunch of SomeObjects:

    Code:
    NSMutableString *someString = [NSMutableString stringWithString: @"foo"];
    
    obj1.str = someString;
    obj2.str = someString;
    obj3.str = someString;
    obj4.str = someString;
    obj5.str = someString;
    
    [someString appendString: @"bar";
    
    The runtime would create a new, immutable copy of the string for each assignment.

    The setter for a copy property looks something like this:

    Code:
    - (void) setStr: (NSString *newString);
    {
      _str = [newString copy];
    }
    


     

Share This Page