A few years ago in the process of learning to sort out the knowledge point, today began to transfer to nuggets. As a result of that year when browsing domestic technology books, found knowledge points have many mistakes, stepped on many pits, of course, there may still be mistakes and omissions, welcome to correct ~

KVC


KVC allows indirect manipulation of attributes of objects in the form of strings, 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 via setter methods. (errata 1)
  2. Otherwise, check+(BOOL)accessInstanceVariablesDirectlyMethod, if you override the method and make it return NO, the KVC next executessetValue:forUndefinedKey:, throws an exception by default.
  3. Otherwise, KVC will search for the names in the class in turn_<key>._<isKey>.<key>.<isKey>A member variable of.
  4. If none exists, run the commandsetValue:forUndefinedKey:Method that throws an exception by default.
Corrigendum 1: Verify that the '-_set<Key>:' method is searched after the '-_set<Key>:' method is not found before going to step 2Copy the code
- (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, find-countOf<Key>.-objectIn<Key>AtIndex:and-<key>AtIndexes:Method, if the count method and one of the other two methods are found, returns a set of proxies that can respond to all NSArray methods, simply as NSArray.
  3. Otherwise, find-countOf<Key>.-enumeratorOf<Key>and-memberOf<Key>:Method, if all three can be found, returns a set of proxies that can respond to all NSSet methods, simply 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 none exists, run the commandvalueForUndefinedKey: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 attributes, but also the “attribute 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 the + (BOOL) accessInstanceVariablesDirectly 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 there is a method in the class -(BOOL)validate

:error: if there is a method, call this method and return YES if there is no method. Note: when KVC sets a value, this method is not actively called to validate, the developer needs to manually invoke the validation, meaning that even if this method is implemented, the assignment can succeed.

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

NSUndefinedKeyException is thrown if the relevant key is not found, which is typically overridden when using KVC.

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

When nil to base type object attribute set, throws NSInvalidArgumentException abnormalities, also commonly needs to be rewritten.

  • 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. The most common way to access and modify private properties is to modify the placeHolderText in UITextField.
  3. through- (void)setValuesForKeysWithDictionary:Dictionary to Model, such as the stock field.
  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 NSKeyValueObserving protocol, which is implemented by all objects) for observers to monitor the changes of Object properties and receive notifications, which is called KeyValueObserving.

Common API - (void)addObserver (NSObject *) Observer forKeyPath (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, overwrites the observed setter method, and notifies the observer of the value change before and after the original setter method is called. The ISA pointer to object A (which tells Runtime what the object’s class is) points to the new class NSKVONotifying_A, and object A becomes an instance of the newly created class. In addition, Apple overwrote the -class method to hide the new class, making people think that the class of object A had not changed before and after the registration. 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.

Alloc/init and new


  • alloc/init

Alloc allocates memory for all member variables of the object and resets 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’re doing pretty much the same thing as alloc, which is allocating memory and initializing.

  • 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"];
NSString *E = [[NSString alloc] initWithFormat:@"hello"];
NSString *F = [[NSString alloc] initWithFormat:@"hello"];

NSLog(@"A=%p\n B=%p\n C=%p\n D=%p\n E=%p\n F=%p\n", A, B, C, D, E, F);

// 结果
A=0x104ba0070
B=0x104ba0070
C=0xdbd16c40a2e07e99
D=0xdbd16c40a2e07e99
E=0xdbd16c40a2e07e99
F=0xdbd16c40a2e07e99
Copy the code

@”hello” is in the constant pool, reusable, where A and B refer to the same memory address. StringWithFormat or initWithFormat is created at run time, stored in run-time memory (heap memory), and they request the corresponding value in the heap. If it exists, the system does not allocate an address.

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 is deciding whether the getter/setter method generated by the compiler is atomic. If you write your own getter/setter method, it doesn’t matter what you use. For atomic purposes, getter/setter methods add locks to ensure operation integrity from other threads. For example, if thread A’s getter is halfway through and thread B calls the setter, thread A still gets A full Value. For nonatomic operations, if multiple threads can access the operation simultaneously, there is no guarantee of a complete Value and dirty data can be generated. But nonatomic is faster, and development is often safe and efficient under controlled conditions.

For example, thread A uses getter methods, while thread B and C use setter methods. Then thread A can obtain the original value, B set value, or 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 be caused.Copy the code
  • 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.

  • Specify accessor (setter=, getter=)

Alias getter/setter methods that can be inconsistent and have the same name as getters/setters of other properties, as defined in the Person class as follows

@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 meaningful and non-repetitive, avoiding 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, and so on, 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 as the mutableName. The person. name is also going to change, which is not what we want, so we use copy so that even if the assignment object is a mutable object, we copy an immutable object and assign it in the setter method. For mutable object properties, if you use the copy modifier, you will get an immutable object, and then if you want to modify the object, you 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 after the object is destroyed, the pointer will not be null, 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 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. 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 @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, so if we really need to add property implementations for a category, we need to use the Runtime’s associated object.

Deep copy and shallow copy


  • Deep copy

Deep copy is a copy of the content, that is, a copy of the original content in another memory, the new object pointer to the memory area, has no relationship with the original object.

  • Shallow copy

A shallow copy is a copy of a pointer. Creating a new pointer also points to the memory space of the original object. It is equivalent to adding +1 to the index of the original object.

  • 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 structure of the SideTable, and uses the memory address of the object as the key. The SideTable section is defined as follows

Struct SideTable {// Spinlock_t slock; // Save the hash table for reference count 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 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; // Hash key maximum offset value uintptr_t max_hash_displacement; };Copy the code

All weak Pointers exist 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_table_t is a global hash table (weak_table_t). Weak_t is a global hash table (weak_table_t). Weak_t is a global hash table (weak_table_t). Weak_entry_t, the underlying structure, takes the memory address of the weak object as the key, and value is an array that stores all the weak Pointers of the object. When the object is dealloc, assume that the memory address of the object is A, find the corresponding SideTable, search the pointer array corresponding to key A, 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 null if (! newObj) { *location = nil; return nil; } return storeWeak<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: if (haveOld) {oldObj = *location; oldTable = &SideTables()[oldObj]; } else { oldTable = nil; } if (haveNew) { newTable = &SideTables()[newObj]; } else { newTable = nil; }... Weak_unregister_no_lock (&oldTable->weak_table, oldObj, location); weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); If (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

Category (Category)


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 purpose of classification is to add methods, should use subclass override or uniform prefix)
  2. Classes can only add methods, not member variables.
  3. Classification affects not only the original class but also its 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 compile time.
  7. Properties can be added, but @property does not generate setter and getter methods or corresponding member variables. (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 classes. However, Apple can only call this method during the construction of a class. It does not allow the dynamic addition of 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 do not fit the current class definition, which would be disastrous. But methods are stored in the mutable region of the class, and changes don’t 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 this property, you will not find getter/setter methods. This is because even if you declare a property, you do 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 SpecialName attribute to a class of Person as follows

#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 associated key, from which // the third argument is obtained: 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); } @endCopy the code

The associated object is also stored in a hash table. When the object is destroyed, the associated object will be found for cleaning.

More on Understanding Objective-C: Categories

Could I have an Extension?


An extension is similar to an anonymous classification, but a classification usually has. H and. M files, and an extension is 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 the C language to implement anonymous functions.

  • features
  1. The default is read-only for local variables.
  2. If you want to modify an external 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 is executed only 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 local variables be modified directly?

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

  1. Why can I modify global 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. A static variable is actually similar to a __block modifier in that a block is a pointer to the static variable that is used directly, without being deep-copied.

  1. How do I modify local variables?

The __block modifier tells the compiler that a local variable can be modified, and instead of regenerating a block, it copies a pointer that uses the local variable.

  1. Why use strongSelf in a block?

We use weakSelf to prevent cyclic reference, but in some cases, self will be suddenly released during the execution of block, 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.

  1. Is block copy or strong?

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

  1. How to modify local variables without using __block?

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

int a = 1; Void (^test)() = ^ {void (^test)() = ^ {void (^test)() = ^ {void (^test)() = ^ {void (^test)() = ^ {void (^test)() = ^ {void (^test)() = ^ { int *p = &a; *p = 2; NSLog(@"%d", a); }; test(); NSLog(@"%d", a);Copy the code

For more on 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. Objective-c 2.0 does not expose the implementation, but we can see the general implementation of Objective-C 2.0, including parent classes, member change tables, 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 technology 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 unwanted objects and frees their memory.

  • Can ARC not 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 circular references; If the OC and Core Foundation classes are not properly managed, memory leaks will occur. The pointer is not cleared, resulting in wild Pointers.

  • The difference between the two
  1. In terms of performance, GC requires an additional system to keep track of processing memory and analyze which memory needs to be freed, which 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 suspended. If there are many resources, this delay will be 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 be changed.

  • 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, and function loop calls 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 variable is initialized only once, has only one copy in memory, and limits its use to declared scopes, such as singletons. Static can also be declared in.h files, but since headers can be imported and used 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 is allocated memory 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. The compiler processes these preprocessing commands before compiling them, and the results of these 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. #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 direct substitution will result in an error if the argument is an arithmetic expression.
  4. Take up code snippets, and heavy use can cause binaries to grow.

# @ class and import


At sign class just tells the compiler that there is a class, but you don’t need to know what’s in that class, you can’t use instance variables, properties, and methods of that class. It compiles more efficiently than #import, because #import requires all the headers of the referenced class to be passed through, whereas @class does not. #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, alloc, copy and mutableCopy, we can declare unavailable methods in the header file, as follows:

// More succinctly +(instanceType) alloc NS_UNAVAILABLE; +(instancetype) new NS_UNAVAILABLE; -(instancetype) copy NS_UNAVAILABLE; -(instancetype) mutableCopy NS_UNAVAILABLE; // Can customize the 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

CocoaPods


  • How to use it?

After installing the CocoaPods environment, go to the root directory of the desired project and use POD Init to create a Podfile. Open the file, add the required third-party library POD ‘XXX’, save and close the file, and enter POD Install to install the software. If you do not import headers from the tripartite library after success, add $(SRCROOT) to User Header Search Paths and select Recursive.

  • The principle of

Put all the dependency libraries into another project called Pods, and then make the main project depend on the Pods project, so that the source management work is moved from the main project to the Pods project. The Pods project will eventually become a libPods.a file, and the main project will only rely on the. A file.

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 and is used to mark the end of an Array and Dictionary, we can’t store nil. We can use NSNull to indicate that the 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 is a data structure that accesses data stored in memory directly based on a Key. That is, it accesses records by calculating a function on the 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, a hash table is essentially an array, and each element in the array is essentially 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, which is created by the developer. Framework is a static library. Dynamic library: link does not copy, program run by the system dynamically loaded into memory, for program call, the system only loaded once, multiple programs shared, saving memory. The file suffix is.dylib, the system’s.framework is a dynamic library.

  • The difference between.a and. Framework

.a is a pure binary file, which also requires. H files and resource files, while the. Framework can be used directly.

See the differences between.A and.Framework Libraries in iOS.

Response chain


See “Some Understanding of iOS Responder Chain”

What happened before main()?


See what happens before main in iOS

@ synthesize and @ dynamic?


The @synthesize semantics means 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 is generated by the user (of course, you only need to provide getters 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 someVar = 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 do you not have autosynthesis?

  1. When I overwrite both the setter and the getter
  2. Overrides the getter for a read-only property
  3. When you use 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 must use @synthesize to manually synthesize ivar. In addition to the last three, we can summarize a law for the others: When you want to manage all the contents of an @property manually, you try to do this either by implementing all the accessor methods of an @property or by using @Dynamic, The compiler will assume that you intend to manually manage @property, and the compiler will disable autosynthesis. Because of autosynthesis, most developers are used to not defining IVAR manually and rely on autosynthesis, but as soon as you need to use IVAR and autosynthesis doesn’t work, If you don’t manually define IVAR, then you have to use @synthesize to manually synthesize IVAR.

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 method of an object to display the last object accessed before EXEC_BAD_ACCESS appears.
  2. Pass the Edit Scheme-Diagnostics-Zombie Objects.
  3. Through global breakpoints.
  4. Through the Edit Scheme-diagnostics-address Sanitizer.