This column will be updated continuously — please pay attention to iOS friends!
(The answer is not unique, only for reference, there are benefits at the end of the article)
61: What is ARC?
ARC (Automatic Reference Counting) is an Objective-C memory management mechanism. In short, retain/release is automatically added to the code, and the code that used to be added manually to handle reference counts for memory management can be automatically done by the compiler.
ARC is used to solve the problem of matching an object’s retain and release. The old problems of manual management causing memory leaks or repeated releases will no longer exist.
Previously, we needed to manually acquire memory for the object with retain and release. Therefore, the previous operation is called Manual Reference Counting (MRC).
62: The underlying principle of ARC, how to achieve automatic release, and what is the difference between MRC?
-
By default, local variables are strong Pointers and stored in the heap. However, strong Pointers to local variables are released after the end of the code block, and the corresponding memory space to which they point is also destroyed.
-
MRC is not strong, weak, and local variable objects are equivalent to basic data types. When MRC assigns a value to a member attribute, it must use the set method. It is not possible to directly access the underline attribute assignment, because using the underline is a direct assignment (such as _name = name), while the set method will do more things that affect the reference count, such as retain.
63: Why did Apple introduce ARC?
-
In MRC era, if we want to keep an object, we only need “retain”. ARC is no longer needed. Now you only need to use a pointer to the object. There are two cases: first, if the pointer is null, the object is freed. Second: the pointer is not empty, the object will always be stored in the heap, if the pointer points to a new value, the original object will be released once, the system will do that for us at the appropriate time, we don’t have to care.
-
In ARC, the object pointer is freed whenever it is set to null. Otherwise, the object will remain on the heap. When a pointer to a new value is set, the original object is released once.
Why do you think you need runloop when you have threads? , what does runloop have to do with threads?
When a thread’s runloop is turned on, the thread will go to sleep after executing a task, and it will wake up to execute the task.
More on the relationship between the two:
- A runloop corresponds to a core thread. The reason why it is called a core thread is that runloops can be nested, but there can only be one core thread. Their relationship is stored in a global dictionary.
- The runloop is created when it is first fetched and destroyed when the thread ends.
- For the main thread, the runloop is created by default as soon as the program starts.
- For the child thread, the runloop is lazily loaded and created only when we use it, so be careful when using a timer for the child thread: make sure the runloop is created for the child thread, otherwise the timer will not call back.
Sixty-five: What happens when objC sends a message to a nil object?
First, two questions need to be understood:
- What is an ISA pointer
- Messaging mechanism
An isa pointer isa pointer for an object to a class object, which points to a metaclass object. The class object and metaclass object respectively store object methods and class methods. In the messaging mechanism, the isa pointer is used to find the actual call address of the method.
When objc sends a message to an object, the Runtime library finds the actual class of the object based on the object’s ISA pointer, and then looks for methods to run in the list of methods in that class and the list of methods in its parent class. When objc_msgSend sends a message, the method returns no value. The so-called return content is the specific call at the time of execution. So, back to the point, if you send a message to a nil object, the first thing you’re looking for is an ISA pointer to the object and it’s returned at zero, so you don’t get any errors.
Sixty-six: Common design patterns
1 proxy mode application scenario: When some functions of a class need to be implemented by another class, but it is uncertain which class will implement them. Advantage: Decouple agile principles: Open – close principles
Example:
- The TableView data source delegate, in coordination with the protocol, accomplishes the delegate request.
- List ROW number delegate
- Custom delegate
2 application scenario of observer mode: Generally, the model layer notifies the controller and view. It does not care who receives the information, but only publishes the information. Advantages: Decoupling Agile principles: Interface isolation principle, open – close principle
Example:
- Notification. Messages can be sent anywhere and can be received by objects registered as observers.
- Kvo, the observer of key-value pair change notifications, is rarely used.
3 MVC pattern application scenario: is a very old design pattern, through the data model, controller logic, view display to logically divide the application. Advantages: Makes the system, hierarchy clear, responsibilities clear, and easy to maintain agile principles: open to extension – closed to modification
Example:
- Model-data model, View-view display, and Controller-logical control of UI display and data interaction.
4 Application scenario of the singleton mode: Ensure that only one instance of a class is available during the program running. The instance is used for resource sharing control. Advantages: Simple to use, delayed evaluation, easy to cross module Agile principle: Single responsibility principle
Example:
- [UIApplication sharedApplication].
Note: Make sure that the only instance of a singleton class is available to the consumer only through the getInstance method. Java, C++ make it without public constructors, make it private and override its constructors. In Object C, override the allocWithZone method to ensure that even if the user directly creates an instance of the singleton using the alloc method,
The only static variable returned is the singleton class.
5. Policy mode application scenario: Define a family of algorithms and encapsulate them to make them interchangeable. Advantages: Make the changes of the algorithm independent of the users using the algorithm agile principles: interface isolation principle; More combination, less inheritance; Program for interfaces, not implementations.
Example:
- Sorting algorithm, NSArray’s sorting selector; The classic duck can quack and fly case.
Note: 1. Strip the mutable behavior from the class and embed it in the abstract base class 2. 3. The final instance of the user class. By injecting the behavior instance, the variable behavior is set to prevent the inheritance behavior mode, resulting in irrelevant behavior pollution to the subclass. Policy encapsulation and replaceability are achieved.
6 Application scenario of the factory mode: The factory mode can be used to create class instances. In most cases, the factory mode works with the proxy mode to create surrogate classes. Advantages: Easy to replace, oriented to abstract programming, Application only calls to abstract factories and generic abstract classes of mutable classes. Agile principles: DIP relies on the inversion principle
Example:
- If the project deployment environment depends on multiple databases of different types, use the factory and proxy to complete ease-of-use replacement
Caution: Early in the project, when the software structure and requirements are not stable, this pattern is not recommended because it has obvious disadvantages, such as increased code complexity, increased call hierarchies, and increased memory burden. So be careful to prevent abuse of patterns.
67: What are the disadvantages of single meeting?
Main advantages:
- Provides controlled access to a unique instance.
- 2. Because there is only one object in the system memory, system resources can be saved. For some objects that need to be frequently created and destroyed, singleton mode can undoubtedly improve the system performance.
- Allow a variable number of instances.
Major disadvantages:
- 1. Because there is no abstraction layer in the simple interest pattern, the extension of singleton classes is very difficult.
- 2. Singletons have too much responsibility, which violates the “single responsibility principle” to some extent.
- 3. The abuse of singleton will bring some negative problems. For example, in order to save resources, the database connection pool object is designed as a singleton class, which may lead to the overflow of connection pool due to too many programs sharing the connection pool object. If an instantiated object is not used for a long time, the system will consider it garbage and collect it, resulting in the loss of the object’s state.
Sixty-eight: How do you store sensitive information about users, such as login tokens
Keychains are used to store keys. To use keychains, you need to import the Security framework
The iOS Keychain service provides a secure way to store private information (such as passwords, serial numbers, and certificates). Each iOS application has an independent keychain. Compared with common methods such as NSUserDefaults and file saving, keychain storage is more secure. In addition, information stored in the keychain is not lost when an App is deleted. Therefore, data in the keychain can still be used after the App is reinstalled. Starting with iOS 3.0, it became possible to share keychain across applications.
To use keyChain in an application, we need to import the Security. Framework. The keyChain interface is declared in the secitem.h header file. To directly use the methods in secitem. h to operate keychain, the code required to write is relatively complex. In order to reduce the development of our programmers, we can use some encapsulated tool classes. KeychainItemWrapper and SFHFKeychainUtils.
Customize a keychain class
CSKeyChain.h
1. @interface CSKeyChain : NSObject
2.
3. + (NSMutableDictionary *)getKeychainQuery:(NSString *)service;
4.
5. + (void)save:(NSString *)service data:(id)data;
6.
7. + (id)load:(NSString *)service;
8.
9. + (void)delete:(NSString *)service;
10.
11. @end
Copy the code
CSKeyChain.m
1. #import "CSKeyChain.h" 2. #import<Security/Security.h> 3. 4. @implementation CSKeyChain 5. 6. + (NSMutableDictionary *)getKeychainQuery:(NSString *)service { 7. return [NSMutableDictionary dictionaryWithObjectsAndKeys: 8. (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass, 9. service, (__bridge_transfer id)kSecAttrService, 10. service, (__bridge_transfer id)kSecAttrAccount, 11. (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible, 12. nil]; + (void)save (NSString *)service data (id)data {16. // Get the search dictionary 17.nsmutableDictionary *keychainQuery = [self getKeychainQuery:service]; 19. SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); 20. / / add a new object to a string 21. [keychainQuery setObject: [NSKeyedArchiver archivedDataWithRootObject: data] forKey:(__bridge_transfer id)kSecValueData]; 23. SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL); 24. } 25. 26. + (id)load:(NSString *)service { 27. id ret = nil; 28. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 30. [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData]; 31. [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit]; 32. 33. CFDataRef keyData = NULL; 34. 35. if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { 36. @try { 37. ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData]; 38. } @catch (NSException *e) { 39. NSLog(@"Unarchive of %@ failed: %@", service, e); 40. } @finally { 41. } 42. } 43. 44. return ret; 45. } 46. 47. + (void)delete:(NSString *)service { 48. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 49. SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); 50. } 51. 52. @endCopy the code
- In other classes to store, load, delete sensitive information methods
2. Static NSString * const KEY_IN_KEYCHAIN = @"com.cs.app.allinfo"; 4. Static NSString * const KEY_PASSWORD = @"com.cs.app.password"; 5. 6. + (void)savePassWord:(NSString *)password { 7. NSMutableDictionary *passwordDict = [NSMutableDictionary dictionary]; 8. [passwordDict setObject:password forKey:KEY_PASSWORD]; 9. [CSKeyChain save:KEY_IN_KEYCHAIN data:passwordDict]; 10. } 11. 12. + (id)readPassWord { 13. NSMutableDictionary *passwordDict = (NSMutableDictionary *)[CSKeyChain load:KEY_IN_KEYCHAIN]; 14. return [passwordDict objectForKey:KEY_PASSWORD]; 15. } 16. 17. + (void)deletePassWord { 18. [CSKeyChain delete:KEY_IN_KEYCHAIN]; 19.}Copy the code
How is UIScrollView implemented? How does it capture and respond to gestures?
When the UIScrollView is scrolling, it is actually modifying the origin coordinates. When the finger touches, the Scroll View will temporarily intercept the touch event, using a timer. Scroll View sends tracking events to the subview that was clicked if there is no finger movement event after the timer expires. If a move event occurs before the timer expires, the Scroll View will not scroll itself.
UIScrollView receives and processes touch events:
-
UIScrollView should reload the hitTest method and always return itself. So all touch events will go into itself. The internal Touch event detects if the event is related to itself and either processes or passes it to the internal View.
-
To detect whether the touch is processing or passing, the UIScrollView generates a timer when the touch occurs.
- If the touch does not move within 150ms, it passes this event to the internal view
- If the touch moves within 150ms, start scrolling, and will not pass to the internal view. (For example, when you touch a table, direct scrolling means that the line you touched will never highlight.)
- CanCancelContentTouches = YES if the Touch doesn’t move within 150ms and the UIScrollView starts passing an internal View event, but moves far enough The UIScrollView calls the touchesCancelled method, cancellations the internal view’s response, and starts scrolling. (for example, if you touch a table, stop scrolling for a while, and start scrolling, that row will be highlighted first, but then no longer scrolling.)
70: How to achieve night mode?
-
1. Prepare two sets of resources, one for day mode and one for night mode.
-
2. Save a variable (BOOL isNight) globally and change the value of the variable according to the user’s operation;
-
3. Add each view and ViewController that needs to be changed to the notification center and listen for events (NeedTransferToNight and NeedTransferToDay);
-
4. The default mode is daytime, isNight = YES.
-
5. When the user clicks the night button, if isNight == YES, the value of this variable is set to NO, and the notification center issues NeedTransferToNight notification, all views and ViewControllers that need to be changed will use the night resource to redraw themselves when listening to this event. If isNight is YES during initialization, other views will initialize themselves using the night resource. (and vice versa)
-
6. Run the program to see the night mode.
Seventy-one: How to catch exceptions?
- In the app starts (didFinishLaunchingWithOptions), add an exception capture listening in.
1.- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
2. // Override point for customization after application launch.
3.
4. NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
5.
6. return YES;
7.}
Copy the code
- Implement a method to catch the exception log and save it locally.
1. Void UncaughtExceptionHandler(NSException *exception){2. 3 callStackSymbols]; 5. NSString *reason = [exception reason]; 6. NSString *name = [exception name]; 7. 8. NSString *excpCnt = [NSString stringWithFormat:@"exceptionType: %@ \n reason: %@ \n stackSymbols: %@",name,reason,excpArr]; 9. 10. / / daily log saved (you can use this function separate refining to a method) 11. NSArray * dirArr = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); 12. NSString *dirPath = dirArr[0]; 13. NSString *logDir = [dirPath stringByAppendingString:@"/CrashLog"]; 14. 15. BOOL isExistLogDir = YES; 16. NSFileManager *fileManager = [NSFileManager defaultManager]; 17. if (! [fileManager fileExistsAtPath:logDir]) { 18. isExistLogDir = [fileManager createDirectoryAtPath:logDir withIntermediateDirectories:YES attributes:nil error:nil]; If (isExistLogDir) {22. // You can extend 23. NSString *logPath = [logDir] stringByAppendingString:@"/crashLog.txt"]; 24. [excpCnt writeToFile:logPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 25. 26}.}Copy the code
72. Relationship between frame and Center bounds
-
The frame property is the positioning coordinate relative to the parent container.
-
The bounds property is specific to itself, specifying the size bounds, with the default point being (0,0), and the width and height being equal to the frame width and height.
-
The Center property is for the center point coordinates associated with the Frame property.
-
As the frame changes, bounds and center change accordingly.
-
When the bounds change, the frame is reset based on the width and height of the new bounds without changing the center.
-
Center is always related to the frame, specify the center coordinates of the frame!
Seventy-three: How is breakpoint continuation implemented?
The understanding of breakpoint continuation can be divided into two parts: one is breakpoint, the other is continuation. A breakpoint occurs when a download file is divided into several parts and the download is performed simultaneously. When the task is suspended at a certain point in time, the point where the download is suspended is called a breakpoint. A continuation is when an unfinished download resumes, continuing from the last break point.
When using multi-threaded breakpoint to continue the download, the download or upload task (a file or a compressed package) is artificially divided into several parts, each part adopts a thread to upload or download, multiple threads concurrent can occupy more resources on the server, thereby speeding up the download speed.
In the process of downloading (or uploading), if the download is interrupted due to network failure, low power, etc., it is necessary to use the resumable function. The next time you start, you can start from the record location (the part that has been downloaded) and continue to download the part that has not been downloaded in the future to avoid duplicate downloads. Resumable is essentially a record of where the last download was completed.
The process of resuming a breakpoint
- 1. The download progress of each thread should be recorded during the download process for resumable transmission.
- 2. Read the database before each download, and query whether there are unfinished records. If there are, continue to download, and if there are no records, create new records and insert them into the database;
- 3. Update the download progress in the database each time data is written to the file.
- 4. Delete the download records from the database.
Seventy-four: Notification, agents, KVO differences, and multithreading issues of notification
1. delegate
When we first wrote an ios app, we noticed the constant use of “delegates” throughout the SDK. The Delegation mode is not IOS specific, but rather relies on the programming background you’ve had in the past. It may not be obvious what it’s good for and why it’s used so often.
The basic characteristic of Delegation is that a controller defines a protocol (that is, a set of method definitions). This protocol describes what a delegate object must do in order to be able to respond to a controller’s events. The protocol is that the delegator says, “If you want to be my delegate, then you have to implement these methods.” Implementing these methods allows the Controller to call these methods in its delegate, and its delegate knows which methods to call when. A delegate can be any object type, so the controller is not coupled to an object, but when that object tries to tell the delegate something, the object can determine that the delegate will respond.
Delegate advantages:
- 1. Very strict grammar. All events to be heard must be clearly defined in the Delegate protocol.
- 2. Compile warning/error if a method in the delegate is not implemented
- 3. The protocol must be defined within the scope of the controller
- 4. The control flow in an application is traceable and identifiable;
- 5. There are many different protocols defined in a controller, each of which has different delegates
- 6. No third party object is required to maintain/monitor the communication process.
- 7. Can receive the return value of the called protocol method. This means that the delegate can provide feedback to the controller
Disadvantages:
- 1. A lot of code to define: 1. Protocol definition; 2. Controller delegate property; 3. Implement the delegate method definition in the delegate itself
- 2. When releasing proxy objects, you need to be careful to change delegate to nil. If the setting fails, then the method that calls the free object will crash the memory
- 3. If there are multiple delegates in a controller and the delegates follow the same protocol, it is still difficult to tell multiple objects the same event, but it is possible.
2. notification
There is a concept in iOS app development called the Notification Center. It is a singleton that allows some objects to be notified when an event occurs. It allows us to satisfy the controller’s purpose of communicating with an arbitrary object with a low degree of coupling. The basic feature of this pattern is to allow other objects to receive messages that are generated by an event occurring in the controller, which uses a key (notification name). This is anonymous to the controller, and other objects that register the notification using the same key (i.e., observers) can react to the notified event.
Notification advantages:
- 1. Not much code to write, simple implementation;
- 2. For a given notification, multiple objects can respond, that is, 1 to many way to achieve simple
- 3. Controllers can pass a Context object (dictionary) that carries custom information about sending notifications
Disadvantages:
- 1. Does not check whether notifications are handled correctly by observers at compile time;
- 2. Before releasing the registered object, cancel the registration in the notification center.
- 3. It is difficult to track the application work and control process during debugging;
- 4. Third-party preferences are required to manage the connection between controller and observer objects;
- 5. The controller and observer need to know the notification name and UserInfo Dictionary keys in advance. If these are not defined in the working interval, they will be out of sync;
- 6. The controller cannot get any feedback from the observer after the notification has been sent
3. KVO
KVO is the ability of one object to observe the value of a property of another object and to detect changes in the value. While the first two modes are more suitable for a controller to communicate with any other object, KVO is more suitable for any type of object to listen for changes to any other arbitrary object (in this case, it can also be a controller, but usually not a controller). This is a way of keeping one object in sync with another, by observing how one object reacts when the state of the other changes. It can only be used to react to attributes, not methods or actions.
Advantages:
- 1. Provides a simple way to achieve synchronization between two objects. For example, synchronizing between model and view;
- 2. To be able to respond to state changes in objects not created by us, namely internal objects, without changing the implementation of internal objects (SKD objects);
- 3. The latest and previous values of the properties that can be provided for observation;
- 4. Use key Paths to view properties, so you can also view nested objects;
- 5. The observation object is abstracted because no additional code is required to allow the observations to be observed
Disadvantages:
- 1. The properties we observe must be defined using strings. So there are no warnings or checks in the compiler;
- 2. Refactoring the properties will cause our observation code to no longer be available;
- 3. Complex “IF” statements require that the object is observing multiple values. This is because all the observation code is directed through a method;
- 4. There is no need to remove the observer when releasing it.
Conclusion:
-
From the analysis above, we can see that each of the three design patterns has its own advantages and disadvantages. In fact, any kind of things are like this, the problem is how to choose the right thing in the right circumstances at the right time. Here’s how to play to their strengths and which models to use in which situations. Note that there is no right or wrong way to use either pattern, only more or less appropriate. Each pattern provides a way for an object to notify other objects of an event, and the former does not need to know the listener. Of the three models, I think KVO has the clearest use case and clear practicality for a particular requirement. The other two modes have similar uses and are often used to communicate between controllers. So where do we use one of these?
-
In my experience developing iOS apps, I’ve found that notifications are used a little too much. Personally, I’m not a big fan of using notification centers. I find it difficult to keep track of the application’s execution flow with notification centers. Passing the Keys around for UserInfo Dictionaries lost synchronization, and too many constants needed to be defined in public space. For a developer working on an existing project, it can be difficult to understand the application process if the notification center is overused.
-
I find it easy to clearly understand the communication between controllers with good protocol and protocol method definitions using naming conventions. Trying to define these protocol methods will improve the readability of your code and make it easier to track your app. Proxy protocol changes and implementations can be checked by the compiler, and if not there will be at least a crash during development, rather than just making something work abnormally. Even in scenarios where multiple controllers are notified of the same event, as long as your application is well structured at the controller level, messages will be delivered at that level. This level can be passed back until all controllers who need to know the event know it.
-
Of course there are exceptions where the Delegation pattern doesn’t fit, and notification might be more effective. For example, all controllers in an application need to know an event. Yet these types of scenarios are rare. Another example is when you set up an architecture and need to notify the event to the running application.
-
As a rule of thumb, I only use observations when it comes to property-level time, whether it’s in an object that doesn’t need programming or in a Model object tightly bound to a View object. For the rest of the events, I’ll use the Delegate mode. If for some reason I can’t use a delegate, the first thing I’ll do is estimate whether there’s something seriously wrong with my app architecture. If there are no errors, then notification is used.
75: How do you generally optimize your APP?
First, the home page start speed
-
Do as little as possible during startup (merge as many interfaces as possible)
-
No time-consuming operations on the UI thread (data processing is performed on the child thread, and the main thread is notified to refresh after processing)
-
Start background tasks at the right time (for example, in a user guide program you can start preparing data for loading)
-
Minimize the size of the packet
-
Optimization method:
- Quantization start time
- Starting speed modularization
- Accessibility Tools (Umeng, Listening Cloud, Flurry)
Second, page browsing speed
- Json processing (iOS built-in NSJSONSerialization, Jsonkit, SBJson)
- Data paging (if there is more data in the back end, it should be returned in paging, such as netease News, or Microblog records)
- Data compression (big data can also be compressed back to reduce traffic and speed up response)
- Content cache (for example, the latest news list of netease News should be cached to the local, loaded from the local, can be cached to memory, or database, depending on the situation)
- Delayed TAB loading (for example, if the app has 5 tabs, you can load the first TAB to be displayed, and the others can be loaded at display time and on demand)
- Optimization of the algorithm (optimization of the core algorithm, for example, some apps have a contact name sorted with the first letter of Chinese pinyin)
Three, operation fluency optimization:
- Tableview Optimization (Load optimization of Tableview Cell)
- ViewController load optimization (jump between different views, so data can be prepared in advance)
Four, database optimization:
- Database design refactoring above
- Query statement optimization
- (If there is too much data, you can divide it into different tables or libraries)
V. Interaction optimization between server and client:
- Clients minimize requests
- The server does as much logical processing as possible
- A combination of push and pull on the server and client (some synchronization mechanisms can be used)
- Optimization of communication protocol. (Reduce packet size)
- Power usage optimization (try not to use background running)
Vi. Non-technical performance optimization
- Logic of product design (the design of the product must be logical, or the logic should be as simple as possible, otherwise it will make the programmer crazy, sometimes it takes a lot of effort to complete a small logical design problem)
- Specification of interface interaction (interface interaction of each module should be unified as far as possible to conform to operation habits)
- Code specification (this can lead to stealthetly improved app performance, such as using if else or switch, or using! Or = =)
- Code Review continues to refactor code. Reduces the logical complexity of the code)
- Daily communication (often sharing some code or logic processing pits)
76: Push Notification principle
Local push: you don’t need to be connected to the Internet to push. Developers set specific times in the APP to remind users what to do
Remote push: When networking is required, the user’s device will form a persistent connection to the Apple APNS server, and the user’s device will send the UUID and Bundle The IdenIdentifier is given to the Apple server, and the Apple server will encrypt and generate a deviceToken for the user’s device, and then the device will send the deviceToken to the APP’s server, and the server will store the deviceToken in their database, and then if someone sends a message to me, the server The terminal will query my deviceToken, and then send the deviceToken and the information to be sent to the Apple server. The Apple server will find my device through the deviceToken and push the message to my device. There is another case here, if the APP is online, then the APP server will generate one for the APP In this case, the APPF server will push the message directly to the device through the deviceToken
Seventy-seven: How many ways to introspect in iOS?
The ability of an object to get its type at run time is called introspection. Introspection can be done in a number of ways.
OC runtime introspection four methods:
Determine the object type:
2. -(BOOL) isMemberOfClass: Indicates whether the class is an instance of this class or a subclass of this classCopy the code
Determine if the object/class has this method
(1) - (BOOL) respondsToSelector: interpretation instance such method 2. + (BOOL) instancesRespondToSelector: to determine whether a class with this methodCopy the code
In Objective-C, the ID type is similar to (void*) and can point to an object of any class, but at run time the object’s type is no longer ID, but the class to which the object actually belongs.
1. Person *person = [[Person alloc] init]; 2. NSArray *arr = @[person]; 3. id obj = arr[0]; 5. BOOL isPersonClass = [obj isKindOfClass: [Person class]]; 6. Determine whether obj is an object of type Person or a subclass of Person.Copy the code
In Objective-C, a pointer defined by a parent type can point to an object in its subclass, but at runtime the real type of the object will be the subclass.
Person *p = [Boy alloc] init]; Person *p = [Boy alloc] init]; BOOL isBoy = [p isMemberOfClass: [Boy class]]; 4. Determine if p of type Person * is of type Boy.Copy the code
78: What’s the difference between a class method and an objc_getClass method?
1. When obj is an Object instance Object, object_getClass(obj) and [obj class] output results are both consistent, the ISA pointer is obtained, that is, the pointer to the class Object.
2. If obj isa Class object, object_getClass(obj) returns the isa pointer in the Class object, that is, the pointer to the metaclass object. [obj class] returns itself.
3. If obj isa Metaclass object, object_getClass(obj) returns an isa pointer to the Metaclass object, because the isa pointer to the Metaclass object points to the root class. [obj class] returns itself.
Object_getClass (obj) returns a pointer to the root metaclass address of the root metaclass object. [obj class] returns itself.
Object_getClass (obj) returns a pointer to isa in obj; When obj is an instance object, the class in [obj class] is the instance method: – (class)class, returns the isa pointer in the obj object; Second, when obj is a Class object (including metaclass and root and root metaclass), the Class method is called: + (Class) Class, and the result returned is itself.
The difference between an int variable being __block or not?
1. Undecorated, captured by block, is a value copy. 2. __block is used to generate a structure that copies the address of the int reference. The modified data is achieved.Copy the code
1. Block intercepts automatic variable (local variable) values
For variable references outside the block, the block by default copies them into its data structure to access them. In other words, the automatic variable interception of a block only applies to the automatic variable used inside the block. If the automatic variable is not used, it will not be intercepted, because the intercepted automatic variable will be stored inside the structure of the block, which will lead to the block volume increasing. It is important to note that by default a block can only access and not modify the value of a local variable.
2. An external variable with __block modifier
For references to external variables decorated with __block, the block is accessed by copying the address of the reference. Block modifies the value of an external variable that __block modifies.
3. Storage domains of blocks and copy operations
Consider this: Are blocks stored on the stack or on the heap? There are actually three types of blocks:
- Global block (_NSConcreteGlobalBlock)
- Stack blocks (_NSConcreteStackBlock)
- Heap block (_NSConcreteMallocBlock)
Global blocks exist in global memory and are equivalent to singletons. A stack Block exists in stack memory and is destroyed immediately beyond its scope. A heap Block exists in stack memory and is an object with a reference count that needs to manage its own memory. In short, a Block stored in the stack is a stack Block, a Block stored in the heap is a heap Block, and a Block not in the stack or heap is a global Block.
So if we have a Block, what do we do with the location of the Block?
(1) Block does not access external variables (including stack and heap variables)
Blocks are not on the stack or the heap, and this is true in code segments, ARC and MRC. This is a global block.
(2) Block accesses external variables
MRC: Access the default Block storage stack of external variables. ARC: Blocks that access external variables are stored in the heap by default (actually in the stack, and then copied to the heap in the ARC case) and released automatically.
A class that uses a Block as its property variable then uses the class itself in the body of a Block method, as follows:
1. self.someBlock = ^(Type var){ 2. [self dosomething]; 3.};Copy the code
The solution:
(1) ARC: __weak
1. __weak typeof(self) weakSelf = self; 2. self.someBlock = ^(Type var){ 3. [weakSelf dosomething]; 4.};Copy the code
(2) MRC: use __block
1. __block typeof(self) blockSelf = self; 2. self.someBlock = ^(Type var){ 3. [blockSelf dosomething]; 4.}; 5.Copy the code
It is worth noting that using __block under ARC also makes possible circular references, as follows:
Self -> _attributBlock -> TMP -> self 2. Typedef void (^Block)(); 3. @interface TestObj : NSObject 4. { 5. Block _attributBlock; 6. } 7. @end 8. 9. @implementation TestObj 10 - (id)init { 11. self = [super init]; 12. __block id tmp = self; 13. self.attributBlock = ^{ 14. NSLog(@"Self = %@",tmp); 15. tmp = nil; 16.}; 17. } 18. 19. - (void)execBlock { 20. self.attributBlock(); @end 23.24. // Use class 25.id obj = [[TestObj alloc] init]; 26. [obj execBlock]; // If you don't call this method, TMP will never be set to nil and memory leaks will always be at 27.Copy the code
Why does block use the copy keyword?
Block using copy is a “legacy” of MRC, where the block inside a method is in the stack, and copy can be used to place it in the heap. It doesn’t matter whether you write in ARC or not: using copy or strong for a block is the same, but writing copy doesn’t hurt, and it reminds us that the compiler automatically copies the block. If you do not write a copy, the caller to this class may forget or not know that the compiler automatically copies the block.
What is off-screen rendering? Under what circumstances does it trigger? How to respond?
Off-screen rendering is to create a buffer outside the current screen buffer.
Off-screen rendering starts with the following scenes:
- Rounded corners (maskToBounds trigger)
- Layer mask
- shadow
- rasterizer
Why off-screen rendering?
You might have learned in high school physics how a display displays images: the images to be displayed are scanned line by line with a CRT electron gun at a very high speed. The scan results in a frame, and then the electron gun returns to its original position and repeats the scan, creating the picture or video we see.
To synchronize the display with the video controller, when the gun scans a new line, it sends a horizontal sync signal (HSync signal) when it is ready to scan. The display’s refresh rate is the frequency at which the HSync signal is generated. Then the CPU calculates the attributes such as frame and delivers the calculated content to the GPU for rendering. After rendering, the GPU will put it into the frame buffer. The video controller then reads the data from the frame buffer line by line according to the HSync signal and passes it to the display after possible digital-to-analog conversion. Specific we find information or ask relevant professionals, here only reference online information to do a simple description.
The cost of off-screen rendering is very high. The first choice for off-screen rendering is to create a new buffer. Screen rendering has a concept of context. That’s why it’s a performance drain.
Because of vSYNC, if the CPU or GPU does not complete the submission within an HSync period, the frame is discarded and displayed at the next opportunity, leaving the display unchanged. That’s why the interface is stuck.
Why avoid off-screen rendering?
The CPU GPU does a lot of work when drawing the render view. Off-screen rendering occurs at the GPU level, creating new render buffers, triggering OpenGL’s multi-channel render pipeline, and causing additional overhead and GPU workload to switch graphics contexts. If the CPU GPU takes 16.67 milliseconds to complete, it will cause frame lag.
The rounded corner property and the mask will trigger off – screen rendering. Specifying the above property marks it as an off-screen render when it is not available for display in the new graphical context until it is healed.
-
In OpenGL, the GPU has two rendering modes
- On-screen Rendering: Renders the current Screen, Rendering the Screen buffer currently used for display
- Off-screen Rendering: Creates a buffer outside of the current Screen buffer for Rendering
-
Why off-screen rendering consumes performance
- You need to create a new buffer
- The whole process of off-screen rendering requires several context switches, first from on-screen to off-screen; After the off-screen rendering is finished, the render results of the off-screen buffer are displayed on the screen, and the context needs to be switched from off-screen to the current screen
-
What actions trigger off-screen rendering?
- Rasterize, layer.shouldRasterize = YES
- Mask the layer mask
- Round the corners and set layer.masksToBounds = YES and layer.cornerRadius greater than 0
- Consider using CoreGraphics to crop rounded corners, or using artists to supply rounded corners
- Shadow, layer.shadowXXX, will not produce off-screen rendering if layer.shadowPath is set
Portal:
IOS Interview collection + Answer (1) (juejin.cn)
IOS Interview collection + Answer (2) (juejin.cn)
IOS Interview collection + Answer (3) (juejin.cn)
IOS Interview collection + Answer (5) (juejin.cn)
Common iOS Development Interview Questions (Set)
IOS Interview Guide (QQ.com)