The following article was published on wechat last week:

  • Introduction to iOS graphics processing
  • __bridge, __bridge_transfer, __bridge_retained.
  • The compilation mode of Flutter
  • Which of these popular programming languages do you know?
  • Bulletin · No. 5

The main contents of this knowledge collection include:

  • Let’s talk about arrays, collections, dictionaries, and the association of hash and isEqual methods
  • A pit that needs to be noticed when Keychain is used to store login states
  • Add a shadow to UIView
  • Compare the differences in uploading pictures between the three network frameworks?
  • The Runtime controls the hidden property of the navigation bar
  • Handling of IAP lost orders

Let’s talk about arrays, collections, dictionaries, and the association of hash and isEqual methods

Author: halohily

We know, more or less, that NSArray, NSSet, and NSDictionary in objective-c have a lot to do with the hash and isEqual methods of NSObject and its subclasses, and this little collection goes into some of the details.

NSArray allows you to add duplicate elements without checking them, so you don’t call the above two methods. When an element is removed, the elements in the current array are iterated over, the isEqual method for each element is called (using the element passed in by the remove method as an argument), and all elements that return a true value are removed. In dictionaries, there are no hash methods involved.

NSSet does not allow you to add duplicate elements, so when you add a new element, the hash method for that element is called. If no element in the collection has the same hash value as this element, it is added directly to the collection without calling isEqual. If yes, the isEqual method of the corresponding element in the set is called. If true is returned, the set isEqual. If false is returned, the element does not exist in the collection and is added.

When an element is removed from a collection, its hash method is first called. If there is an element in the set equal to its hash value, the isEqual method of the element will be called. If the element is true, it will be evaluated and removed. If not, the isEqual method is called for each element in the collection in turn, and as soon as one element returns a true value, it is removed, ending the process. (so there are other elements that satisfy the isEqual method but are left out.) The procedure is similar when the CONTAINS method is called.

Therefore, if a custom object is to be added to a collection or used as a dictionary key, you need to override both the isEqual and hash methods. This way, if an element in the collection exists, the contains and remove methods can be called, and the query can be done at O(1). Otherwise, the time complexity of querying it increases to O(n).

It is worth noting that the keys and values of NSDictionary are both object types. However, objects that are set as keys need to comply with the NSCopying protocol.

A pit that needs to be noticed when Keychain is used to store login states

Author: KANGZUBIN

This is a problem that you may never encounter, and in most cases it’s hard to anticipate in development that it might happen in the future, but when it does, it can be a serious online problem, learned the hard way.

Sensitive data, such as passwords and user login status, is stored in a Keychain (Keychain). Second, when users uninstall the App and reinstall it, they can automatically log in and retain the last login state. Third, different apps under the same developer account can share login status through Keychain Groups if they use the same account system.

Previously, our App only stored the user’s login status in the Keychain and read it when the App started. There was no problem with this. Some time ago our App was rejected because of business compliance audit, in accordance with the requirements of the apple have to put the App from the company of A developer account transfer to B account (company, there are many different principal developer account), transfer process is very smooth, but within A short period of time after release received widespread user feedback said, After the new version is updated, the system displays “Login failed. You need to log in again”.

The reason is easy to guess. When the App is transferred from A to B, the Keychain data saved under the ACCOUNT of A cannot be read. After the update version is overwritten and installed, the user cannot access the previous login state when opening the App.

And for this problem that has occurred, we seem to have no effective remedial measures, temporary urgent and then send a version seems to be unable to solve the problem, because the previous Keychain data is not read, always can not transfer the App back, 😂

So how to take precautions to prevent the loss of login state stored in Keychain due to App transfer in the future? (Although the probability of App transfer is very low)

We have adopted a compatible approach in the new version: The login state of the user is encrypted and stored in the local cache (Sandbox) and the Keychain at the same time. When the App is started, it is read from the Keychain preferentially. If it cannot be read from the Keychain, it is read from the local cache (and then the local cache is synchronized to the Keychain. Because even if the App is transferred, the data in the Sandbox will not change after the user’s updated version overwrites the installation), if neither is available, it is considered not logged in.

Do you have a better solution? Welcome to comment.

In addition, many users use Keychain to store unique device identifiers. You need to pay attention to this problem.

For details about how to use Keychain, see The official Apple document GenericKeychain. For details about Keychain abuse, see this post on V2EX.

Add a shadow to UIView

Author: Lefe_x

Adding a shadow to a UIView may seem simple, but it can cost you some time if you don’t do it right. Sometimes shadows are added but don’t show up on the UI, especially when cell reuse is involved. Here are a few reasons why shadows don’t show up:

  • If masksToBounds=YES, shadow will not be displayed.
  • Whether the frame of the view is CGRectZero when the shadow is set. If so, the shadow will not be displayed even if the frame is not CGRectZero after the shadow is set.
  • When using automatic layout, the shadow setting will not work if the frame is CGRectZerolayoutIfNeededMethods;

Set the shadow at Layer

// The shadow color
self.imageView.layer.shadowColor = [UIColor blackColor].CGColor;
self.imageView.layer.shadowOpacity = 0.8;
// Rounded corners of shadows
self.imageView.layer.shadowRadius = 1;
// If the shadow is negative, it is in the opposite direction
self.imageView.layer.shadowOffset = CGSizeMake(3.4);
Copy the code

Set shadows using shadowPath

Shadows set this way can customize the shape of the shadow using properties set at Layer, such as shadowRadius.

UIEdgeInsets edges = UIEdgeInsetsMake(15.10.15.10);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(-edges.left, -edges.top, CGRectGetWidth(self.imageView.frame) + edges.left + edges.right, CGRectGetHeight(self.imageView.frame) + edges.top + edges.bottom)];
self.imageView.layer.shadowPath = path.CGPath;
Copy the code

Compare the differences in uploading pictures between the three network frameworks?

Author: Chen Man iOS

AFNetworking uploads an image to the Request HTTPBodyStream using the image, and then uploads a new task using the Request with the image. HYNetworking uses the AFNetworking API for uploading images, which is one of the APIS in HYNetworking. The XMNetworking upload image request is also encapsulated based on the AFNetworking upload, but it is more subtle than HYNetworking and encapsulates the image array method.

AFNetworking

  1. Compression transformation: UIImage instance objects through UIImageJPEGRepresentation (compression) converted to NSData, called the imageData below.
  2. Information integration: Combine imageData with fileName, file path name, type name mimeType into an object bodyPart of the image model (AFHTTPBodyPart).
  3. Add image model: Add the newly created image model object bodyPart to the object bodyStream (HTTPBodyParts) of the image input stream (AFMultipartBodyStream).
  4. Set the request HTTPBodyStream attribute to bodyStream: encapsulation for requestByFinalizingMultipartFormData
  5. Image model object formData with AFNetwork POST request with upload uploadTaskWithStreamedRequest method.

HYBNetworking

  1. Compression transformation: UIImage instance objects through converting UIImageJPEGRepresentation compression NSData, called the imageData below.
  2. Information integration: With appendPartWithFileData of AFNetwork, add imageData to fileName, file path name, Type name mimeType into images (AFStreamingMultipartFormData) model of an object formData.
  3. Image model object formData with AFNetwork POST request with upload uploadTaskWithStreamedRequest method.

XMNetworking

  1. Compression transformation: UIImage instance objects through converting UIImageJPEGRepresentation compression NSData, called the imageData below.
  2. Information integration: With appendPartWithFileData of AFNetwork, add imageData to fileName, file path name, The type name mimeType is incorporated into the image model (XMUploadFormData) into an object called formData.
  3. Add image model: Add formData to the manager’s image model array uploadFormDatas.
  4. Traversal model array images, image model, using the method of the POST request and uploadTaskWithStreamedRequest AFNetwork to upload.

[Conclusion] It can be seen that the above three frameworks are encapsulated based on AFNetworking, and the essential process is the same. The flow chart for uploading pictures is shown below.

The Runtime controls the hidden property of the navigation bar

The hidden property of navigationBar is set in viewWillAppear and viewDidDisappear, as shown in Figure 1.

Here’s another way to do it, through the Runtime.

Create a VC category and declare the hideNavigationBar attribute of type Bool. The main idea is to rewrite the Initialize method and create a custom method via Runtime to replace the viewWillAppear of the system. In this custom method, set the Hidden property of the navigationBar. The specific code is shown in Figure 2.

A brief description of the runtime methods used in this code:

// Get the method implementation in the class
    class_getMethodImplementation
/ / replace Method
    method_exchangeImplementations
// Get an instance method of the class
    class_getInstanceMethod
// Associated object, equivalent to setValue:forKey
    objc_setAssociatedObject
Copy the code

As for the usage method, hideNavigationBar is NO by default, so it can only be called on the page where the navigation bar needs to be hidden. The code is shown in Figure 3.

Handling of IAP lost orders

Author: Miss Gao is busy

In-app Purchase (IAP) may encounter the problem of order loss, which means that the user has made the payment, but the client cannot process subsequent operations for some reason, for example, it does not receive the successful callback of Apple Pay at all, or the network is interrupted during the verification process with the server, etc. If not handled well, it is easy to destroy the user’s credit for the product.

Apple’s recommendation is the rational use of the transaction, the AppDelegate. M application: didFinishLaunchingWithOptions: Methods add [[SKPaymentQueue defaultQueue] addTransactionObserver: XXX]; If you haven’t called [[SKPaymentQueue defaultQueue] finishTransaction: XXX], so when the next time you start the App in the paymentQueue: updatedTransactions: You need to call the finishTransaction method at an appropriate time, such as when the entire payment process has completed (including successfully verifying the ticket), depending on your business situation. This can greatly reduce the probability of lost orders. Don’t forget to removeTransactionObserver oh!

If processing single time is long, can according to the actual situation in the relevant information to the local (if there is a need of business information, subsequent processing this kind of situation is a must to save local), the switch to the network or switch user or do you think of the actual right to deal with the follow-up process, that can also double insurance, can put the losses to a minimum.

Pay attention to our

Please follow our official account ios-tips and join our group to discuss issues. You can leave messages on public accounts, including ios, flutter, web, PWA and applets.