Level: ★☆☆ Tag: “iOS” “NSString” “Strong and Copy” author: MrLiuQ

In iOS development, you will encounter NSString attribute declarations almost every day. In ARC memory management mechanism, NSString attribute declarations have two keywords to choose from: strong and copy; So the question is, when do you use copy and when do you use strong?

Below I write a small demo, I hope you can understand, but also please pass by the great god advice!

I declared two NSString attributes in the.h file, as follows:

@property(nonatomic, strong) NSString *strongStr; @property(nonatomic, copy) NSString *copyyStr; // Note: names cannot start with alloc, new, copy, mutableCopy, such as copyStrCopy the code

The first scenario: direct assignment with NSString

NSString *originStr1 = [NSString stringWithFormat:@"hello,everyone"]; _strongStr = originStr1; _copyyStr = originStr1; NSLog(@" Scenario 1: Direct assignment with NSString "); NSLog(@" object address object pointer address object value "); NSLog(@"originStr: %p , %p , %@", originStr1, &originStr1, originStr1); NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr); NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);Copy the code

Then we run it and print the result as shown below:

Conclusion: In this case, either objects decorated with strong or copy refer to originStr’s address.


Second scenario: Direct assignment using NSMutableString

NSMutableString *originStr2 = [NSMutableString stringWithFormat:@" Hello,everyone"]; _strongStr = originStr2; _copyyStr = originStr2; [originStr2 setString:@"hello,QiShare"]; NSLog(@" Second scenario: Direct assignment from NSMutableString "); NSLog(@" object address object pointer address object value "); NSLog(@"originStr: %p , %p , %@", originStr2, &originStr2, originStr2); NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr); NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);Copy the code

Then we run it and print the result as shown below:

So if you look at this, you might wonder, why is it that an object, whether it’s a strong object or a copy object, still points to an originStr address? Why does the value of _copyyStr become “hello, QiShare”? Shouldn’t it be “Hello, everyone”? Let’s keep this in suspense and move on.


Third scenario: Assignment using NSMutableString dot syntax

NSMutableString *originStr3 = [NSMutableString stringWithFormat:@" Hello,everyone"]; NSMutableString *originStr3 = [NSMutableString stringWithFormat:@"hello,everyone"]; self.strongStr = originStr3; self.copyyStr = originStr3; [originStr3 setString:@"hello,QiShare"]; NSLog(@" Third scenario: NSMutableString dot syntax assignment "); NSLog(@" object address object pointer address object value "); NSLog(@"originStr: %p , %p , %@", originStr3, &originStr3, originStr3); NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr); NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);Copy the code

Then we run it and print the result as shown below:

OK, now we finally see what we want to see, _copyyStr is still “hello, everyone”, not “hello, QiShare”, and the _copyyStr pointer is no longer the address of _originStr. Careful students will notice that the third type of assignment uses dot syntax instead of direct assignment. In addition to _strongStr = originStr2; Self. strongStr = originStr3; _copyyStr = originStr2; Self. CopyyStr = originStr3; The rest is exactly the same.

In other words, we take _copyyStr = originStr2; Self. CopyyStr = originStr3; That’s why _copyyStr doesn’t change in the third case. Why?

When we declare a property variable with @property, the compiler automatically generates an instance variable named @synthesize copyyStr = _copyyStr, and generates its getter and setter methods. When we assign self.copyystr = originStr, we call the setter method for coppyStr, and when we assign _copyyStr = originStr we assign the _copyyStr instance variable directly, CopyyStr setter methods are not called, and there is a very critical statement in the setter method:

_copyyStr = [copyyStr copy];
Copy the code

Conclusion: In the third scenario, when self. CopyyStr = originStr is assigned, the setter method of copyyStr is called. The setter method makes a subdeep copy of the passed copyyStr and generates a new object assigned to _copyyStr. So _copyyStr no longer points to the same address or object value as originStr.


Fourth scenario: assignment using NSString dot syntax

NSString *originStr4 = [NSString stringWithFormat:@"hello,everyone"]; self.strongStr = originStr4; self.copyyStr = originStr4; NSLog(@" Third scenario: NSMutableString dot syntax assignment "); NSLog(@" object address object pointer address object value "); NSLog(@"originStr: %p , %p , %@", originStr4, &originStr4, originStr4); NSLog(@"strongStr: %p , %p , %@", _strongStr, &_strongStr, _strongStr); NSLog(@" copyyStr: %p , %p , %@", _copyyStr, &_copyyStr, _copyyStr);Copy the code

So we’re going to make _copyyStr = originStr; I changed it to self. CopyyStr = originStr; What would the print look like?

So if you look at the print, you might wonder why I’m using self.copyystr = originStr, calling the setter, calling _copyyStr = [copyyStr copy], Student: Does _copyyName point to the same address as originStr?

Cause: The copy is a shallow copy and does not generate a new object

Conclusion:

It can be concluded from the above example:

  • When the original string is NSString, because it is immutable, both strong and copy are used to refer to the original object, and copy just makes a shallow copy.
  • When the source string is NSMutableString, strong simply increments the reference count of the source string by one, while copy makes a subdeep copy of the original string, creating a new object that points to the new object. Also notice that this copy object is always of type NSString, not NSMutableString, so if you want to copy an object to be mutable, you use mutableCopy. So, using strong only increases the reference count if the source string is NSMutableString. However, copy will perform a deep copy, resulting in unnecessary memory waste. If the original string is NSString, strong and copy are the same, and this problem is not present.

However, when you declare AN NSString, you don’t want it to change, so in general, copy is recommended to avoid NSMutableString errors.

Please pass by and mention assign and weak

As we all know, assign is used to modify base data types, and weak is used to modify OC objects.

Assign can also be assigned to OC objects, but the pointer to assign will not be set to nil after the object is released. This creates a serious problem: wild Pointers. So when I access this wild pointer, it points to the original address, and the original address is nil, so it crashes the program. Weak, however, sets the pointer to nil when the object is released, avoiding wild Pointers.

That raises the question of why primitive data types should be assigned. This brings us to the heap and stack problem, where basic data types are allocated to the stack space, which is automatically allocated and freed by the system, so there is no problem with wild Pointers.

Ps: Demo link of this article

QiShare(Simple book) QiShare(digging gold) QiShare(Zhihu) QiShare(GitHub) QiShare(CocoaChina) QiShare(StackOverflow) QiShare(wechat public account)

Recommended article: iOS UISlider value and sliding linkage