1. What is the difference between classification and extension? What can be used for? What are the limitations of classification? What are the members of the classification structure?
- Classification is mainly used to add methods, attributes, and protocols to a class (I usually use it to extend the methods of a system class or to separate the functions of a complex class into different files).
- Extensions are used mainly for member variables, attributes, and methods that a class does not already have. Note: Methods are declarations only (I usually declare private properties with extensions, or override read-only properties of.h to be read and write)
The difference between classification and extension:
- Classification merges classification information into class information at run time, whereas extension merges information into the class at compile time. Dynamically merge classified methods into class objects and metaclass objects through runtime.
- Class declared properties only generate declarations of getter/setter methods. Member variables and implementations of getter/setter methods are not automatically generated, whereas extensions do
- Classes cannot be used to add instance variables to classes, whereas extensions can
- A classification can add implementations of methods to a class, whereas an extension can only declare methods, not implement them
Limitations of classification:
- Note: The memory management of the associated object does not have weak, so you need to pay attention to the problem of wild Pointers. You can implement it through other methods. For details, please refer to the iOS weak keyword ramblers
- A classified method with the same name as the original implementation of the class overwrites the implementation of the original method. Note: This is not true overwriting
- Methods of multiple classes have the same name, and the implementation of the last compiled class is called
What members are in the structure of the classification
struct category_t { const char *name; // name classref_t CLS; Struct method_list_t *instanceMethods; Struct method_list_t *classMethods; Struct protocol_t *protocols; Struct property_list_t *instanceProperties; Struct property_list_t *_classProperties; // Class attribute list};Copy the code
2. Talk about the implementation mechanism of atomic; Why can’t we guarantee absolute thread-safety (preferably in context)?
-
Atomic is one of the property modifiers that means atomic and is used as @property(atomic)int age; , the compiler automatically generates getter/setter methods and eventually calls objc_getProperty and objc_setProperty methods to access the property. Os_unfair_lock is used to lock both methods to ensure atomicity of reads and writes. Locks are stored in PropertyLocks (8 on iOS and 64 on MAC), and are initialized before being used. When needed, the locks are retrieved from PropertyLocks using the address of the object plus the offset of the member variable as key. Because the same lock is used to access the property, atomic can guarantee thread-safe access to the property. Note: Since locks are finite, it is possible to read different properties using the same lock without using objects
-
Why can’t Atomic guarantee absolute thread-safety?
- Atomic adds a lock to the getter/setter method only to ensure thread-safe access, assuming that our property is
@property(atomic)NSMutableArray *array;
With mutable containers, there is no guarantee that changes to the container will be thread-safe - The compiler automatically produces getter/setter methods that are eventually called
objc_getProperty
andobjc_setProperty
When we override getters/setters, we have to rely on ourselves to ensure thread-safety in getters/setters
- Atomic adds a lock to the getter/setter method only to ensure thread-safe access, assuming that our property is
3. What happens to weak objects when they are released? How is it done? You know sideTable? Can I draw the structure inside?
- What happens to the weak modified object when it is released? An object decorated with weak sets the weak pointer to nil automatically when it is released
- How is weak implemented? The runTime will put the weakly modified object into a global hash table. The memory address of the weakly modified object is key, and the weak pointer is the value. When the object is destroyed, the runTime will use its own address to find all the weak Pointers to this object in the hash table, and set all the weak Pointers to nil
- The structure of sideTable
struct SideTable { spinlock_t slock; // SideTable RefcountMap refcnts; // Reference counter value weak_table_t weak_table; // hash table where weak pointer exists; Copy the codeCopy the code
4. What are the applications of associated objects and how does the system manage them? Do I need to manually null all Pointers to associated objects when it is released?
- What are the applications of associated objects? Typically used to add instance variables to classes in a classification
- How does the system manage associated objects?
First of all, we have a global in the systemAssociationsManager
There’s aAssociationsHashMap
Hash table, hash table key is the memory address of the object, value isObjectAssociationMap
, is also a hash table, where key is the key that we set the associated object to, value isObjcAssociation
, which holds the values of the associated object Settings and memory management policies. hasvoid objc_setAssociatedObject(id object, const void * key,id value, objc_AssociationPolicy policy)
For example, it will pass firstAssociationsManager
To obtainAssociationsHashMap
And then toobject
The memory address of theAssociationsHashMap
Remove theObjectAssociationMap
If no, create a new oneObjectAssociationMap
, and then get the old value through key and generate the new value through key and policyObjcAssociation(policy, new_value)
, save the new value toObjectAssociationMap
, if the new value is not nil and the memory management policy isretain
, the new value is evaluated onceretain
, if the new value is nil, the old value is deleted, if the old value is not empty and the memory management strategy isretain
, the old value is performed oncerelease
- Do I need to manually null all Pointers to associated objects when it is released? Note: When an object is released, do I need to manually remove the associated object set by the object? No, because in the object’s dealloc, it is called when an object is found to have an associated object
_object_remove_assocations
Method to remove all associated objects and determine whether the value of the associated object needs to be released according to the memory policy
5. The underlying implementation of KVO? How to cancel the system default KVO and trigger it manually (set conditions for triggering KVO: trigger KVO when the changed value meets a certain condition)?
-
The underlying implementation of KVO?
- When properties of a class are observed, the system dynamically creates a subclass of that class at run time. And points the object’s ISA to this subclass
- Suppose the property name being observed is
name
If there is one in the parent classsetName:
Or this_setName:
Override both methods in subclasses. If both methods exist, override onlysetName:
One (this is the same search order as KVCset) - If the type being observed is NSString, the implementation of the overridden method will point to
_NSSetObjectValueAndNotify
This function, if it’s a Bool, then the implementation of the overridden method will point to_NSSetBoolValueAndNotify
This function, this function is calledwillChangeValueForKey:
anddidChangevlueForKey:
And calls the implementation of the parent set method between the two method calls - The system will in
willChangeValueForKey:
Assign to change[old] in observevalueForKey:
The values,didChangevlueForKey:
Assign change[new] to Observe and call observe’s method- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
- When you use KVC assignment, in NSObject
setValue:forKey:
Method, if the parent class does not existsetName:
Or this_setName:
These methods are called_NSSetValueAndNotifyForKeyInIvar
This function, this function will also be calledwillChangeValueForKey:
anddidChangevlueForKey:
, if it exists
-
How to cancel the system default KVO and trigger it manually (set conditions for triggering KVO: trigger KVO when the changed value meets a certain condition)? For example, disable the default KVO for the age attribute of the Person class. If age is greater than 18, KVO is triggered manually
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { if ([key isEqualToString:@"age"]) { return NO; } return [super automaticallyNotifiesObserversForKey:key]; } - (void)setAge:(NSInteger)age { if (age > 18 ) { [self willChangeValueForKey:@"age"]; _age = age; [self didChangeValueForKey:@"age"]; }else { _age = age; }} Copy the codeCopy the code
6. What is the data structure used by Autoreleasepool? Is the AutoreleasePoolPage structure understood?
Autoreleasepool is made up of multiple Autoreleasepoolpages that are connected in a bidirectionally linked list. When each AutoreleasePoolPage is created, a marker bit is set in the current AutoreleasePoolPage. During this time, when an object calls autorelsease, the object is added to the AutoreleasePoolPage. If the current page is full, a new page is initialized. When automatically releasing pool POP, pop up from the bottom, calling the release method of each object until flag bits are encountered. The AutoreleasePoolPage structure is as follows
class AutoreleasePoolPage { magic_t const magic; id *next; Pthread_t const thread; //AutoreleasePoolPage thread AutoreleasePoolPage * const parent; // AutoreleasePoolPage *child; // Uint32_t const depth; Uint32_t hiwat; // Uint32_t hiwat; } Duplicate codeCopy the code
7. Talk about objects, class objects, metaclasses, and the composition of metaclasses and how they are related. Why are object methods not stored in the object structure, but in the structure of the class object?
-
Talk about objects, class objects, metaclasses, and the composition of metaclasses and how they relate to each other. Isa and member variables are stored in the structure of the object. Isa refers to the class object. The ISA of the class object points to the metaclass, and the ISA of the metaclass points to the metaclass of NSObject. The structures of class objects and metaclasses include ISA, superclass, cache, and bits. Bits contain Pointers to class_rw_t. Let me show you a classic picture
-
Why are object methods not stored in the object structure, but in the structure of the class object? Methods are shared by each object. It would be a waste of memory to store a list of methods for each object. Since the isa of an object refers to a class object, when called, you can just look it up in the class object. Can save a lot of memory space
8. What is the difference between class_ro_t and class_rw_t?
Class_rw_t provides the ability to extend classes at runtime, whereas class_ro_t stores most of the information that the class has already determined at compile time. Both contain information about the class’s methods, attributes (member variables), protocols, and so on, but the lists that store them are implemented differently. Simply put, class_rw_t stores a two-dimensional array for lists, and class_ro_t uses a one-dimensional array. Class_ro_t is stored in the class_rw_T structure and is immutable. Holds information about the class that was determined at compile time. The methods, attributes, protocols, and so on used to modify classes at run time are stored in class_rw_t
9. How many ways to introspect in iOS? What is the difference between the class method and the objc_getClass method?
- What is introspection?
In computer science, introspection refers to the ability of a computer program to check the type of an Object at Run time, often referred to as runtime type checking. Introspection should not be confused with reflexes. Taking introspection one step further, reflection refers to the ability of a computer program to access, detect, and modify its own state or behavior during Run time.
-
How many ways to introspect in iOS?
- IsMemberOfClass // Whether the object is of a certain type
- IsKindOfClass // Whether the object is an object of a type or a subclass of a type
- IsSubclassOfClass // Whether a class object is a subclass of another type
- IsAncestorOfObject // Whether a class object is the parent of another type
- RespondsToSelector // Whether a method can be responded to
- ConformsToProtocol // Specifies whether to comply with a protocol
-
What is the difference between the class method and object_getClass method? The instance class method returns object_getClass(self) directly, the class class method returns self directly, and object_getClass(class object) returns a metaclass
10. The method objc_allocateClassPair that creates the class at runtime ends in pair.
Because this method creates a class object and a metaclass, it fits into a line
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes){ ... // Generate a class object CLS = alloc_class_for_subclass(superclass, extraBytes); // Create a metaclass object meta = alloc_class_for_subclass(superclass, extraBytes); objc_initializeClassPair_internal(superclass, name, cls, meta); return cls; } Duplicate codeCopy the code
11. What is the difference between an int variable being modified by __block or not?
An int variable is wrapped as an object after being modified by __block, such as __block int age
struct __Block_byref_age_0 { void *__isa; __Block_byref_age_0 *__forwarding; // point to yourself int __flags; int __size; int age; // The specific value of the package}; // age = 20; (age.__forwarding->age) = 20; Copy the codeCopy the code
12. Why use the __weak modifier outside a block and the __strong modifier inside?
When asked a question about Block in an interview, say “Good question” on the spot (I haven’t thought about it before), and now think about it again.
__weak __typeof(self)weakSelf = self;
Block(param)
^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
// Do stuff
});
Copy the code
- First, discuss the case where there is no weakSelf. Block will make a strong reference to self, and at the same time Block itself is strongly referenced by self, leading to the classic circular reference problem (S -> B -> S).
- WeakSelf is designed to break the loop. Objects modified by the __weak modifier are automatically empty when their strong object is empty, without causing the reference count to change (S -> B -> WS). In fact, weakSelf is enough here, why should we continue to convert strongSelf in the Block function body?
- If self is dealloc during the execution of Block function body, at this time, the first part of weakSelf may be effective in the function body, and the second part becomes weakSlef==nil, which may lead to crash. The introduction of strongSelf in the Block, with its __strong modifier, means that self in the function body will not be forced to be empty due to external operations. When the function body completes, strongSelf is null because of the end of scope, dereferencing.
Conclusion:
- Use weakSelf to remove circular references
- Use strongSelf for increased security.
13. What does RunLoop do? Is its inner workings understood? (Best combined with thread and memory management)
-
In general, a thread can execute only one task at a time, and when it is finished, the thread exits. If we need a mechanism that allows threads to handle events at any time without exiting. This model is often referred to as the Event Loop. Event Loop is implemented in many systems and frameworks, such as Node.js Event processing, Windows message Loop, and OSX/iOS RunLoop. The key points to implement this model are how to manage events/messages and how to make threads sleep when they are not processing messages to avoid resource usage and wake up as soon as a message arrives.
-
What does RunLoop do? (What can you do with RunLoop?)
-
To keep the program running, in iOS threads a RunLoop is created for the main thread in the main method to ensure that the main thread is not destroyed
-
Handle various events in the APP (touch, Timer, performSelector, etc.)
-
Interface to update
-
Gesture recognition
-
AutoreleasePool
- The system registers two observers in the main thread RunLoop
- The first observe listener is about to enter the RunLoop. Call _objc_autoreleasePoolPush() to create the automatic release pool
- The second observe listens for two events, before entering hibernation and before exiting RunLoop
- In the callback before going to sleep, the auto release pool is first released, and then another auto release pool is created
- In the exiting callback, the automatic release pool is released
-
Thread to keep alive
-
Monitoring the caton
-
-
The internal logic of RunLoop (the picture below is from YY Dashen’s blog)
14. What scenes can trigger an off-screen rendering? (Speak as much as you know)
- Add a mask mask
- Add shadow shadow
- Set rounded corners and masksToBounds to true
- Setting allowsGroupOpacity to true and layer.opacity less than 1.0 and having a sublayer or background that is not empty
- ShouldRasterize =true
15. How does an AppDelegate slim down?
- Why is the AppDelegate so bloated? The AppDelegate is a portal to a project that performs a lot of functions, such as initializing the root controller, managing the application’s state, managing push, interacting with other apps, initializing third-party SDKS, obtaining permissions, and so on
- There are many ways to slim down, such as putting some methods into the swift extension or OC classification, extracting intermediate classes, using notification listening, etc., but my favorite is to use command design mode to slim down. The command mode describes an object called a command rather than a simple method or event. Because the object encapsulates all the parameters needed to trigger itself, so the caller of the command doesn’t know what the command does or who the responder is, can define a command for each of the Responsibilities of the APPdelegate with a name they specify
protocol Command { func execute() } struct InitializeThirdPartiesCommand: The Command {func the execute () {/ / initializes the third-party libraries}} struct InitialViewControllerCommand: Command {let keyWindow: UIWindow func the execute () {/ / set the root controller keyWindow rootViewController = UIViewController ()}} struct RegisterToRemoteNotificationsCommand: Command {func the execute () {/ / registered remote push}} to copy codeCopy the code
We then define StartupCommandsBuilder to encapsulate the details of how commands are created. The APPdelegate calls the Builder to initialize commands and execute them
// MARK: - Builder final class StartupCommandsBuilder { private var window: UIWindow! func setKeyWindow(_ window: UIWindow) -> StartupCommandsBuilder { self.window = window return self } func build() -> [Command] { return [ InitializeThirdPartiesCommand(), InitialViewControllerCommand(keyWindow: window), RegisterToRemoteNotificationsCommand() ] } } // MARK: - App Delegate @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { StartupCommandsBuilder() .setKeyWindow(window!) .build().foreach {$0.execute()} return true}} Copies the codeCopy the code
If the APPdelegate needs to add new responsibilities, you can create new commands and add them to the Builder without changing the APPdelegate. And using command mode has the following benefits
- Each command has a single responsibility
- You can easily add new commands without changing the APPdelegate
- Each command can easily be tested individually
16. What is reflection? Can you name some application scenarios? (Speak as much as you know)
- What is reflection
Reflection refers to the ability of a computer program to access, detect, and modify its own state or behavior at runtime. Reflection, figuratively speaking, is the ability of a program to “observe” and modify its behavior as it runs.
In OC, reflection means that the program retrieves and modifies information about a class at run time. 2. Application scenarios
- Conversion between JSON and model
- Method Swizzling
- The implementation principle of KVO
- NSCoding automatic archiving and automatic file solution
- Explore concrete implementations of some of the system’s classes
17. What scenarios are easier for NSOperation to implement than GCD? (or NSOperation is better than GCD, say as much as you know)
- NSOperation can set dependencies
- NSOperation can be paused or continued
- NSOperation can monitor the status of the current queue
- NSOperationQueue can cancel all operations in the queue
- NSOperationQueue is a handy way to set the maximum number of concurrent requests
18. App startup optimization strategy? It is best to say this in combination with the startup process (the main() function before and after the execution, as much as you know).
-
IOS startup process
- Follow the Settings in info.plist to load splash screens, set up sandboxes, check permissions, etc
- Load the executable file
- Load dynamic link library, rebase pointer adjustment and bind symbol
- Initial processing of Objc runtime, including registration of Objc related classes, category registration, selector uniqueness check, etc.
- Initialization, which includes calling functions that perform the +load() method, attribute((constructor) modification, and creating C++ static global variables.
- Execute main
- Application initialization to applicationDidFinishLaunchingWithOptions performed
- Initialize the frame rendering, and by the time viewDidAppear is done, the user can see it.
-
Start the optimization
- Reduce dynamic library loading
- Remove the number of useless classes and C++ global variables
- Try to keep the load method after the first screen rendering, or use Initialize instead
- Remove unnecessary features before the first screen display
- Check the time-consuming methods of the main thread before the first screen display, and delay or delay the execution of unnecessary time-consuming methods
19. Is the idea of App traceless burying point understood? What characteristics do you think an ideal traceless burying point system should have? Speak as much as you know.
The idea behind App traceless burying point is to use AOP to intercept user actions, mark them and then upload them
I think the ideal traceless burying point system should have the following characteristics
- No intrusion into business code
- Count as many events as possible
- Automatically generate unique identifiers
- To be able to count the control in different states with different meanings
- Some mechanism is required to provide business data
- Upload data at the right time
20. Do you know which situations will cause app crashes, and what methods can be used to intercept and resolve them? Speak as much as you know.
- Unrecognized selector sent to instance method not found
- Array out of bounds, insert null value
[NSDictionary initWithObjects:forKeys:]
When using this method to initialize a dictionary, the number of objects and keys is inconsistent- NSMutableDictionary,
setObject:forKey:
orremoveObjectForKey:
, key is nil setValue:forUndefinedKey:
Pass in an incorrect key or assign an immutable dictionary when using KVC to store values for objects- NSUserDefaults store keys as nil
- When operating on string, the subscript passed is out of range, check whether there is prefix, suffix substring, substring is empty
- When a string is initialized with a C string, null is passed
- Use the copy modifier on a mutable collection or string and modify it
- AutoLayout is used for layout before space is added to the parent element
- KVO No KVO was removed or KVO was removed multiple times during object destruction
- Wild pointer access
- A deadlock
- In addition to 0
From 1-9, the Runtime can be used for interception, and then some logical processing can be carried out to prevent crash
21. Do you know which situations may cause app lag, and what can be done to avoid them? Speak as much as you know.
- In the main thread evolution IO or other time-consuming operations, to solve: time-consuming operations in the child thread operation
- GCD concurrent queue creates a large number of tasks in a short time, solution: use thread pool
- Text computation, resolution: Put computation in child threads to avoid blocking the main thread
- Large number of image drawing, solution: in the child thread to decode the picture after the display
- Hd picture display, solution: can be in the sub-thread under sampling processing after the display
22. What are the optimization strategies for App network layer?
- Optimize DNS resolution and caching
- Compress the transmitted data to reduce the transmitted data
- Use caching to reduce the number of requests
- Use strategies to reduce the number of requests made, such as not making new requests until the last one has hit the ground
- Avoid network jitter and provide retransmission mechanism
23. Why does TCP require three handshakes and four waves?
Three handshakes:
- The client sends a SYN packet with SYN=1 and SEq = X to the server, and the client enters the SYN_SENT state
- The server replies to the client with SYN=1, SEq = Y,ACK=1, ACK= X +1 and enters the SYN_RCVD state
- After receiving an acknowledgement packet, the client sends an acknowledgement packet to the server, ACK=1, ACK= y+1. The client enters ESTABLISHED. After receiving the acknowledgement packet, the server also enters ESTABLISHED
Four waves:
- The client initiates a close link to the server and stops sending data
- When the server receives the request to close the link, it sends a response to the client, I know, and then stops receiving data
- When the server ends sending data, it sends a close link to the client and stops sending data
- When the client receives the request to close the link, it sends a response to the server, I know, and then stops receiving data
Why the three-way handshake is needed: To prevent an invalid connection request segment from suddenly being sent to the server, an error is generated assuming that the connection request segment is already invalid. However, after the server receives the invalid connection request packet segment, it mistakenly thinks it is a new connection request sent by the client. Then the client sends a confirmation message to agree to establish a connection. Assuming that the “three-way handshake” is not used, a new connection is established as soon as the server sends an acknowledgement. Since the client does not send a connection request, it ignores the server’s confirmation and does not send data to the server. However, the server assumes that the new transport connection has been established and waits for data from the client. As a result, many of the server’s resources are wasted.
Why is it necessary to wave four times: Because TCP is full-duplex communication, it may send data to the client when it receives the closing request from the client. Therefore, it cannot respond to the closing request from the client, and sends the closing request at the same time
24. What is the difference between symmetric and asymmetric encryption? Which algorithms are implemented respectively?
Symmetric encryption, in which encryption and decryption of encryption use the same key.
Asymmetric encryption: a public key and a private key are used for encryption and decryption. The public key is available to all. After obtaining the public key of the receiver, the sender can use the public key to encrypt the communication, and the receiver uses the private key to decrypt the communication.
Symmetric encryption algorithm commonly used to implement AES,ChaCha20,DES, but DES is considered to be insecure; Asymmetric encryption algorithm to achieve RSA, ECC
25. HTTPS handshake process? Why should asymmetric encryption be used for key transfer? Two-way authentication understand?
The HTTPS handshake flow is shown below, taken from the diagram HTTP
- The Client sends a Client Hello packet to start SSL communication. The packet contains the SSL version supported by the client and the list of encryption components.
- After receiving the packet, the Server responds with a Server Hello packet. Like the client, the packet contains the SSL version supported by the client and a list of encryption components. The server’s encryption component content is filtered from the received client encryption component
- The server sends a Certificate packet. The message contains a public key certificate.
- Then, the Server sends a Server Hello Done packet to notify the client that the INITIAL SSL handshake negotiation is complete
- After the SSL handshake is complete, the Client uses the Client Key Exchange packet as the conference. The packet contains a random password string called pre-master secret, which is used in communication encryption
- Then the client sends a Change Cipher Space packet. The packet prompts the server that the communication after the second packet is encrypted with the pre-master secret key
- The client sent a Finished packet. Procedure The packet contains the overall checksum of all packets linked so far. The success of the handshake negotiation depends on whether the server can disclose the text correctly
- The server also sends a Change Cipher Space packet.
- The server also sent a Finished packet.
- After exchanging Finished packets between the server and client, the SSL connection is established and HTTP communication starts. All communication content is encrypted using pre-master Secret. Then start sending the HTTP request
- After receiving an HTTP request, the application layer sends an HTTP response
- Finally, a client disconnects
Why should asymmetric encryption be used for key transfer?
A: Asymmetric encryption is used for the security of the pre-master secret key generated by the client. It can be seen from the above steps that the step of the server sending the public key certificate to the client may be intercepted by others. If symmetric encryption is used, When the client sends the pre-master secret to the server, if it is intercepted by a hacker, the secret key can be decoded using the public key, and the security of the pre-master secret key cannot be guaranteed
Two-way authentication understand? (HERE I really want to say don’t know)
A: The HTTPS communication process only verify the server’s identity, and the server did not verify the identity of the client, two-way authentication is the service side is also to ensure the identity of the client, probably process is the client in after checking the server’s certificate, will send your public key to the server, and then generate a new key is encrypted with the public key of a service, to the client, The client then decrypts it with the private key, which is then used for symmetrically encrypted communication
26. How does HTTPS implement authentication and integrity?
When using a digital certificate and a CA for identity authentication, the server first applies for a certificate from the CA. After verification, the CA provides a digital certificate containing information such as public key, signature, validity period, and user information. When the client sends a request, the server sends the digital certificate to the client. The client then verifies the identity of the server through the trust chain to verify that the digital certificate is valid.
The digest algorithm is used to verify the integrity, that is, a digest algorithm is used to generate a summary of the content of the message when the message is sent, and the same algorithm is used to generate a summary when the message is received to judge whether the summary is consistent.
27. How to use Charles to capture HTTPS packet? What are the principles and processes?
Process:
- Start by installing the Charles certificate on your phone
- Enable SSL Proxying in proxy Settings
- Then add the address of the server to be captured
Principle:
Charles acts as a middleman, masquerading as a server to the client and as a client to the server. In a nutshell:
- Intercepts THE HTTPS request from the client and sends the REQUEST to the server disguised as a middleman client
- The receiving server returns and sends the data content to the client disguised as a man-in-the-middle server with its own certificate.
The detailed process is shown in the following figure, which shows HTTPS unidirectional authentication, bidirectional authentication, packet capture principle, and anti-packet capture policy
28. What is a man-in-the-middle attack? How to avoid it?
A man-in-the-middle attack is a man-in-the-middle attack that intercepts client requests and server responses. For example, Charles captures HTTPS packets.
Avoid: The client can pre-bury the certificate locally and then compare the certificate to see if it is a match
29. Do you understand the compilation process? What are the steps?
-
Precompilation: Mainly deals with precompiled instructions that start with “#”.
-
Compile:
- Lexical analysis: The division of character sequences into a series of tokens.
- Parsing: Generates a syntax tree based on parsing generated tokens.
- Semantic analysis: analyzing the semantics of the syntax tree, matching, converting, identifying and so on.
- Intermediate code generation: The source-level optimizer converts the syntax tree into intermediate code and performs source-level optimizations, such as 1+2 to 3. Intermediate code makes compilers divided into front end and back end. Different platforms can use different compiler back end to convert intermediate code into machine code to achieve cross-platform.
- Object code generation: The subsequent process is at the back end of the compiler. The code generator converts intermediate code into object code (assembly code), which is then optimized by the object code optimizer, such as adjusting addressing, using displacement instead of multiplication, removing redundant instructions, adjusting instruction order, and so on.
-
Assembly: The assembler converts assembly code into machine instructions.
-
Static linking: The linker links together object files that have been compiled into machine instructions and relocates them to output an executable file.
-
Load: Loads the executable and the shared objects it depends on.
-
Dynamic linking: The dynamic linker corrects the locations in executable files and shared objects that need to be relocated.
-
Finally, control of the process is transferred to the program entry, and the program is finally running.
30. Static links? What is the difference between static and dynamic libraries?
Static linking is the merging of multiple object files into a single executable, which intuitively feels like merging segments of all object files. It should be noted that the structure of the executable file is basically the same as that of the object file, the difference is whether it is “executable”. Static library: complete copy to executable file when linking, multiple use of multiple redundant copies. 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.
31. What are the functions of the large areas of memory?
- Stack area: the system automatically allocates and releases, generally storing function parameter values, local variables and so on
- Heap area: allocated and released by the programmer, if not released by the programmer, at the end of the program released by the system, iOS created objects are placed in the heap area
- Data segment: string constants, global variables, static variables
- Code snippet: compiled code
What is the difference between static and const?
Const const means that the global variable is visible only in the current file. Static means that the initial value of each call is the value of the last call. Storage space is not released after the call
33. Do you know inline functions?
To reduce the overhead of function calls, the compiler copies the code in the function body to the function call at compile time
34. When will a deadlock occur? How to avoid it?
A deadlock is a phenomenon in which two or more threads are blocked during execution, either by competing for resources or by communicating with each other, and cannot proceed without external action. Four necessary conditions for a deadlock to occur:
- Exclusive condition: a resource can only be used by one thread at a time.
- Request and hold conditions: when a thread is blocked requesting a resource, it holds on to the acquired resource.
- Non-expropriation condition: a thread cannot forcibly expropriate a resource it has acquired until it is used up.
- Circular waiting condition: a circular waiting resource relationship is formed between several threads.
Deadlock can be avoided if only one of the above four conditions is not met
35. What is your understanding of thread safety?
In concurrent execution environment for sharing data by every thread synchronization mechanism to ensure the correct execution, there will be no pollution data, or for a resource, when be multiple threads access, no matter what kind of runtime execution of these threads are order or crisscross, won’t appear the wrong behavior, thought that the resource is thread-safe, in general, If only read operations are performed on a resource, the resource is thread safe without synchronization. If multiple threads perform read and write operations, thread synchronization is required to ensure thread safety.
What thread synchronization strategies do you know?
- OSSpinLock is no longer safe, except for this lock, the following locks will enter the thread sleep state while waiting, instead of busy etc
- Os_unfair_lock Atomic is used to ensure atomicity
- Pthread_mutex_t is a mutex and supports recursive and conditional implementations
- NSLock,NSRecursiveLock, the basic mutex,NSRecursiveLock supports recursive calls, all encapsulating pthread_mutex_t
- Lock NSCondition NSConditionLock, conditions, are also of pthread_mutex_t encapsulation
- Dispatch_semaphore_t semaphore
- @synchronized is also an encapsulation of pthread_mutex_t
37. What kinds of locks are there? How do they work? What’s the difference between them? It’s best to use it in context
- The spin lock. Spin lock attempts are constantly made when it cannot be locked. It is generally used in scenarios where the execution time of critical sections is short. However, iOS spin lock OSSpinLock is no longer safe, mainly because when low-priority threads get the lock, high-priority threads enter busy-wait state, consuming a lot of CPU time. As a result, the low-priority thread can’t get CPU time, so it can’t complete the task and release the lock. This problem is known as priority inversion.
- Mutex: Allows only one access to a resource at a time. NSLock is a mutex
- Read/write lock: Allows only one write or multiple read access to a resource. In iOS, pthread_rwlock is a read/write lock
- Conditional lock: Lock or unlock conditional conditions. NSConditionLock is used in iOS
- Recursive locks: Can be acquired multiple times by a thread without causing a deadlock. It records the number of times the lock was successfully acquired. For each successful lock acquisition, there must be a corresponding release lock so that a deadlock is not caused. Only after all locks have been released can another thread acquire the lock, which iOS can do using NSRecursiveLock
What is the difference between a linked list and an array? What is the time complexity of insert and query?
Both lists and arrays are ordered collections, arrays require contiguous memory space, while linked lists do not. The insertion and deletion time of linked lists is O(1), array is O(n), and query by subscript is O(1), list is O(n), and query by value is O(n).
39. How are hash tables implemented? How do I resolve address conflicts?
Hash table is also realized by array, first hash the key value to get an integer, and then calculate the integer to get the subscript in an array, and then access, address conflict resolution commonly used methods are open addressing and linked list method. The Runtime source code for the weak pointer hash table uses the open addressing method, and the Java HashMap uses the linked list method.
40. What can bubble sort, select sort, insert sort, quick sort (two way, three way) write?
Here under the simple said the difference between several quick sort, random fast row, is orderly, in order to solve the approximate time complexity will degenerate into O (n ^ 2), dual fast row is in order to solve the quick sort in the case of a large amount of data repeat, time complexity will degenerate into O (n ^ 2), three way fast row is in a large amount of data under the condition of repetition, An optimization of double – channel fast row.
- Bubble sort
extension Array where Element : Comparable{ public mutating func bubbleSort() { let count = self.count for i in 0.. <count { for j in 0.. "(the count - 1 - I) {if self [j] > self [m + 1] {(self [j], self [j + 1]) = (self [j + 1], the self [j])}}}}} to copy codeCopy the code
- Selection sort
extension Array where Element : Comparable{ public mutating func selectionSort() { let count = self.count for i in 0.. <count { var minIndex = i for j in (i+1).. <count {if self[j] < self[minIndex] {minIndex = j}} (self[I], self[minIndex]) = (self[minIndex], self[I])}}Copy the code
- Insertion sort
extension Array where Element : Comparable{ public mutating func insertionSort() { let count = self.count guard count > 1 else { return } for i in 1.. <count { var preIndex = i - 1 let currentValue = self[i] while preIndex >= 0 && currentValue < self[preIndex] { Self [preIndex + 1] = self[preIndex] preIndex -= 1} self[preIndex + 1] = currentValue}Copy the code
- Quick sort
extension Array where Element : Comparable{ public mutating func quickSort() { func quickSort(left:Int, right:Int) { guard left < right else { return } var i = left + 1,j = left let key = self[left] while i <= right { if self[i] < key { j += 1 (self[i], self[j]) = (self[j], self[i]) } i += 1 } (self[left], self[j]) = (self[j], self[left]) quickSort(left: j + 1, right: right) quickSort(left: left, right: j - 1) } quickSort(left: 0, right: Self.count-1)}} Copies the codeCopy the code
- Random fast row
extension Array where Element : Comparable{ public mutating func quickSort1() { func quickSort(left:Int, right:Int) { guard left < right else { return } let randomIndex = Int.random(in: left... right) (self[left], self[randomIndex]) = (self[randomIndex], self[left]) var i = left + 1,j = left let key = self[left] while i <= right { if self[i] < key { j += 1 (self[i], self[j]) = (self[j], self[i]) } i += 1 } (self[left], self[j]) = (self[j], self[left]) quickSort(left: j + 1, right: Right) quickSort(left: left, right: j-1)} quickSort(left: 0, right: self.count-1)}} Copies the codeCopy the code
- Dual fast row
extension Array where Element : Comparable{ public mutating func quickSort2() { func quickSort(left:Int, right:Int) { guard left < right else { return } let randomIndex = Int.random(in: left... right) (self[left], self[randomIndex]) = (self[randomIndex], self[left]) var l = left + 1, r = right let key = self[left] while true { while l <= r && self[l] < key { l += 1 } while l < r && key < self[r]{ r -= 1 } if l > r { break } (self[l], self[r]) = (self[r], self[l]) l += 1 r -= 1 } (self[r], self[left]) = (self[left], self[r]) quickSort(left: r + 1, right: right) quickSort(left: left, right: r - 1) } quickSort(left: 0, right: Self.count-1)}} Copies the codeCopy the code
- Three way fast row
// Extension Array where Element: Comparable{ public mutating func quickSort3() { func quickSort(left:Int, right:Int) { guard left < right else { return } let randomIndex = Int.random(in: left... right) (self[left], self[randomIndex]) = (self[randomIndex], self[left]) var lt = left, gt = right var i = left + 1 let key = self[left] while i <= gt { if self[i] == key { i += 1 }else if self[i] < key{ (self[i], self[lt + 1]) = (self[lt + 1], self[i]) lt += 1 i += 1 }else { (self[i], self[gt]) = (self[gt], self[i]) gt -= 1 } } (self[left], self[lt]) = (self[lt], self[left]) quickSort(left: gt + 1, right: Right) quickSort(left: left, right: lt-1)} quickSort(left: 0, right: self.count-1)}} Copies the codeCopy the code
41. Linked list question: How do I detect if there are rings in the linked list? How do I delete all nodes in a linked list that are equal to a certain value?
- How do I detect if there are rings in a linked list?
public class ListNode { public var val: Int public var next: ListNode? public init(_ val: Int) { self.val = val self.next = nil } } extension ListNode { var hasCycle: Bool { var slow:ListNode? = self var fast = self.next while fast ! = nil { if slow! === fast! { return true } slow = slow? .next fast = fast? .next? .next} return false}} Copy the codeCopy the code
- How do I delete all nodes in a linked list that are equal to a certain value?
func remove(with value:Int, from listNode:ListNode?) -> ListNode? { let tmpNode = ListNode(0) tmpNode.next = listNode var currentNode = tmpNode.next var persiousNode:ListNode? = tmpNode while currentNode ! = nil { if let nodeValue = currentNode? .val, nodeValue == value { persiousNode? .next = currentNode? .next }else { persiousNode = currentNode } currentNode = currentNode? .next} return tmpNode.next} copies the codeCopy the code
42. Array questions: How to find two elements in an ordered array whose sum equals a given value? How do I merge two ordered arrays and keep them ordered?
- How do I find two elements in an ordered array whose sum is equal to a given value? LeetCode 167 questions
func twoSum(_ numbers: [Int], _ target: Int) -> [Int] { var i = 0, j = numbers.count - 1 while i < j { let sum = numbers[i] + numbers[j] if sum == target { return [i + 1, J + 1]}else if sum > target {j -= 1}else {I += 1}} return []} copy codeCopy the code
- How do I merge two ordered arrays and keep them together? LeetCode 88 questions
func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) { for i in stride(from: n + m - 1, to: n - 1, by: -1) { nums1[i] = nums1[i - n] } var i = 0, j = 0 while i < m && j < n { if nums1[n + i] > nums2[j] { nums1[i + j] = nums2[j] j += 1 }else { nums1[i + j] = nums1[n + I] I += 1}} while I < m {nums1[I + j] = nums1[n + I] I += 1} while j < n {nums1[I + j] = nums2[j] j += 1}Copy the code
43. Binary tree: How to reverse a binary tree? How do I verify that two binary trees are exactly equal?
- How do I flip a binary tree? LeetCode 226 questions
func invertTree(_ root: TreeNode?) -> TreeNode? { guard let root = root else { return nil } (root.left, root.right) = (root.right, Root.left) invertTree(root.left) invertTree(root.right) return root} Copies the codeCopy the code
- How do I verify that two binary trees are exactly equal?
func isSameTree(_ p: TreeNode? , _ q: TreeNode?) -> Bool { guard let pNode = p ,let qNode = q else { return q == nil && p == nil } return pNode.val == qNode.val && isSameTree(pNode.left, qNode.left) && isSameTree(pNode.right, qNode.right) }Copy the code
Author: Li Kun Link: juejin.cn/post/684490… The copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.