Q&A

1. What is the difference between the weak keyword and assign?

When is the weak keyword used?

In ARC, when a circular reference is possible, it is usually resolved by having one end use weak, such as the delegate delegate attribute

It has already been strongly referenced once by itself, so there is no need to strongly reference it again. In this case, weak is also used. Custom IBOutlet control properties usually use weak as well.

Of course, you can also use strong. Why can view attributes connected to IBOutlet be set to weak?

Difference:

Weak Indicates that this attribute defines a nonowning relationship. When you set a new value for this property, the setting method neither preserves the new value nor frees the old value. This property is similar to assign, except that the value of the attribute is nil out when the object to which it refers is destroyed.

The Assign “Setup methods” will only perform simple assignments for “scalar types” (e.g. CGFloat or NSlnteger, etc.).

Assign can be used with non-OC objects, while weak must be used with OC objects

2. How do I make my class use the copy modifier? How do I override a setter with the copy keyword?

If you want to copy your own objects, you need to implement the NSCopying protocol.

NSCopying and NSMutableCopying protocols are implemented simultaneously if the custom object is of mutable and immutable versions.

Procedure: Declare that the class complies with the NSCopying protocol

Implement the NSCopying protocol. The protocol has only one method:

- (id)copyWithZone:(NSZone *)zone;
Copy the code

Note: When it comes to having your class use the copy modifier, we tend to overwrite the copy method when what we really need to implement is the “copyWithZone” method.

Override setters with copy, for example:

- (void)setName:(NSString *)name {
    //[_name release];
    _name = [name copy];
}
Copy the code

3. What are deep and shallow copies?

A shallow copy is a copy of a pointer. After a copy, the two Pointers point to the same memory space. A deep copy is a copy of both Pointers and the content that the Pointers point to. In addition to the need to consider a custom copy constructor when copying an object when there are pointer members in the object, the following two situations should be considered:

  • When the argument is an object, the argument passed to the parameter is actually a copy object of the argument. The system automatically implements this by copying the constructor.

  • When the return value of a function is an object, the object is actually a copy of the object within the function, which is used to return the function call.

Copy method: shallow copy if non-extensible class object. If it is an extensible class object, it is a deep copy.

MutableCopy method: Both extensible and non-extensible class objects are deep copies.

What is the essence of 4.@property? How are ivar, getters, and setters generated and added to this class?

The essence of @property is instance variable (IVar) + access method (getter + setter), that is, @property = IVar + getter + setter;

Properties, as a feature of Objective-C, encapsulate data in objects. Objective-c objects typically store the data they need as various instance variables.

Instance variables are typically accessed through an “access method.” Getters are used to read variable values, and setters are used to write variable values.

Ivar, getters, and setters are automatically synthesized in this class

Once the attributes are defined, the compiler automatically writes the methods needed to access them, a process called autosynthesis.

It is important to note that this process is implemented by the compiler at compile time, so the source code for these synthesized methods is not available in the editor.

In addition to generating getters and setters for the method code, the compiler automatically adds instance variables of the appropriate type to the class and precedes the attribute names with an underscore as the name of the instance variable.

In the previous example, two instance variables are generated with names _firstName and _lastName. You can also specify the name of an instance variable in the class implementation code by using the @synthesize syntax.

How do you use @property in 5.@protocol and category

  • Using property in protocol only generates setter and getter method declarations, and we use properties in the hope that objects that comply with our protocol will implement the property

  • Using @property for a category is also a declaration that only generates setter and getter methods. If we really need to add property implementations to a category, we need to use two functions at runtime: Objc_setAssociatedObject and objc_getAssociatedObject

6. What should I pay attention to when using CADisplayLink and NSTimer? When does BAD_ACCESS occur?

1. What should I pay attention to when using CADisplayLink and NSTimer? CADisplayLink and NSTimer will cause circular references. You can use YYWeakProxy or add block methods for CADisplayLink and NSTimer to solve circular references

2. When does BAD_ACCESS appear? Access dangling Pointers, such as releasing an object that has been freed, accessing a member variable of a freed object, or sending a message. Infinite loop

7. IOS memory partitions

  • Stack area

The stack, which is automatically allocated by the compiler to hold parameters of a function, values of local variables, etc., is a data structure that extends to a lower address. It is a continuous area of memory

  • Heap area

Allocated free by the programmer is a data structure that extends to a high address and is a discontinuous area of memory

  • The global area

Global variables and static variables are stored together. Initialized global variables and static variables are stored in one area. Uninitialized global variables and uninitialized static variables are released by the system after the program ends in another area adjacent to the system

  • The constant area

The constant string is put here and released by the system after the program ends

  • Code section

The binary code that holds the function body

ps:

  • In iOS, memory in the heap is shared by applications, and memory allocation in the heap is the responsibility of the system
  • The system uses a linked list to maintain all allocated memory space (the system only records, not manages the details)
  • After the variable is used, the memory needs to be released. In the OC, it is determined whether the reference count is 0. If so, it means that no variable is using the space, and the system will reclaim it
  • When an app starts, the size of the code area, constant area, and global area are fixed, so Pointers to these areas do not generate crash errors. The heap area and stack area are constantly changing (heap creation and destruction, stack in and out), so when using a pointer to this area of memory, be careful whether the memory has been freed, otherwise it will cause program crash (i.e., the wild pointer error).

8. IOS memory management mode

  • Tagged Pointer (small object)

Tagged Pointer is used to store small objects, such as NSNumber and NSDate

The Tagged Pointer value is no longer an address, but a real value. So, it’s not really an object anymore, it’s just a normal variable in an object’s skin. Therefore, its memory is not stored in the heap and does not require malloc and free

Three times more efficient at memory reads and 106 times faster at creation

Objc_msgSend can recognize Tagged Pointer, such as the intValue method of NSNumber, and extract data directly from the Pointer

After using Tagged Pointer, the Data stored in the Pointer becomes Tag + Data, that is, the Data is stored directly in the Pointer

  • NONPOINTER_ISA (a pointer that holds information related to the object’s memory) Apple has designed ISA to be a federation, storing some of the information related to the object’s memory in ISA, because, as mentioned above, not all 64 bits are required to store Pointers.

Isa structure:

// struct {uintptr_t nonpointer: 1; // uintptr_t has_assoc: 1; Uintptr_t has_cxx_dtor: 1; // Uintptr_t shiftcls: 44; Uintptr_t magic: 6; // Uintptr_t magic: 6; Uintptr_t Weakly_referenced: 1; // Whether the locating is weakly referenced to the uintptr_t deallocating: 1; // Whether the object is releasing the uintptr_t has_sidetable_rc: 1; Uintptr_t extra_rc: 8; // Reference counts can be stored in 8 bits, stored directly here}; // struct {uintptr_t nonpointer: 1; // uintptr_t has_assoc: 1; Uintptr_t has_cxx_dtor: 1; // Uintptr_t shiftcls: 33; Uintptr_t magic: 6; // Uintptr_t magic: 6; Uintptr_t Weakly_referenced: 1; // Whether the locating is weakly referenced to the uintptr_t deallocating: 1; // Whether the object is releasing the uintptr_t has_sidetable_rc: 1; Uintptr_t extra_rc: 19; // Reference counts can be stored in 19 bits, stored directly here};Copy the code

Has_sidetable_rc and extra_rc indicate whether the pointer refers to the SIDETable hash table. This option is available because small reference counts are not stored directly in the SideTables table. The object’s reference count is stored in extra_RC first, and only when it is full is stored in the corresponding SideTables hash. There are many SideTables in SideTables, and each SideTable is also a hash. The reference counting table is included in the SideTable.

  • Hash table (reference count table, weak reference table)

Reference counts are stored either in the extra_rc of isa or in the reference count table, which is contained in a structure called SideTable, which isa hash table, or hash table. The SideTable, in turn, is contained in a global StripeMap hash map table called SideTables.

When an object accesses SideTables:

  • We get the address of the object, hash the address, and mod the number of SideTables in SideTables. The result is the SideTable that the object accesses

  • Perform another hash lookup in the RefcountMap table of the obtained SideTable to find the position of the object in the reference count table

  • If the position has a reference count, the operation is performed on it. If there is no reference count, a size_t object is created, which is an unsigned integer of type uint

  • Weak-reference table is also a hash table structure, which contains weak_entry_t corresponding to each object. Weak_entry_t is a structure array, which contains the weak-reference pointer corresponding to each weakly referenced object.

9. Circular references

The essence of circular references: multiple objects have strong references to each other and cannot be freed for the system to recycle. How to solve circular reference?

Avoid circular references, usually by changing a strong reference to an weak reference. For example, using a weak reference to an object method called inside a block with weak while decorating a property, you can use two macros

#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self; / / weak referencesCopy the code
#define ST(strongSelf) __strong __typeof(&*self)strongSelf = weakSelf;
Copy the code

WeakSelf can also use __block to modify variables

__block does not increase its reference count in MRC, avoiding circular references. In ARC, __block modifiers are strongly referenced, and circular references cannot be avoided and need to be removed manually.

2. Manually break circular references when appropriate. Usually we use the first one.

  • A delegate circular reference is a cross-circular reference

    Delegate is a circular reference that is commonly encountered in iOS development. When you declare a delegate, you usually use a weak reference, or a weak reference, assign. How do you choose to use the weak or weak reference? Because the weak variable automatically points to nil after being freed, it prevents wild Pointers

  • NSTimer circular references are circular references to each other

    Within a controller, create an NSTimer as its property, and since the timer is also strongly referenced to the controller object after it is created, the object and timer are referred to each other in a loop. How to solve it? Here we can use a manual break loop reference: if the timer is not repeated, set timer invalidate to nil in the callback method. If it is a repeat timer, set its invalidate to nil in the appropriate place

Block loop reference

A simple example:

@property (copy, nonatomic) dispatch_block_t myBlock;
@property (copy, nonatomic) NSString *blockString;

- (void)testBlock {
    self.myBlock = ^() {
        NSLog(@"%@",self.blockString);
    };
}
Copy the code

Since a block holds an object in the block, it holds an object in the block, and if the object in the block holds the block, it creates a circular reference. The solution is to use the __weak modifier self

__weak typeof(self) weakSelf = self;

self.myBlock = ^() {
        NSLog(@"%@",weakSelf.blockString);
 };
Copy the code

Not all blocks cause circular references. Only strongly referenced blocks make circular references and dispatch_async(dispatch_get_main_queue()), ^{}),[UIView animateWithDuration:1 animations:^{}] These systematic methods, etc., or blocks are not properties of them but temporary variables, i.e. stack blocks

[self testWithBlock:^{
    NSLog(@"%@",self);
}];

- (void)testWithBlock:(dispatch_block_t)block {
    block();
}
Copy the code

In another scenario, at the beginning of block execution, the self object is not released, but during the execution, self is released. Since it is modified with weak, weakSelf is also released. At this point, when weakSelf is accessed in the block, errors may occur (sending messages to nil objects does not crash, But it didn’t work either).

For this scenario, the object should be decorated with __strong in the block so that it is held for the duration of the block and then released when the block completes.

__weak typeof(self) weakSelf = self;

self.myBlock = ^() {

        __strong __typeof(self) strongSelf = weakSelf;

        [strongSelf test];
 };
Copy the code

10. How is ARC retainCount stored?

How is ARC retainCount stored?

There are 64 hash tables, according to the hash algorithm to find the location, no traversal, very fast

Hash table (reference count table, weak table)

  • On non-embedded 64-bit systems, there are 64 SideTables
  • Each SideTable consists of three main parts. Spin locks, reference count tables, weak reference tables.
  • The reason why global reference counts are not in the same table is to avoid resource competition and solve the problem of efficiency.
  • The concept of split locking is introduced in reference counting tables. A table can be split into multiple parts and locked separately to achieve concurrent operations.

Improve execution efficiency

  • Reference count table (hash table)
  • Through the address of the pointer, you can find the address of the reference count, which greatly improves the search efficiency
  • The DisguisedPtr(objC_object) function is stored and also searched through this function, thus avoiding loop traversal.

11. What does ARC do at compile time?

Insert retain, release in the appropriate place, depending on the context in which the code is executed