This “iOS fish Weekly 19th issue” interview analysis module explains the knowledge point is OC attribute and attribute keywords, so the author made a summary of OC attribute and attribute keywords, most of the content is extracted from the past blog, add some new understanding and experience summary.

At sign property, at sign synthesize, and at sign dynamic

@property

Attribute is used to encapsulate the data in the object. The essence of attribute is IVAR + setter + getter.

Properties can be declared using the @property syntax. @property will help us automatically generate declarations of setter and getter methods for the property.

@synthesize

Help us automatically generate implementations of setter and getter methods and _ivar.

You can also specify instance variable names at @synthesize, if you don’t like the default instance variable names that start with an underscore. However, it is best to use the default, otherwise it will affect readability.

If you don’t want the compiler to synthesize access methods, you can implement them yourself. If you only implement one of the access setters or getters, the other one will still be synthesized by the compiler. But it’s important to note that if you implement all the methods you need for a property (setter and getter if it’s readwrite, getter if it’s readonly), then the compiler doesn’t automatically synthesize at sign, At this point, the instance variable of the property is not generated, so you need to manually @synthesize it according to the actual situation.

@synthesize ivar = _ivar;
Copy the code

@dynamic

Tell the compiler that instead of automatically doing the @synthesize, you’ll provide the implementation of these methods at run time, without warning, but it doesn’t affect the declaration of the setter and getter methods that @property generates. @dynamic is an expression of OC as a dynamic runtime language. Dynamic runtime languages differ from compile-time languages: dynamic runtime languages defer function decisions to runtime, while compile-time languages make function decisions at the compiler.

@dynamic ivar;
Copy the code

Before, we had to manually add the @synthesize to each @property. After iOS 6, the LLVM compiler introduced property autosynthesis. In other words, the compiler automatically adds the at sign synthesize to every at sign property.

Then you might ask, what does @synthesize do now?

  1. If we override both setter and getter methods, then the compiler won’t automatically add the @synthesize to this @property, so there’s no _ivar, so we need to manually add the @synthesize;
  2. If the property is readonly, then as long as you override the getter,property autosynthesisIt’s not going to execute, and again, you have to manually put in the at sign synthesize if you want to, depending on whether you want to define this property as a store property or a compute property;
  3. Implement the properties required in the protocol.

Also note that the properties added to the classification will not be property autosynthesis. Because the memory layout of a class is determined at compile time, but classes are loaded at run time and the data is merged into the host class, member variables cannot be added to a class, and the effect of member variables can only be achieved indirectly by associating objects. If you add a property to a class and don’t manually implement getters and setters for it (you don’t need to if the property is readonly), Property ‘ivar’ requires method ‘ivar’, ‘setIvar:’ to be defined – use @dynamic or provide a method So implementation in this category, the compiler already tells us that there are two ways to get rid of warnings:

  1. Provide implementations of getter and setter methods for this property in this class
  2. Using @dynamic to tell the compiler that the implementation of getter and setter methods comes naturally at runtime, so you don’t have to worry about it. Of course, @dynamic just removes the warning here, and if you don’t add the method implementation dynamically at runtime, the access method that calls this property will Crash.

Attribute modifier classification

classification Attribute keyword
atomic Atomic, nonatomic
Read and write access Readwrite, readonly
The method name Setter and getter
Memory management Assign, weak, unsafe_unretained, retain, strong, and copy
Nullable sex (_Nullable, __nullable),

Nonnull, _Nonnull, __nonnull),

(NULl_unspecified, _Null_unspecified, and __NULl_unspecified),

null_resettable
Class attribute class

atomic

Attribute keyword usage
atomic Atomicity (default), the compiler automatically generates mutex (previously spinlocks, but later mutexes), and locks setter and getter methods to ensure thread-safe assignment of properties and atomic operations on values, but not operations and access.

For example, if an atomic modifier is an array, assigning and evaluating the array is thread-safe. However, if we operate on an array, such as adding or removing objects from the array, it is not atomic’s responsibility, so adding or removing objects from an atomic array is not thread-safe.
nonatomic Nonatomic, general properties are modified with nonatomic because atomic takes time.

Read and write access

Attribute keyword usage
readwrite Readable and writable (default), generating declarations and implementations of both setter and getter methods.
readonly Read-only, only generates the declaration and implementation of getter methods. For encapsulation purposes, we should expose attributes only when necessary, and try to set the exposed attributes to ReadOnly. If you want to modify the property inside the object using setters, you can redeclare the property as readwrite in the class extension. You do not need to redeclare it as readwrite if you only modify it internally with _ivar.

The method name

Attribute keyword usage
setter You can specify the generated setter method name, such as setter = setName. This keyword is often used when adding attributes to a class. To avoid the problem of “overwriting” a host class (or other class) method with the same name, we usually prefix the method, such as bb_ivar, but the generated setter name is not beautiful (setBb_ivar). So you use the setter keyword@property (nonatomic, strong, setter = bb_setIvar:) NSObject *bb_ivar;
getter You can specify the generated getter method name, such as getter = getName. Example:@property (nonatomic, assign, getter = isEnabled) BOOL enabled;

Memory management

Attribute keyword usage
assign 1. You can modify both basic data types and object types;

2. The implementation of setter methods is direct assignment, generally used for basic data types;

Modify basic data types, such as NSInteger, BOOL, int, float, etc.

4. Modify the object type without increasing its reference count.

Overhang pointer: After the assigned object is released, the pointer will still point to the original address of the assign object. The overhang pointer will become the overhang pointer. Continuing to access the original object through this pointer may cause the program to crash.
weak 1. Only object types can be modified.

2. It can only be used in ARC mode.

3. Modify weak references, do not increase the object reference count, mainly used to avoid circular references;

4. After the weak modified object is released, the pointer is automatically set to nil and no dangling pointer is generated;

5. For views, usually xiB and storyboard; You can also use weak in your code for views that need to be removed, so remove is automatically set to nil afterwards.
unsafe_unretained 1. You can modify both basic data types and object types;

2. It is often used under MRC, but rarely used under ARC;

3. The same as weak, the difference lies in that unsafe_unretained leads to dangling Pointers.

4. Weak has a certain consumption on performance. When an object is dealloc, it needs to traverse the weak table of the object and set the values of all the weak pointer variables in the table to nil. So unsafe_unretained is faster than weak. Selecting unsafe_unretained provides some performance improvement when you clearly know the life cycle of the object. For example, A holds object B, and B is destroyed when A is destroyed. So when B exists, A must exist. If B needs to call A’s interface again, B can store the unsafe_unretained pointer of A. The performance improvement is tiny, though. But as you know, “unsafe_unretained” is also safe, so it can be retained quickly. When the situation is uncertain, weak should be preferred. “For example, the author encapsulates a DisplayLink class, uses the NSProxy intermediate variable internally to better avoid circular references, sets the target of DisplayLink to proxy, and the proxy needs to call the DisplayLink API. To avoid cyclic references to the proxy, you need to weakly reference the displayLink, because when the displayLink exists, the proxy exists, the displayLink destroys the proxy, So proxy can store the unsafe_unretained pointer of displayLink.”
retain 1. In MRC, strong is used in ARC;

2. Modify the strong reference, the original pointer to the old object, then point to the new object, and increase the reference count of the new object by 1;

3. The implementation of the setter method is to release the old value and retain the new value for the OC object type.
strong 1. It can only be used under ARC.

2. Same principle as retain;

3. But when modifying blocks, strong equals copy and retain equals assign.
copy The implementation of setter methods is to release the old value and copy the new value, which is commonly used for blocks, NSString, NSArray, NSDictionary, etc. Using copy or strong to modify a block is the same as using MRC. NSString, NSArray, and NSDictionary are used to ensure that the assigned value is an immutable object, so as not to cause unexpected results due to external modification.

Nullable sex

Nullability and Objective-C

Annotations, a new Objective-C feature introduced by Apple in Xcode 6.3, are called Nullability Annotations. These keywords can be used in properties, method return values, and parameters to specify the nullability of an object so that code will be intelligently prompted. Can be used in Swift? And! To say is an object optional or non-optional, like UIView? And UIView!!! . In Objective-C, we don’t have that distinction, UIView can say this object is optional or it can say non-Optioanl. This creates a problem: When Swift mixes with Objective-C, the Swift compiler doesn’t know whether an Objective-C object is optional or non-optional, So in this case the compiler implicitly treats objective-C objects as non-optional. Nullability Annotations are introduced to allow iOS programmers to smoothly transition from Objective-C to Swift on the one hand, and to encourage developers to be more standardized when writing Objective-C code to reduce communication costs between colleagues.

The __nullable and __nonnull keywords were released by Apple in Xcode 6.3. Due to potential conflicts with third-party libraries, Apple changed them to _Nullable and _Nonnull in Xcode 7. However, in order to be compatible with Xcode 6.3, Apple predefined the __nullable and __nonnull macros to extend to the new name. Apple also supports nullable and nonNULL without underscores, which differ depending on where they are placed.

Note: This type of keyword only provides warnings and does not generate compilation errors. Can only be used to declare object types, not basic data types.

Attribute keyword usage
Nullable, _Nullable, and __nullable Objects can be empty, depending on where they are placed
Nonnull, _Nonnull, __nonNULL Objects cannot be empty. The difference is where they are placed
Null_unspecified, _Null_unspecified, and __NULl_Unspecified Nullable is not specified. The difference is where it is placed
null_resettable 1. Getter methods cannot return null, setter methods can return null;

2. You must override setter or getter methods for non-null processing. Otherwise a warning will be reportedSynthesized setter 'setName:' for null_resettable property 'name' does not handle nil

Use effect

@interface AAPLList : NSObject <NSCoding.NSCopying>
// ...
- (AAPLListItem * _Nullable)itemWithName:(NSString * _Nonnull)name;
@property (copy.readonly) NSArray * _Nonnull allItems;
// ...
@end

// --------------

[self.list itemWithName:nil]; // warning!
Copy the code

Audited Regions: Nonnull Zone Settings

It would be tedious to specify nonNULL and nullable for every attribute or method. To ease our workload, Apple provides two macros: NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END. In the code between the two macros, all simple pointer types are assumed to be nonNULL, so we only need to specify those nullable pointer types. Example code is as follows:

NS_ASSUME_NONNULL_BEGIN
@interface AAPLList : NSObject <NSCoding.NSCopying>
// ...
- (nullable AAPLListItem *)itemWithName:(NSString *)name;
- (NSInteger)indexOfItem:(AAPLListItem *)item;

@property (copy.nullable) NSString *name;
@property (copy.readonly) NSArray *allItems;
// ...
@end
NS_ASSUME_NONNULL_END

// --------------

self.list.name = nil;   // okay

AAPLListItem *matchingItem = [self.list itemWithName:nil];  // warning!
Copy the code

Some experience summary of the author

  • Using good nullability keywords allows objective-C developers to make a smooth transition to Swift without tripping over Swift optional types.
  • Using good nullability keywords can make code more formal, such as you should not assign a property specified as nonNULL to nil.
  • NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_ENDIt’s just a macro that Apple provides to ease our workload, rather than allowing us to ignore the nullability keyword.
  • If you don’t specify property/method arguments as nullable, you’ll get annoying warnings when assigning/passing nil to that property.
  • When you’re mixing, if you don’t specify nullable for a nullable property, you can’t do an optional chain call, because Swift will treat it as a non-optional type, and you can’t force unpack because it might be nil, so you have to add a layer of protection.

Class attribute class

Attributes can be divided into instance attributes and class attributes:

  • Instance attributes: Each instance has its own set of attribute values, which were previously independent of each other;
  • Class attributes: You can define attributes for the class itself. No matter how many instances of the type are created, these attributes are unique because the class is a singleton.

Instance attributes are associated with instance, and class attributes are associated with class.

Usefulness: Class attributes are used to define data shared by all instances of a type, such as a constant/variable that all instances can use (like static constants/variables in C).

Class attributes are defined by adding the class keyword to the attributes.

@property (class, nonatimoc, strong) NSObject *object;
Copy the code

Class attributes don’t have property autosynthesis, so how do you associate values?

  • If it’s a storage property
    1. Define a static global variable in.m and then operate on it in setter and getter methods.
    2. Use associated objects in setter and getter methods to store values. One usage scenario I encountered earlier was when classes were created dynamically through the Runtime, so there was no way to use static global variables to store values. So I define a class attribute in the parent class and use the associated object to store the value so that dynamically created subclasses can associate the value to their class attribute.
  • If you’re evaluating properties, you just implement setter and getter methods.

Other supplementary

When setting an instance variable for a property, be sure to follow the semantics declared for the property:

@property (nonatomic.copy) NSString *name;

— (instancetype)initWithName:(NSString *)name {
    if (self = [super init]) {
        _name = [name copy];
    }
    return self;
}
Copy the code

If you implement the access method yourself, you should also ensure that it has the properties declared by the related properties.