preface

A summary of @property fundamentals


Properties and instance variables

When we write @property NSObject *foo, the compiler does the following things for us (this process is also called “autoSynthesize”)

  • Creating instance variables_foo
  • Declaration of the property foosetter,gettermethods
  • Implements the property foosetter,gettermethods

But back in the days of the GCC compiler, declaring a property took three steps

.h
{
    NSObject *foo;
}
@property NSObject *foo
.m
@synthesize foo;
Copy the code

Foo member variables are created,@property declares setter/getter methods, and @synthesize implements both methods

Then Apple changed the compiler to LLVM, so we didn’t have to declare instance variables for attributes, the compiler automatically created an instance variable that started with an underscore, _foo, and did the @synthesize foo = _foo property for us, This explains why we override setter/getter methods to operate on the _foo instance variable instead of foo. Of course, if you like, you can specify the local variable name by using @synthesize foo = differentFoo instead of using the automatically generated _foo name.

The corresponding to autocomposition is @dynamic, which tells the compiler to cancel the automatic execution of the above three steps. The corresponding action is implemented by the developer himself. The most common is the management class that implements reading and writing to NSUserDefault in the program. The properties of this class do not need to be synthesized automatically by the compiler


@ Property specifies the function of a property

// Write @property (nonatomic, assign) NSInteger testTag; @property (nonatomic, strong) UIButton *btn;Copy the code

Atomicity: atomic&nonatomic

  • This property is set by default through thesetterTo add@synchronized(self)Ensure data dataRead and write security, it needs to be noted, but itNot thread safethe
  • Nonatomic: it’s not locked

The difference between atomic and nonatomic is that the getter/setter methods generated automatically are different. If they write getter/setter, the atomic/nonatomic/retain/assign/copy these keywords prompt role only, write not write all the same

nonatomic

//@property(nonatomic, retain) UITextField *userName; - (UITextField *) userName {return userName; } - (void) setUserName:(UITextField *)userName_ { [userName_ retain]; [userName release]; userName = userName_; }Copy the code

atomic

//@property(retain) UITextField *userName; - (UITextField *) userName {UITextField *retval = nil; @synchronized(self) { retval = [[userName retain] autorelease]; } return retval; } - (void) setUserName:(UITextField *)userName_ { @synchronized(self) { [userName release]; userName = [userName_ retain]; }}Copy the code

Atomic guarantees read and write safety by locking @synchronized(self), and the reference count in the getter is also +1 to assure the caller that the object will always exist. If you don’t, a thread race may occur if another thread calls the setter, causing the reference count to drop to zero and the original object to be released

What’s the Difference between Atomic and Nonatomic?


Read and write permission :readwrite&readonly

  • Readwrite: Readwrite property, default property, allows the compiler@synthesizeAutomatic synthesis
  • Readonly: read-only property, not generatedsetter

Method name definition :getter=/setter=

So if you look at UIButton, it’s usually used for Bool properties, so it’s easy to read

@property(nonatomic,getter=isEnabled) BOOL enabled;                                  // default is YES. if NO, ignores touch events and subclasses may draw differently
@property(nonatomic,getter=isSelected) BOOL selected;                                // default is NO may be used by some subclasses or by application
@property(nonatomic,getter=isHighlighted) BOOL highlighted;  
Copy the code

Memory management

  • assign
  • unsafe_unretained
  • strong
  • retain
  • weak
  • copy
assign

Assign is used for value types, such as int, float, double, NSInteger, and CGFloat. Assign simply overwrites the original value without additional operations

unsafe_unretained

Same as assign, but after the object is destroyed, the property pointer is not equal to nil but points to a piece of wild address, forming a wild pointer. If accessed, BAD_ACCESS appears

strong/retain

Ownership modifier for the ID type and object type. Strong, which was introduced when ARC was introduced in iOS, is an optional alternative to Retain. Indicates that the instance variable has ownership of the passed object, that is, a strong reference. Strong has the same meaning as retain and produces the same code, but strong is more semantically related to the object. So in the setter, retain the new value, release the old value, and return the new value

weak

Use the same range as strong. The difference is that in setter methods, no reference-count increment is performed on the passed object, that is, there is no ownership of the passed object

copy

A copy of the modified result will be saved again. So is often used to modify nsstrings NSArray/NSDictionary property protection encapsulation. Because of polymorphism, the parent class pointer can point to the child class pointer. If a child class is assigned to an immutable attribute, the value of the current attribute will also be affected when the child class is added or deleted, which violates the original intention of immutable and makes the program uncontrollable. Copy is a mutable type that stores the current value and is immutable.

Let’s write a quick example to test the effect of copy on properties:

  1. Declare the two separatelystrongandcopyThe modification type isAn array variableThe properties of the
  2. Declare the two separatelystrongandcopyThe modification type isImmutable arrayThe properties of the
@property (nonatomic, strong) NSMutableArray *smArr;
@property (nonatomic, copy) NSMutableArray *cmArr;
@property (nonatomic, strong) NSArray *strongImArr;
@property (nonatomic, copy) NSArray *CopyImArr;
Copy the code

Then each of them is assigned a local variable of a mutable array, and several properties are printed before and after changing the local variable

// Initialize a local mutable array NSArray *arr = @[@"1"]; NSLog(@"original arr address:%p class:%@",arr,[arr class]); NSArray *carr = [arr copy]; NSLog(@"copy arr address:%p class:%@",carr,[carr class]); NSMutableArray *marr = [arr mutableCopy]; NSLog(@"mutable arr address:%p class:%@",marr,[marr class]); // Assign the mutable array to the declared properties and print the message self.cmArr = marr; NSLog(@"copy mutable property address:%p class:%@ property:%@",self.cmArr,[self.cmArr class],self.cmArr); self.smArr = marr; NSLog(@"strong mutable property address:%p class:%@ property:%@",self.smArr,[self.smArr class],self.smArr); self.strongImArr = marr; NSLog(@"strong immutable property address:%p class:%@ property:%@",self.strongImArr,[self.strongImArr class],self.strongImArr); self.CopyImArr = marr; NSLog(@"copy immutable property address:%p class:%@ property:%@",self.CopyImArr,[self.CopyImArr class],self.CopyImArr); // Change the mutable array and print the message [marr addObject:@"2"]; NSLog(@"copy mutable property address:%p class:%@ property:%@",self.cmArr,[self.cmArr class],self.cmArr); NSLog(@"strong mutable property address:%p class:%@ property:%@",self.smArr,[self.smArr class],self.smArr); NSLog(@"strong immutable property address:%p class:%@ property:%@",self.strongImArr,[self.strongImArr class],self.strongImArr); NSLog(@"copy immutable property address:%p class:%@ property:%@",self.CopyImArr,[self.CopyImArr class],self.CopyImArr);Copy the code

Print the result

original arr address:0x600000017f50 class:__NSSingleObjectArrayI copy arr address:0x600000017f50 class:__NSSingleObjectArrayI mutable arr address:0x60c000250680 class:__NSArrayM copy mutable property address:0x608000201de0 class:__NSSingleObjectArrayI property:( 1 ) strong mutable property address:0x60c000250680 class:__NSArrayM property:( 1 ) strong immutable property address:0x60c000250680 class:__NSArrayM property:( 1 ) copy Immutable property address: 0x608000201DD0 Class :__NSSingleObjectArrayI Property :(1) // Print copies after changing local variables property address:0x608000201de0 class:__NSSingleObjectArrayI property:( 1 ) strong mutable property address:0x60c000250680 class:__NSArrayM property:( 1, 2 ) strong immutable property address:0x60c000250680 class:__NSArrayM property:( 1, 2 ) copy immutable property address:0x608000201dd0 class:__NSSingleObjectArrayI property:( 1 )Copy the code

As you can see, copy changes the type of self.cmArr from a mutable array to __NSSingleObjectArrayI, and the compiler creates a new memory space to store the value of copy. So when we write something like @property (nonatomic, copy) NSMutableArray *foo, we need to think about whether this declaration makes sense.

It is also interesting to note that self.strongImArr, which we declared as an immutable array, points to a mutable array because of polymorphism (a parent pointer points to a subclass) and changes when marr changes. This may not be what the developer intended when they declared it immutable, and it may be closer to what the developer really wanted than if the last line was printed. So this is a lot of articles advocating nsstrings with copy/NSArray NSDictionary properties of intention.


After getting to know @property, we will continue to explore @Property in iOS and learn more basic knowledge of @property

Blog address: iOS- Meet @property