I am just a porter, just to deepen the memory, thank the author for sharing, most of the article source: advance snail king

Alloc/init and new


  • alloc/init

Alloc is responsible for allocating memory for all member variables of the object and resetting them to default values, such as 0 for int, NO for BOOL, and nil for pointer variables. It’s not enough just to allocate space, you need init to initialize the object before you can use it. If you just call alloc and don’t call init, it will work, but you may get unknown results.

  • new

You do the same thing with alloc, which is allocate memory and initialize it.

  • The difference between

New can only be initialized using the default init, while alloc can be initialized using other methods, often using alloc/init because a display call is better than an implicit call.

What’s the difference between @”hello” and [NSString stringWithFormat:@”hello”]?


NSString *A = @"hello";
NSString *B = @"hello";
NSString *C = [NSString stringWithFormat:@"hello"];
NSString *D = [NSString stringWithFormat:@"hello"];
Copy the code

@ “hello” is in the constant pool, reusable, where A and B refer to the same memory address. [NSString stringWithFormat:@”hello”] is created at run time and stored in run time memory (heap memory), where C and D point to different memory addresses, as well as A and B.

Propoty modifier


It can be divided into four categories: thread safety, read and write permissions, memory management, and specified read and write methods.

  • Thread safety (atomic, nonatomic)

If the class modifier is not written, the default is atomic. The big difference between the two determines whether the getter/setter method generated by the compiler is atomic or not. If you write your own getter/setter method, it doesn’t matter what you use. For atomic purposes, getters/setters add locks to ensure the integrity of data operations from other threads. For example, thread A’s getter is halfway through, thread B calls the setter, and thread A, name, still gets A full Value. For nonatomic operations, if multiple threads can access the operation at the same time, there is no guarantee that the Value is complete and dirty data will occur. But nonatomic is faster, and development is often safe and efficient under controlled conditions.

If thread A uses getter methods and thread B or C uses setter methods, thread A can fetch one of three possible values: the original value, the B set value, or the C set value. For example, thread A uses the getter method and thread B calls the release method at the same time. Since the release method is not locked, cash may result.

  • Read and write permission (readonly, readwrite)

Readonly A read-only property that generates getters but not setters. Readwrite A read/write property that generates getter/setter methods. This qualifier is the default.

  • Memory management (strong, weak, assign, copy)

Strong Strong reference, applied to objects. The reference count is +1. Objects default to this modifier. Weak weak reference. When a new value is set for this attribute, the setting method neither frees the old value nor preserves the new value, and does not increase the reference count by one. When the object is destroyed, the pointer is automatically set to nil, preventing wild Pointers.

Assgin applies to basic data types such as NSIntger,CGFloat,int, etc., and does only simple assignments. The base data types default to this modifier. If you use this modifier to modify an object, it is not null when the object is destroyed, resulting in a wild pointer. Copy is to solve the context of abnormal dependence, the actual assignment type immutable object, shallow copy; Mutable object when deep copy. Shallow copy: pointer copy. Deep copy: Copy of Pointers and values pointing to memory addresses.

  • Specify accessor (setter=, getter=)

Alias getter/setter methods, which can be inconsistent and have the same name as getters/setters of other properties. For example, the Person class defines the following:

@property (nonatomic, copy, setter=setNewName:, getter=oldName) NSString *name;
@property (nonatomic, copy) NSString *oldName;
Copy the code

P1. oldName = _oldName; p1.oldName = _oldName; p1.name = _oldName; So aliases are interesting and not repetitive to avoid unexpected problems.

  • Difference between strong and copy

Strong is a shallow copy that copies only Pointers and increases the reference count. Copy, on the other hand, is a deep copy when the actual assignment object is mutable. Immutable objects use the copy modifier, such as NSString, NSArray, NSSet, etc. Mutable objects such as NSMutableString, NSMutableArray, NSMutableSet, etc., use strong decorations. Why? Since superclass attributes can point to subclass objects, consider an example like this:

@interface: Person :NSObject
@property (nonatomic, strong) NSString *name;
@end

NSMutableString *mutableName = [NSMutableString stringWithFormat:@"hello"];
p.name = mutableName;
[mutableName appendString:@" world"];
Copy the code

Because of the strong modifier used by Person.name, which makes a shallow copy of the assignment object, person. name actually points to the same block of memory that the mutableName points to. This is not what we want, so we use copy to modify it so that even if we assign a mutable object, we copy an immutable object in the setter method to reassign. For mutable object properties, if you use copy modifier, we know from the above that you will get an immutable object and then assign a value, which will throw an exception, so we use strong.

  • The difference between assgin and weak

Assgin is used for basic types and can modify objects, but the pointer will not be null after the object is destroyed, resulting in wild pointer errors. Weak is used for objects that cannot modify the underlying type, and Pointers are automatically set to nil after the object is destroyed, without causing wild Pointers to crash.

  • How are var, getters, and setters generated and added to 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 at compile time, so the source code for these synthesized methods is not available to the compiler. 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. You can also specify the name of an instance variable in the class implementation code by using the @synthesize syntax.

  • How do you use @Propety in @protocol and category

Using property in protocol only generates setter and getter method declarations, and we use properties in the hope that protocol-compliant objects will implement the property. Using @propety for a category is also a declaration that only generates setter and getter methods. If we really need to add attributes to a category, we need to use the Runtime’s associated object.

Deep copy and shallow copy


  • Deep copy

A deep copy is a copy of the content, that is, a copy of the original content is stored in another memory. The pointer to the new object points to the memory area, which has no relationship with the original object.

  • Shallow copy

Shallow copy refers to the copying of Pointers. That is, creating a new pointer points to the memory space of the original object, which is equivalent to adding +1 to the original object index.

  • Copy and MutableCopy

For mutable objects, Copy and MutableCopy are both deep copies; For immutable objects, Copy is a shallow Copy, and MutableCopy is a deep Copy: Copy returns immutable objects, and MutableCopy returns mutable objects.

  • The test case
    NSArray *arr1 = @[];
    NSArray *arr2 = arr1;
    NSArray *arr3 = [arr1 copy];
    NSArray *arr4 = [arr1 mutableCopy];
    
    NSMutableArray *arr5 = [NSMutableArray array];
    NSMutableArray *arr6 = arr5;
    NSMutableArray *arr7 = [arr5 copy];
    NSMutableArray *arr8 = [arr5 mutableCopy];
    
    NSLog(@"%p %x", arr1, &arr1);
    NSLog(@"%p %x", arr2, &arr2);
    NSLog(@"%p %x", arr3, &arr3);
    NSLog(@"%p %x", arr4, &arr4);
    NSLog(@"%p %x", arr5, &arr5);
    NSLog(@"%p %x", arr6, &arr6);
    NSLog(@"%p %x", arr7, &arr7);
    NSLog(@"%p %x", arr8, &arr8);

Copy the code

Print the result

0x604000001970 e7ba22d8
0x604000001970 e7ba22c8
0x604000001970 e7ba22c0
0x604000458360 e7ba22b8
0x6040004581e0 e7ba22b0
0x6040004581e0 e7ba22a8
0x604000001970 e7ba22a0
0x604000458270 e7ba2298
Copy the code

Weak implementation principle


  • The premise

In Runtime, to manage the reference count and weak pointer for all objects, a global SideTables is created, which is actually a hash table containing the SideTable structure and the memory address of the object as the Key. The SideTable part is defined as follows

Struct SideTable {// Spinlock_t slock; // Save the reference counthashTable RefcountMap refcnts; Weak_table_t Weak_table; // Weak_table. . };Copy the code

Weak_table_t, a structure used to maintain the weak pointer, is a global table, which is partially defined as follows

Weak_entry_t *weak_entries; struct weak_table_t {// Save weak_entry_t *weak_entries; // Storage space size_t num_entries; // Uintptr_t mask; //hashUintptr_t max_hash_displacement; };Copy the code

All weak Pointers are in Weak_entry_t, which is partially defined as follows

Struct weak_entry_t {// Address of the object being referred to. The previous iteration of the search is to determine whether the target address is the same as it. DisguisedPtr<objc_object> referent; Union {struct {// a mutable array that holds the addresses of all weak references to this object. When the object is released, all the Pointers in the referrers are set to nil. weak_referrer_t *referrers; uintptr_t out_of_line_ness : 2; uintptr_t num_refs : PTR_MINUS_2; uintptr_t mask; uintptr_t max_hash_displacement; }; struct { // out_of_line_ness field is low bits of inline_referrers[1] weak_referrer_t inline_referrers[WEAK_INLINE_COUNT]; }; }; . };Copy the code
  • A flowchart

Weak_entry_t = weak_entry_t; Weak_entry_t = weak_entry_t; Weak_entry_t = weak_entry_t; weak_entry_t = weak_entry_t; weak_entry_t = weak_entry_t; weak_entry_t = weak_entry_t; weak_entry_t = weak_entry_t; Value is an array that stores all weak Pointers to the object. When this object dealloc, find the corresponding SideTable, search the pointer array corresponding to key, traverse the number group, set all weak objects to nil, and clear the record.

  • Code Analysis (nsobject.mm)
// Create the weak object id __weak obj1 = obj; // The Runtime calls the following method to initialize the id objc_initWeak(id *location, id newObj) {// If the instance is nil, the current weak object is emptyif(! newObj) { *location = nil;return nil;
    }
    returnstoreWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating> (location, (objc_object*)newObj); } / / pointer to update the static id storeWeak (id * the location, objc_object * newObj) {assert (haveOld | | haveNew);if(! haveNew) assert(newObj == nil); Class previouslyInitializedClass = nil; id oldObj; SideTable *oldTable; SideTable *newTable; // Query oldSideTable and newSideTable retry on newObj:if (haveOld) {
        oldObj = *location;
        oldTable = &SideTables()[oldObj];
    } else {
        oldTable = nil;
    }
    if (haveNew) {
        newTable = &SideTables()[newObj];
    } else{ newTable = nil; }... // Unregister the weak pointer in the old objectif(haveOld) { weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); } // Add weak to the register of the new objectif(haveNew) {newObj = (objc_object *) // This place still needs newObj to check the memory address to find weak_entry_t, Weak_register_no_lock (&newTable-> Weak_table, (ID)newObj, location, crashIfDeallocating);if(newObj && ! newObj->isTaggedPointer()) { newObj->setWeaklyReferenced_nolock();
        }
        *location = (id)newObj;
    } else {}
    
    SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);

    return (id)newObj;
}

Copy the code

KVC


KVC allows you to brief the properties of an operation object in the form of a string, known as Key Value Coding.

  • Underlying implementation mechanism
-(void) setValue:(nullable id)value forKey:(NSString *)key;
Copy the code
  1. In the first place to find-set<Key>:Code is assigned by setter methods if-set<Key>:If they don’t find it, they’ll look it up_set<Key>:Methods.
  2. Otherwise, check+(BOOL)accessInstanceVariableDirectlyMethod, if you override the method and make it return NO, the KVC next executessetValue:forUndefineKey:, throws an exception by default.
  3. Otherwise, KVC searches for the class name in turn_<key>_<isKey><key><isKey>A member variable of.
  4. If none exists, run the commandsetValue:forUnderfinekKeyMethod that throws an exception by default.
- (nullable id)valueForKey:(NSString *)key;
Copy the code
  1. First sequential search-get<key>.-<key>.is<key>The code gets the value through the getter method.
  2. Otherwise, findcountOf<key>.objectIn<Key>AtIndex:and-<key>AtIndexesMethod and one of the other two are found and return a collection of proxies that respond to all NSArray methods, which can be used as NSArray in short.
  3. Otherwise, find-countOf<key>.-enumeratorOf<key>and-memberOf<key>:Method, if all three can be found, returns a set of proxies for all NSSet methods, which in short can be used as nssets.
  4. Otherwise, search for the names in the class in turn_<key>._<isKey>.<key>.<isKey>Returns the value of the member variable.
  5. If no, run the commandvalueForUndefineKey:Method that throws an exception by default.
  • Key Path
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
Copy the code

KVC can manipulate not only object properties, but also the “property chain” of objects. If Person has a birthday attribute of type Date, and Date has attributes such as year, month, day, etc., then Person can directly use the birthday. Year Key Path to operate the birthday year attribute.

  • How to prevent KVC from modifying readOnly attributes?

Can be seen from the above mechanism, when there is NO setter method, will check (BOOL) accessInstanceVariableDirectly to decide whether to search similar member variable, so you just need to override this method and return NO.

  • How to verify the correctness of KVC

In development, some object attributes may need to be set and certain values cannot be set. In this case, the availability of Value needs to be checked by the following method

- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
Copy the code

The default implementation of this method is to find out if it has a method -(BOOL)validate

:error: if it has a method, call it and return YES if it doesn’t. Note: when KVC is set, this method is not used by the caller to validate, so the developer needs to call the validation manually, which means that even if this method is implemented, the assignment will succeed

  • Common exceptions
- (nullable id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
Copy the code

NSUndefinedKeyException is thrown when no relevant Key is found, and these methods are typically overridden when using KVC.

- (void)setNilValueForKey:(NSString *)key;
Copy the code

When an object property of the underlying type is set to nil, an NSValidArgumentException is thrown and generally overridden.

  • Common Application Scenarios
  1. You can use strings to dynamically value and set values, but manipulating objects through KVC performs worse than getters and setters.
  2. Access and modify private properties.
  3. through-(void)setValuesForKeysWithDictionary:Dictionary to Model.
  4. When using KVC on container classes,ValueForKey:Will be passed to each object in the container, rather than the container itself, so we can effectively extract the specified set of property values for each object in the container.
  5. Use functions to manipulate objects in the container to quickly perform operations on the underlying type properties of each object, such as@avg.@count.@max.@min.@sum.

KVO


KVO provides a mechanism (based on NSKeyValueObservin protocol, which is implemented by all objects) for observers to monitor the changes of Object properties and receive notifications, which is called KeyValue observin.

Common API - (void)addObserver:(NSObject *)observerforKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
Copy the code
- (void) observeforkeypath :(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;Copy the code
  • Underlying implementation mechanism

When an observer registers A listener on object A, the system dynamically creates A new class named NSKVONotifying_A, which inherits the original class of object A and overwrites the observed setter method to notify the observer of the value change before and after the original method is called. Then the ISA pointer to object A (which tells Runtime what the class of the object is) points to the new class NSKVONotifying_A. Object A becomes an instance of the new class. Apple overrides the -class method to hide the new class. Make it look like the class of object A has not changed before and after registration, but in fact if you manually create A new NSKVONotifying_A class, the duplicate class will crash when the observer runs to the registration.

  • Matters needing attention

From the above implementation principle, it is obvious that the KVO mechanism will not be triggered if the member variable is directly assigned without setter assignment, except for KVC, which also proves that KVC and KVO are intrinsically related.

classification


Classes are used to add new methods to existing classes, without creating new subclasses, without accessing the source code of the original class, and modularized distribution of class definitions across multiple classes.

  • The characteristics of
  1. The classification method can have the same name as the original class. If the method is implemented in the classification, the classification method has a higher priority than the original class method. (The same name is not recommended, the function of classification is to add square method, should use subclass rewrite or uniform prefix).
  2. Classes can only add methods, not member variables.
  3. Classification affects not only the original class, but also the subclasses.
  4. A class supports defining multiple categories.
  5. If the same method exists in multiple classes, the compiler decides which method to call at run time, and the last method to participate in the compilation will be called.
  6. Categories are loaded at run time, not at the compiler.
  7. You can add properties, but @ Propetry doesn’t generate setter and getter methods. Corresponding member variables are not generated. (Actually meaningless)
  • Usage scenarios
  1. Modular design: For a large feature class, breaking it down by category is a very effective way to facilitate management and collaborative development.
  2. Declare a private method: We can use classes to declare a private method so that it can be used externally without error.
  3. Implementation of informal protocols: Because methods in a classification can only be declared without implementation, the original protocol does not support optional methods, you can use the classification to declare optional methods to implement informal protocols.
  • Why can’t you add a member variable?

Class_addIvar () is used to add member variables to a class. However, apple can only use this method in the construction of a class. It is not allowed to dynamically add member variables to an existing class. Why doesn’t Apple allow it? This is because the object has already allocated memory for its member variables at runtime, and adding attributes dynamically would not only destroy the internal layout, but also create instances of classes that fit the current class definition, which would be disastrous. However, methods are stored in the mutable region of the class, and changes do not affect the memory layout of the class, so no problem.

  • How do I add valid attributes?

If you declare a property in a class, it will compile, but if you use that property, you will not find getter/setter methods. This is because even if you declare a property, you will not generate member variables, so there is no need to implement getter/setter methods. We then need to implement getter/setter methods for properties through the Runtime’s associated object. For example, add the SPeciaName property to a category of Person

#import "Person+Test.h"
#import <objc/runtime.h>// Define the associated key static const char* specialNameKey ="specialName";

@implementation Person (Test)

- (void)setSpecialName:(NSString *) SpecialName {// The first argument: which object to associate with // The second argument: the associated key, from which to obtain // the third argument: Association_retain_nonatomic objc_setAssociatedObject(self, specialNameKey, specialName, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSString *)specialName {// Get the associated value based on the associated key.return objc_getAssociatedObject(self, specialNameKey);
}

@end
Copy the code

Where the associated object also exists in a hash table, by internal addressing. When an object is destroyed, the associated object of the corresponding store is found to clean up the object.

More on Understanding Objective-C: Categories

Could I have an Extension?


Extensions are similar to classes in that they are anonymous, but classes usually have.h and.m files. Extensions are often used to temporarily extend a class’s interface by declaring private attributes, private methods, and private member variables.

  • The characteristics of
  1. It can be defined separately as a file and named the same way as a classification.
  2. Usually put in.m of the main class.
  3. Extensions are loaded at compile time.
  4. To extend the newly added method, the class must be implemented.

Block


Block is an extension of C language, used to realize the characteristics of anonymous functions. Block is also an OC object in nature, which also has an ISA pointer inside. It is an OC object that encapsulates the function call and the function call environment.

  • features
  1. The default for local variables is properties only.
  2. If you want to modify a local variable, declare _block.
  3. A block is an object in OC, and the object holding the block may also be held by the block, thus triggering a circular reference. WeakSelf can be used.
  4. A block simply holds a piece of code that can only be executed when called.
  • The underlying implementation

The corresponding structure of a block is as follows

struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *); }; Struct Block_layout {// All objects have this pointer, which is used to implement object related functions void *isa; // Additional information used to indicate some blocks by bit int flags; // int reserved; Void (*invoke)(void *,...) ; Struct Block_descriptor *descriptor; // Additional description of the block, including size and Pointers to copy and dispose functions. /* Imported variables. */ / Local variables can be accessed by the block because it can copy these variables (or their addresses) into the structure};Copy the code

In Objective-C, there are three types of blocks: _NSConcreteGlobalBlock Global static blocks that do not access any external variables. _NSConcreteStackBlock Holds blocks in the stack that are destroyed when the function returns. _NSConcreteMallocBlock Blocks stored in the heap that are destroyed when the reference count reaches zero.

  • Applicable scenario

Event response, data passing, chain syntax.

  • Answering questions

1. Why can’t you modify local variables directly?

This is because a block regenerates variables, so local variable changes do not affect the block’s variables, and the compiler imposes restrictions on variables in the block.

2. Why can I modify global variables and static variables

Global variables occupy only one copy of memory, which all functions can call together, and blocks can be used directly without deep copying or using variable Pointers. Static variables are actually similar to the _block modifier in that a block is a pointer to a static variable that is used directly, without re-testing it.

3. How to modify local variables

The _block modifier tells the compiler that the local variable can be modified, so that the block does not regenerate, but copies the pointer that uses the local variable.

4. Why strongWeak in blocks

We use weakSelf to prevent cyclic reference, but in some cases, self will be suddenly released during block execution, resulting in incorrect operation, so we use strongSelf to increase strong reference and ensure the normal operation of subsequent code. Wouldn’t that lead to circular references? It does, but only within the scope of the block. Once execution is done, strongSelf is released and the temporary circular reference is automatically broken.

5. Block uses copy or strong

Copy can be used in MRC or ARC. In MRC, if a block is created using a member variable and the block type is _NSConcreteStackBlock, the memory of the block is in the stack area, and the scope is only in the initialized area. If the block is used externally, it may crash. Therefore, copy is used to copy the BLCOK to the heap. In this case, the type is _NSConcreteMallocBlock, making the block usable outside the declaration domain. ARC has only _NSConcreteGlobleBlock and _NSConcreteMallocBlock types. If a block uses a member variable, it is of type _NSConcreteMallocBlock, so either strong or copy works.

6. How to modify local variables without _block?

Despite the compiler’s restrictions, we can still make pointer changes in blocks, such as

int a = 1;
void (^test)() = ^ {// We bypass the compiler restriction by using Pointers, but since the block is a copy of the outer local variable, it does not change the outer local variable even if it is modified. int *p = &a; *p = 2; NSLog(@"%d", a);
};
test(a); NSLog(@"%d", a);
Copy the code

Talk about Objective-C Block implementation

Objective-c object model


All objects at the runtime layer are represented as structs, and NSObject isa structure that contains isa Pointers, as follows

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
Copy the code

Class is also a structure that contains ISA, as follows

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if ! __OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
Copy the code

The ISA pointer in objC_Object tells the Runtime what class it points to, the ISA in objc_Class points to the parent class, and eventually the ISA in the root metaclass points to itself, forming a closed loop. The implementation is not exposed in Objective-C 2.0, but we can see the general implementation in Objective-C 2.0, including parent classes, member variables, method tables, and so on.

  • Common usage
  1. Dynamically change the value of ISA, isa swizzling, such as KVO.
  2. Dynamically modify methodLists, Method Swizzling, such as Category.

The ARC with GC


ARC (Automatic Reference Counting) is a memory management Counting method proposed by Apple at WWDC 2011. It is often applied to iOS and MacOS. The Garbage Collection (GC) mechanism is well known due to the popularity of Java. In simple terms, the system periodically searches for unused objects and frees the memory of the Garbage collector.

  • Is ARC sure not to leak memory?

No, although most of the memory management using ARC is good, it can still cause memory leaks if not used properly, such as when the circular reference: OC Bridges with the Core Foundation class, which can also cause memory leaks if the pointer is not cleared, resulting in wild Pointers, etc.

  • The difference between the two
  1. In terms of performance, GC requires an additional system to keep track of processing memory, and analyzing which memory needs to be freed requires relatively more computation; ARC is the developer’s own way to manage the release of resources, requires no additional systems, and has higher performance than GC.
  2. When GC collects memory, due to the timed trace collection, unused memory cannot be released in time and the current program needs to be paused. If there are many resources, this delay can be very large. ARC only needs a reference count of 0 to be released immediately, without delay.

Memory partition


Divided into five areas: stack area, heap area, global area, constant area, code area. After the program starts, the global area, constant area and code area are fixed and will not change.

  • Stack area

Save some local variables, function jump address, site protection, etc., the area is processed by the system, without our intervention. A large number of local variables deep recursion, function loops can exhaust stack memory and cause a program to crash.

  • Heap area

Runtime memory, that’s where we create objects, and that’s where the developer manages them.

  • Global zone/static zone

Used to store global and static variables, initialized in one area, uninitialized in an adjacent area.

  • The constant area

Store constants, such as string constants, const constants.

  • Code section

Store code.

Static, const, and extern


Static variables are stored in the static section, memory is allocated at compile time, and they remain in app memory until they stop running. This static section is initialized only once, has only one copy in memory, and restricts its use to declared scopes, such as simple interest. Static can also be declared in.h files, but since headers can be referenced by other files, limiting the scope makes no sense.

Const is used to declare a constant. It is read-only and cannot be written. This constant is stored in the constant area, and memory is allocated at compile time.

Int const *p // *p read-only; Int * const p // * const p; P read-only const int * const p //p and *p are both read-only int * const p //p and *p are both read-onlyCopy the code

Extern is used to declare external global variables/constants, telling the compiler to find the corresponding global variable, which needs to be implemented in.m

//Person.h
extern NSString *const Test = @"test";
Copy the code

The correct way to use it is

//Person.h
extern NSString *const Test;

//Person.m
NSString *const Test = @"test";
Copy the code

It is often used to allow the current class to use global variables/constants from other classes. It is also used to manage global variables/constants uniformly. It is cleaner and can be packaged with const to avoid modification by others. Extern can be declared in more than one place, but the implementation must be a single one, otherwise the definition will be repeated.

pretreatment


Preprocessing is part of THE C language and is processed by the compiler before compilation. The results of preprocessing are compiled with the source program.

  • Characteristics of the
  1. All preprocessing commands must start with #.
  2. Usually at the beginning of the program.
  • Common preprocessing commands
  1. Macro definitions: #define, #undef.
  2. Conditional compilation: #ifdef, #ifndef, #else, #endif.
  3. Other #include (C), #import(Objective-c).
  • The macro
  1. Macros are not C statements, they are neither variables nor constants, so they do not need to be assigned with the = sign, and they do not need to be used; The end.
  2. The compiler only finds and replaces macros, replacing all occurrences with the macro’s string, so it’s up to the developer to make sure the macro definition is correct.
  3. Macros can take arguments. It is best to wrap the argument in (), otherwise if the argument is an arithmetic expression, direct substitution will result in an error.
  4. Take up code snippets, and heavy use can cause binaries to grow.

# @ class and import


@class simply tells the compiler that the class exists, but it does not need to know what is in the class. It is not possible to use instance variables, attributes, and methods of the class. #import is more efficient than #import, because #import requires all files that reference the class. #import also creates recursive references. If classes A and B refer only to each other, no error is reported, but if either class declares an instance of the other, an error is reported.

How do I disable calls to existing methods


Since system methods cannot be hidden in OC, for example, when we implement singleton classes new, Allco, copy, and mutableCopy in the future, to ensure that there is only one singleton instance in the entire system, we can declare unavailable methods in header files as follows:

// More succinctly +(instanceType) alloc NS_UNAVAILABLE; +(instancetype) new NS_UNAVAILABLE; -(instancetype) copy NS_UNAVAILABLE; -(instancetype) mutableCopy NS_UNAVAILABLE; // Can customize prompt +(instanceType) alloc __attribute__((unavailable()"alloc not available, call sharedInstance instead")));
+(instancetype) new __attribute__((unavailable("call sharedInstance instead")));
-(instancetype) copy __attribute__((unavailable("call sharedInstance instead")));
-(instancetype) mutableCopy __attribute__((unavailable("call sharedInstance instead")));
Copy the code

Nil nil NULL and NSNull


NULL is used in C. When a function is called or a member variable is accessed, an error message is reported. Can be used to assign a primitive data type to indicate null. Nil and nil are OC syntax. There is no error when calling a function or accessing a member variable. Nil is null for object and nil is null for a pointer to Class type. NSNull is a class. Since nil is special, it’s used to mark the end of an Array and Dictionary, so it can’t store nil, we can use NSNull to indicate that data is empty. However, sending a message to NSNull will result in an error.

NSDictionary implementation principle


NSDictionary is implemented using a Hash table (also called a Hash table). A hash table accesses a data structure stored in memory directly based on a key, that is, it accesses records by calculating a function on a key value and mapping the data to a location in the table, which speeds up lookups. This mapping function is called a hash function, and the array of records is called a hash table. In other words, the essence of a hash table is an array, and each element in the array is actually an NSDictionary key-value pair.

. A and. The framework


  • What is a library?

Libraries are ways of sharing program code. They are generally divided into static libraries and dynamic libraries.

  • What is the difference between a static library and a dynamic library?

Static library: complete copy to executable file when linking, multiple use of multiple redundant copies. The file suffix is usually. A. Framework created by the developer can be used directly. See the differences between.A and.Framework Libraries in iOS.

Response chain


See “iOS Responder Chain” for details.

What happened before main()?


See what happens before main in iOS

@ synthesize and @ dynamic?


The at sign synthesize semantics is that if you don’t implement setter/getter methods manually, then the compiler automatically adds these two methods. It can be used to change the name of an instance variable, such as @synthesize firstName = _myFirstName.

@dynamic tells the compiler that it does not need to be generated automatically, but that the user generates it himself (of course, only getters are provided for readonly properties). If a property is declared as @dynamic var, and you don’t provide @setter and @getter methods, that’s fine at compile time, but when the program runs to instance.var = someVar, the lack of setter methods will crash the program; Or when sameVar = var is run, it will also crash due to the lack of getter methods. Compile time is fine, and the corresponding method is executed at run time, which is called dynamic binding.

  • Now that we have automatic synthetic property instance variables, what else does @synthesize do

So we have to figure out, when does autosynthesis not happen?

  1. When I overwrite both the setter and the getter;
  2. Overrides the getter for a read-only property;
  3. At sign dynamic;
  4. All attributes defined in @protocol;
  5. All properties defined in the category;
  6. Overloaded properties, when you override a property in a subclass, you have to use @synthesize to manually synthesize ivar. In addition to the last three, we can summarize a law for the others; When you want to manually manage everything at sign property, you try to do that either by implementing all the accessor methods of the at sign property or by using at sign dynamic, which is why the compiler thinks you’re going to manually manage the at sign Propetry, The compiler disables autosynthesis. Because of autosynthesis, most developers are not used to manually defining IVAR and rely on autosynthesis, but once you need to use IVAR and autosynthesis doesn’t work, If you don’t manually define IVar, then at sign synthesize ovar manually.

BAD_ACCESS


Wild Pointers are accessed, such as releasing a freed object, accessing a member variable of a freed object, or sending a message.

  • How to debug?
  1. Override the respondsToSelector of an object to show the last object accessed before EXEC_BAD_ACCES appears.
  2. Pass the Edit Scheme-Diagnostics-Zombie Objects.
  3. Through global breakpoints.
  4. Through the Edit Scheme-diagnostics-address Sanitizer.