What design principles are introduced and the application of open and close principles in the project is described in detail?

  • Single responsibility principle

  • Open and close principle: Category in OC, adding exchange methods through Runtime, etc., are open and close principle

  • Richter’s substitution principle

  • Interface Isolation Principle

  • Dependency inversion principle

  • Demeter’s rule

  • Combination/aggregation reuse principle

Introduce my past project experience, and ask some thinking about the structure of the project

Architecture addresses the growing business and functional requirements as the project gets bigger, the development team gets bigger and the application gets up and running. Good architecture often leads to rapid development efficiency and efficient code management. We can see that our architecture is always changing with the project, not fixed. First of all, our architectural design should bear in mind the design principles of software. Design principles guide us in designing easy-to-understand APIS and establishing proper dependencies. Common client architectures are

  • MVC

    1. The biggest advantage of MVC is the rapid development. In the early stage of the project, MVC can be used in pursuit of a quick launch, and Apple provides the official support of MVC. Therefore, it is undoubtedly the best choice to choose MVC in the early stage of the project.

    2. MVC is simple and easy to maintain even for less experienced developers.

  • MVP

    1. Very easy to test, because the View has very few features, it is very easy to test UI details
  • MVVM

    1. The advantage of MVVM is that tasks are evenly distributed and each part assumes its own responsibility. The structure is clear and more in line with software design principles

    2. Second is the testability, we just need to test the ViewModel can easily test the PROBLEMS on the UI

    3. Using observer mode for property binding, the amount of code is much smaller

  • VIPER

    1. Easy to test, clear blame, easier to test each part.

    2. The design is clearer and more compatible

    3. It also requires more team members, more code than the other architectures, and higher management requirements.

For component-oriented architecture, actually derived from the design ideas of the front end, routing plays a key role in the application of the front end SPA single page. The main function of routing is to ensure the synchronization of views and urls. From the front end’s perspective, a view is considered a representation of a resource. When users perform operations on the page, the application will switch between several interactive states. Routing can record some important states, such as the user viewing a website, whether the user logs in, and which page of the website the user visits. These changes are also recorded in the browser’s history, and users can switch status using the browser’s forward and back buttons. In general, the user can change the URL manually by typing or interacting with the page, then send a request to the server for resources synchronously or asynchronously, and redraw the UI after success. So we can apply this idea to iOS and Android as well. This ensures that each page is more independent and that we can quickly replace it with a Web page when we need a quick bug fix. Common routes include MGJRouter.


iOS

The process and principle of iOS compilation

There are two kinds of programming languages, compiled languages and literal languages

The compiler must first generate machine code, which can be directly executed on the CPU with high execution efficiency. Representative languages include C++, OC, Swift and so on

A literal language interprets code at execution time as code that can be executed by the CPU through an intermediate interpreter. Literal translation is less efficient than compiled languages, but more flexible to write.

Compilation in iOS is dependent on Clang(Swift) +LLVM compilation process preprocessing -> lexical analysis -> syntax analysis -> static analysis -> generate assembly instructions -> assembly -> link -> generate Mach-O file -> DYLD dynamic link -> dSYM

See here for details on how iOS compilation works

IOS static and dynamic libraries

Static libraries and dynamic libraries are relative to compile time and run time: static libraries are linked to the object code when the program is compiled, so the program does not need to change the static library when it is run. Dynamic libraries are not linked to the object code when the program is compiled, but are only loaded when the program is running, because dynamic libraries are needed during the program’s runtime.

  1. Static libraries: file name extensions are. A and. Framework.

  2. Dynamic libraries: file names are.tbd(formerly.dylib) and.framework. (The framework that the system provides to us directly is dynamic library!)

This section describes common attribute modifiers and the differences between assign and weak. This extends to memory-management concerns, such as the way reference counts are handled.

Common attribute modifiers: weak, assign, strong, copy, nonatomic, atomic

Assign: Generally used to modify basic data types, including basic and C data types. The assign attribute does not increase the reference count. After the assigned attribute is released, the attribute will not exist. If a new object is allocated to this memory address, it will crash again. Therefore, it is usually used only to declare basic data types.

Weak: weak reference and does not increase the reference count. Prevents cyclic references from being used, and the weak pointer is set to nil after the pointed object is freed. Weak references are usually used to deal with the problem of circular references, such as the use of proxies and blocks. Weak references are more commonly used.

When an attribute is modified with weak, the pointer is stored in a weak table, which is a hash table with obj as the key and a set of obj_weak addresses. When an attribute is configured with the weak modifier, the performance overhead is high.

Strong: Attributes modified by strong are not automatically released. In the OC, objects are strong Pointers by default. The strong reference count is automatically increased by 1.

Copy: When we copy an object, there are deep copies and shallow copies.

Deep copy: Object copy – directly copy content. The source object and the replica object refer to two different objects, the source object reference counter is unchanged, the replica object reference counter is 1.

Shallow copy: Pointer copy – Makes a copy of the address value in the pointer. Both the source object and the replica object refer to the same object, and the object reference counter +1 is equivalent to a retain.

Nonatomic: A nonatomic operation, as opposed to atomic. Atomic guarantees the integrity of getter/setter operations generated by the system. Note that getter/setter operations are only guaranteed here. Using atomic is not thread-safe and can cause errors when multiple threads operate on this property.

This section describes runloop knowledge and its application in actual development

A RunLoop, as the name suggests, is a running loop. Each thread has a RunLoop, which is created as needed. The RunLoop simply keeps the thread from exiting and handles events. Runloops are part of the thread infrastructure. Both Cocoa and CoreFundation provide Run Loop objects for configuring and managing thread Runloops. Each thread, including the main thread of the program, has a corresponding Runloop object.

int main(intargc,char* argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegateclass])); }}Copy the code

UIApplicationMain(), which sets an NSRunLoop object for the main thread so that it can rest when no one is working on it and respond when it needs to.

For other threads, runloop is not started by default, and can be configured and started manually if you need more thread interaction, but not if the thread is just going to perform a long, determined task.

In any Cocoa thread, you can retrieve the current thread’s runloop with the following code

NSRunLoop *runloop = [NSRunLoop currentRunLoop];
Copy the code

Runloop uses model to specify the priority of events in the running loop.

NSDefaultRunLoopMode (kCFRunLoopDefaultMode) : by default, idle UITrackingRunLoopMode: ScrollView sliding UIInitializationRunLoopMode: NSRunLoopCommonModes (kCFRunLoopCommonModes) : Set of modes at startupCopy the code

In practice, Runloop can be used to perform time-consuming operations, such as loading images from a TableView, and stopping timers from scrolling through the screen.

Detailed description of message forwarding process and event response chain is required

When you click on the screen it generates a touch event, and the system adds that event to an event queue managed by UIApplication, which takes the event from the message queue and distributes it. First it goes to UIWindow, and UIWindow will use the hitTest:withEvent: method to find the view where the touch event started, and once it finds that view, it’ll call the View’s touchesBegan:withEvent: method to handle the event. The event is sent as a message to the first responder, giving it the opportunity to process the event first. If the first responder does not process, the system passes the event (via message) to the next responder in the responder chain to see if it can process. In event passing, iOS responds to animation first and Android responds to events first

Control the click event or gesture added to it which responds first, and explain why

  1. When the control is a normal control such as UIView, the gesture event is first responded, but gestures take time, and the event is passed to the first response object in the response chain. Response chain UIResponder touchsBegan: withEvent method of gesture recognition after successful, would have to cancel all the response object is passed to the before, so I will call them touchsCancelled: withEvent: method.

  2. When the control is UIButton, UISwitch, UISegmentedControl, UIStepper, UIPageControl, in ios6 and above, to prevent overlapping events, the control event is responded first and gesture events are blocked. See click events and gesture conflicts for more details

Implementation principle of Block

struct Block_layout { void *isa; int flags; int reserved; void (*invoke)(void *, ...) ; struct Block_descriptor *descriptor; /* Imported variables. */ }; struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *); };Copy the code

Nsconcretestackblock: a Block object created on the stack _NSConcreteMallocBlock: Nsconcreteglobalblock: A Block object created on the heap. In the ARC environment, in most cases, the compiler makes appropriate judgments and automatically generates code that copies blocks from the stack to the heap. The principle is that when a __block structure is initialized, the original value becomes a member variable of the structure and the __forwarding pointer points to the structure itself. As with Block initialization, there are copy_helper and dispose_helper methods associated with the function Pointers byref_keep and byref_destroy, respectively, if necessary. Note that interviewers often ask how to capture automatic variables into blocks. We can see from the above source, block is actually anonymous function, and forbid to modify the automatic variable from the stack area, because the variable into the block is actually changing the scope of the variable, when switching between several scopes, if not add such restrictions, variable maintainability will be greatly reduced. So when we declare __block, we are actually moving the memory address of the variable from the stack to the heap. In turn, you can modify the values of external variables inside the block.

CoreAnimation and CoreGraphics

CoreGraphics is the CoreGraphics library, including Quartz2D drawing API CoreAnimation is the CoreAnimation library, used to do iOS, MAC related animation

Talk about the understanding of GCD, and how GCD is the bottom of the thread scheduling

IOS thread management is divided into pThread, NSThread, GCD, NSOperation pThread: POSIX standard, C – based universal cross-platform thread management API. NSThread: the earliest Apple thread management API NSOperation: object-oriented thread management API based on GCD GCD: replace NSThread, C language thread management API

GCD is a set of parallel programming frameworks provided by Apple to help developers improve the responsiveness of their applications. It provides an easy-to-use concurrency model that improves the potential for optimizing code under common design patterns, such as singleton patterns, which can be created using GCD to ensure that singleton is thread safe.

GCD has a thread pool layer that doesn’t need to be written by the developer. Threads in the thread pool are reusable and are destroyed after a certain period of time when the thread is not called. So all we need to do is add tasks to the thread queue, and the thread queue schedules. If synchronous tasks are stored in the queue, the underlying thread pool provides a thread for the task to execute after the task is queued. After the task is executed, the thread returns to the thread pool. Deposit if the queue is asynchronous tasks, when the task after the team, the underlying thread pool will provide a thread for task execution, because be executed asynchronously, the queue tasks can schedule does not need to wait for the current task has been completed the next task, then the underlying thread pool will once again provide a thread for the second task execution, execution after the return to the underlying thread pool. In this way, the thread completes a reuse, and does not need to open a new thread for each task execution, which saves the system overhead and improves efficiency.

The use of common methods in GCD (group, semaphore, barrier, etc

See the detailed usage

Explain how @synchronized locks work and what problems they may have. It also introduces the common locks in iOS development.

@synchronized encapsulates the mutex recursive lock. @synchronized(OBj) internally generates a recursive lock corresponding to OBJ, and locks and unlocks the lock. The biggest problem is that it is inefficient and the incoming object must wait for the previous lock to complete before it can be executed asynchronously.

There are also several common locking mechanisms:

  • NSLock: NSLock simply encapsulates a pthread_mutex internally with the attribute PTHREAD_MUTEX_ERRORCHECK

  • NSCondition: Conditional lock, implemented through the condition variable pthread_cond_t. Condition variables are a bit like semaphores, providing thread blocking and signaling mechanisms, so they can be used to block a thread, wait for some data to be ready, and then wake up the thread, such as the common producer-consumer pattern.

  • NSConditionLock: This is achieved with NSCondition, which is essentially a producer-consumer model.

  • NSRecursiveLock: Recursive lock, implemented by the pthread_mutex_lock function, which determines the lock type inside the function

  • Pthread_mutex_t: A mutex under a pthread. The mutex is implemented in much the same way as a semaphore. Instead of busy, the mutex blocks the thread and sleeps, requiring a context switch.

  • Dispatch_semaphore_t: semaphore.

  • OSSpinLock: spin lock, define a global variable, used to indicate the availability of the lock. The highest efficiency, but prone to lock priority reversal, resulting in lock insecurity.

Describe the situations in which you have used locks during your development.

Scenarios for using locks:

Such as downloading decompression, sorting display, loading multiple images and then combining the whole image after downloading and so on.

Why pages cannot be updated in asynchronous threads

Updating the UI in the child thread is an illusion: because the child thread completes its code execution, it automatically enters the main thread and executes the UI update stack in the child thread, which is very short, leading to the illusion that the thread can update the UI. If the child thread is always running, the function stack main thread for UI updates in the child thread is not known, that is, cannot be updated.

The principle of KVC and KVO is introduced in detail.

KVC leverages the Runtime dynamic mechanism to implement a set of methods for indirectly accessing properties by using property names

  • The program calls the setKey: property value method first, and the code sets it through setter methods. Note that the key here refers to the member variable name, and the initial case must conform to the KVC naming convention

  • If not found elegantly-named setName: method of KVC mechanism will check + (BOOL) have accessInstanceVariablesDirectly method returns YES, returned by default is YES, if you rewrite the method is to make its return NO, So at this step KVC will execute the setValue: forUndefineKey: method, but it usually doesn’t. So the KVC mechanism searches for a member variable named _key in that class, and regardless of whether the variable is defined in a.h or a.m file, and regardless of the access modifier, KVC can assign a value to any member variable named _key.

  • If the class has neither a setKey: method nor a _key member variable, the KVC mechanism searches for the _isKey member variable.

  • Similarly, if the class has no setKey: method and no _key and _isKey member variables, KVC will continue to search for key and isKey member variables and assign them values.

  • If none of the methods or member variables listed above exist, the setValue: forUndefinedKey: method of the object is executed, and the default is to throw an exception.

KVO Chinese name is called key-value observation, which belongs to the observer mode of design mode. Simply put, it is to add an attribute of the observed object A. When the attribute of the observed object A changes, the observed object will be notified and make corresponding processing. The underlying layer of KVO is implemented through ISa-Swizzling.

In OC, each object has a pointer named ISA to the object’s class. Each class also describes its instance characteristics, such as a list of member variables, a list of member functions. Each object can receive messages, and the list of messages that an object can receive is stored in its corresponding class. NSObject isa structure that contains a pointer to isa. Each instance object has a pointer to ISA that points to the object’s Class, and the Class has a pointer to ISA that points to meteClass. Similarly, a metaclass is a class. It’s an object. Metaclasses also have isa Pointers, which ultimately point to a root metaclass whose ISA pointer points to itself, forming a closed inner loop.

Isa-swizzling, on the other hand, dynamically changes the value of the ISA pointer at run time to replace the entire behavior of the object.

Problems and solutions exist in the process of using Webview

Cookie problem: UIWebView cookies are uniformly managed by NSHTTPCookieStorage. They are written when the server returns and read when the request is made. The Web and Native can share cookies through this object

On WKWebView, NSHTTPCookieStorage is no longer a necessary process node. Although WKWebView also writes cookies to this object, it is not real-time, and the latency varies according to different system versions. Cookies are not read in real time when the request is made. As a result, cookies will be lost every time the APP restarts, and session and Native synchronization cannot be achieved. This can be resolved through OAuth2 protocol.

Functional problem: WkWebView view size problem, default jump is shielded, manual interaction is required. Download links require special handling, cache issues

How JSBridge is implemented and the invocation relationship with native.

JavaScript is run in a separate JS Context (e.g., WebView’s Webkit engine, JSCore). Due to the natural isolation of these contexts from the native runtime environment, JSBridge is implemented

  1. Communication calls Native to communicate with JS
  2. Handle resolution calls.

Js and native communication

Jsbridge mainly realizes communication with Native by injecting API and intercepting URL scheme.

  1. API injection is to inject objects or methods into JavaScript Context through the interface provided by WebView, so that when JavaScript is called, the corresponding Native code logic can be directly executed to achieve the purpose of JavaScript calling Native.
  2. Interception scheme, not very elegant, abandoned.
  3. Native JavaScript call is actually to perform the splicing of JavaScript strings and call methods in JavaScript from the outside. Therefore, JavaScript methods must be on the global window.

Talk about the understanding and function of Bitcode.

Bitcode is an encoding of the intermediate code of the LLVM compiler, which compiles programming languages such as C/C++/OC/Swift into assembly instructions or executable machine instruction data on the chip platform. BitCode is the code directly in between. Because of the existence of intermediate codes, it is easy to create new languages or construct new instruction outputs. Bitcode is just an intermediate code that doesn’t work on any platform, but it can be converted to any supported CPU architecture, including CPU architectures that haven’t been invented yet, which means turning on Bitcode now and submitting an App to the App Store, and later if Apple releases a new phone with a completely new CPU design, on Apple If the background server can also start compiling from the App’s Bitcode into an executable program on the new CPU, which can be downloaded and run by new mobile phone users.

APM (Performance Monitoring)

Details refer to the

Introduce the realization principle of tripartite library which I am familiar with

AFNetworking, SDWebImage YYkit, FFMpeg, etc

Practical development issues related to AFNetworking and SDWebImage.


network

This section describes the HTTPS process in detail.

The client initiates an Https request -> intermediate CDN, Load balancing node forwarding and so on -> Connect to Server443 -> The server needs to configure Https protocol certificate -> Transfer certificate -> client parse certificate -> transmit encrypted information -> server parse encrypted information -> transmit encrypted information -> client restore decrypted information.Copy the code

If you are making a new network layer framework now, what points need to be considered

  1. Conifg that can be used globally and configured individually.

  2. Cache processing, cache method, cache validity period, cache key.

  3. Repeat network request processing.

  4. Network request release interrupt processing.

Determine if a string is an ipv6 address (do your best to consider all exceptions)

A) Whether a string is a valid IPv4 or IPv6 string

We can consider whether the string is an IPv4 string or an IPv6 string, respectively.

B. It is slightly harder to determine whether a string is an IPv4 string than an IPv6 string.

IPv4 consists of four numeric segments with three ‘.’ symbols, each ranging from 0 to 255, and each valid number (no leading zeros).

So we can separate the string with a ‘.’, count the number of ‘.’, and determine whether each number is valid.

Note that leading zeros are not allowed in each digit of an IPv4 string, but individual zeros are allowed.

C. The procedure for checking IPv6 is similar to that for IPv4. Split and determine the number of separators, and check each number in turn.

The IPv6 address does not need to determine the leading zeros, but it is valid in case.


To optimize the

What optimization work has been done in the past development, ask more detailed.

The reason for the lag is that, during a refresh time in the vSYNC mechanism, the CPU or GPU work has not completed the content submission, and this frame will be discarded. The screen will keep the display of the previous frame, and the lag will be visible to the naked eye if the interval is too long.

The common optimization schemes are:

  1. Cell reuse,

  2. Cell height calculation is time-consuming. Cache the height.

  3. Reduce the view hierarchy and use Layer to draw elements.

  4. For pictures, try to use determinate size pictures, reduce dynamic scaling, sub-thread pre-decoding. Multithreaded download image fragments, merge display.

  5. Reduce transparent View

  6. Reduce off-screen rendering

  7. Use rasterization wisely

  8. Asynchronous Rendering (Facebook Framework AsyncDisplayKit)

An understanding of memory leaks and a solution to the problem.

Memory leakage means that the requested memory space is not reclaimed after it is used up. A memory leak can be ignored, but if it continues, no matter how much memory there is, it will be used up sooner or later, and eventually cause the program to crash.

In iOS, we can use the Leaks tool in Instrument to detect memory leaks and optimize.

The main possible causes of leakage are circular references to blocks, delegates, etc.

How to detect lag in projects (such as suspended animation)

  • Core Animation, A graphical performance test tool for Instruments.

  • View debugging, Xcode built-in, view level.

  • Reveal: view hierarchy.

How to load a large memory image like a map (just say the implementation idea)

Use CATiledLayer to load the large image, and tile Layer to set a set of zoom areas and redraw threshold, so that when the Scroll View is scaled, the drawing layer will redraw the currently displayed area according to these areas and the zoom threshold


Video image audio

Knowledge of image codec

I’m going to write it later


# algorithm

Palindrome algorithm

Checks whether an integer is a palindrome. Palindromes are integers that read in positive (left to right) and backward (right to left) order. Determine if a string is symmetric, such as ABBA or ABA.

  1. Invert the output of positive integers against the original data, such as 123321, invert the original data by modulo cofactor, which is a palindrome if it is equal, and finally return two possible cases (numbers only) with an or state.

  2. Convert to a string and check whether it is a palindrome by comparing the shift of the palindrome string.

This section describes the principles of the hash algorithm

Hash is similar to a structure that maps values to another space and stores data in key-value indexed, so we can find the corresponding value just by inputting the value to be searched namely key. By the hash function will be find the index into an array of key, in the ideal case, the keys will be converted to different index value, but in some cases we need to deal with multiple keys are hash to the same index value, so the hash lookup the second step is to handle conflict is the hash collision.