Keyboard, static library, animation and crash location of IOS Development Notes

Time:2020-3-13

Preface

This paper mainly shares the problems encountered in the development and some related thoughts. Let’s share it with friends in need for reference and study. Let’s have a look at the detailed introduction.

IOS 11 keyboard problems

Functional background:

When the keyboard pops up, if there is an input box, the position of the input box needs to change according to the size of the keyboard.

Problem Description:

When the keyboard is switched quickly, the position of the input box is not close to the keyboard, as follows: (take Jianshu keyboard as an example)

Related implementation:

The input box listens for uikeyboardwillshownotification and uikeyboardwillhidenotification events of the system. During the callback process, use uikeyboardframeenduserinfokey to get the frame of the keyboard, and then dynamically adjust the position of the input box.

Problem location:

This problem can be repeated. After calling the keyboard, switch the keyboard frequently.

Add log to debug and get the following results:

/*
226 is the height of the English keyboard of the system;
292 is the height of Sogou input keyboard;
271 is the height of Emoji keyboard;
*/
UIKeyboardWillShowNotification : {{0, 510}, {414, 226}}
UIKeyboardWillShowNotification : {{0, 444}, {414, 292}}
UIKeyboardWillShowNotification : {{0, 510}, {414, 226}}
UIKeyboardWillShowNotification : {{0, 444}, {414, 292}}
UIKeyboardWillShowNotification : {{0, 465}, {414, 271}}
UIKeyboardWillShowNotification : {{0, 510}, {414, 226}}
UIKeyboardWillShowNotification : {{0, 444}, {414, 292}}

In actual operation, when the keyboard is switched from 292 height Sogou keyboard to 271 Emoji keyboard, sometimes the callback cannot be triggered, resulting in the actual keyboard height error of 292-271 (21pt).

Normally Apple should call back every time it switches the keyboard, but when it switches Emoji expression keyboard, it does not trigger the callback occasionally.

Problem fix:

Increase the input box to increase the height of the red box on the left of the figure above;

When aligning with the keyboard, count down the height of the red box.

Attachment:

IOS 11 has another keyboard performance exception: call up the keyboard in app, cut the app into the background, and call up the system search keyboard in the system desktop, which will cause the keyboard in app to fold up.

Static library related

Functional background:

There are some functions in the project, which need to be accessed in the way of static library integration.

Problem Description:

During the online operation, it is found that some crash comes from the static library, but the specific number of lines of code in the static library can not be located in the crash log.
As follows, the thread 0 of testnull crashes, but there is no function related information.


Exception Type: EXC_BAD_ACCESS (SIGSEGV)

Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 testNull       0x000000010494aacc 0x104944000 + 27340
1 testNull       0x000000010494aac8 0x104944000 + 27336
2 testNull       0x000000010494a6b0 0x104944000 + 26288
3 UIKit        0x000000018cec4efc -[UIViewController loadViewIfRequired] + 1040
4 UIKit        0x000000018cec4ad4 -[UIViewController view] + 28
5 UIKit        0x000000018cecb6a0 -[UIWindow addRootViewControllerViewIfPossible] + 136
6 UIKit        0x000000018cec890c -[UIWindow _setHidden:forced:] + 272
7 UIKit        0x000000018cf379ec -[UIWindow makeKeyAndVisible] + 48

Related implementation:

The static library has a separate project. It will package out two frameworks, the simulator and the real machine, then merge them into one framework, and then put them into the project project.

Problem location:

The information in the crash log cannot be symbolized because there is no static library information in the symbol table of the restored crash information.

We know that static libraries are only compiled, no link process.

Only when the binary package is actually hit can the link operation be performed.

There is no static library information in the symbol table. There is no code line number information in the static library framework!

By querying the official documents, we know that the properties of generate debug symbols are described as follows

Enables or disables generation of debug symbols. When debug symbols are enabled, the level of detail can be controlled by the Debug Information Format (DEBUG_INFORMATION_FORMAT) setting.

If no is set for the static library project, the packaged framework does not include the information for debugging.

Problem fix:

Modify the generate debug symbols settings.

Set correctly

Attachment:

For the documentation of Xcode related settings, click the link here. If it fails, you can follow the steps below:

Xcode settings

Animation exception caused by uitableview pull-down refresh

Functional background:

Uitableview is used to display content, and a refreshheadrview will be added to Scrollview to implement pull-down refresh.

Problem Description:

Now, after the pull-down refresh, the view inside the cell will move. Similar effects are as follows (to facilitate the display, click the button instead of the pull-down refresh operation):

Related implementation:

Refreshheadrview (pull-down refresh view) triggers pull-down refresh by listening to the didscroll callback of Scrollview; at the end of the refresh process, it automatically finishes the operation of sliding up by modifying scrollview.contentinset.

The drop-down refresh end code is as follows:


  [UIView beginAnimations:nil context:NULL];
  [UIView setAnimationDuration:0.2];
  [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
  scrollView.contentInset = UIEdgeInsetsMake(-REFRESH_TRIGGER_HEIGHT + _initTopContentInset, 0.0f, 0.0f, 0.0f);
  [UIView commitAnimations];

Problem location:

First look at the performance of the problem: the view on the uitableviewcell is displaced after refreshing.

There are many possible reasons for displacement. Colleague Austin provides a solution: after the pull-down refresh, reload data is put into the next runloop for execution.
After trying, the problem was fixed!

Austin’s solution let me make sure that the problem must be some operations performed by the current runloop, resulting in the view displacement on the uitableviewcell.
After some debugging, the whole original path of the problem is traced back:

  • 1. Pull down refresh = = > 2. Data request = = > 3. Local data source update = = > 4.1 call reload data update view
  • 3. Local data source update = = > 4.2 drop down refresh end didfinish = = > 4.3 refreshheaderview end animation = = > 4.4 trigger didscroll
    Callback = = > 4.5 callback calls visiableCell = = > 4.6 trigger cellFor method = = > 4.7UITableViewCell initialization will change frame

The reason for view displacement is that the ending animation in 4.3 is the animation transaction operation of uiview, and the operation of changing frame in 4.7 is considered to be also in the animation transaction, so the animation effect of view will be triggered.

Problem fix:

The repair scheme can be dispatch to the next runloop to execute reloadData again, so that when visiableCell is called in the 4.5 callback, visiableCell will get the last cell, so the link will be disconnected without causing the view displacement. However, this will hide the bug: the data source and UI display are inconsistent!!

The best solution: instead of calling visiblecell to get the currently displayed cell, instead, listen to the willdisplay and didenddisplayingcell methods of uitableview, and then use a two terminal queue to maintain the currently visible cell on the business side.

Through this problem, we can confirm that the reloadata method is to clear the visible cell of uitableview;
Visiblecell is a getter. When calling, if visiblecell is empty, the method of cellfor will be triggered for initialization.

Crash location

It originates from a crash problem encountered in the actual development. The similar stack is as follows:

Crash problems appear in all IOS versions, and the daily crash rate (crash times / users) is about 1.5 per 10000.

Through the description of crash platform? Memmove and stack information, we can locate that the code exception is the function that appears in memcpy.

Through the error type, we know that it is to access the illegal memory address.

Memcpy has three parameters in total, which will be pushed into three registers of x0, X1 and X2 when the function is executed. Through the register information of crash log, we can get the values of these three parameters, as follows:


Thread 0 crashed with ARM Thread State (64-bit):
 x0: 0x00000000000000aa x1: 0x00000000000000bb x2: 0x00000000000000cc x3: 0x00000000000000c0
 x4: 0x0000000000000010 x5: 0x0000000000000002 x6: 0x0000000000000064 x7: 0x0000000000000000
 x8: 0x00000000000000aa x9: 0x0000ddf9664f0000 x10: 0x0000000000004887 x11: 0x00000001b8741211
 x12: 0x00000001b8741211 x13: 0x000000000000001d x14: 0x0000000000000001 x15: 0x0000000000000881
 x16: 0x00000001855b1ab0 x17: 0x0000000000000000 x18: 0x0000000000000000 x19: 0x00000000000000aa
 x20: 0x0000000119d064f0 x21: 0x0000000000000018 x22: 0x000000018fb4dd6a x23: 0x0000000000000000
 x24: 0x0000000000000010 x25: 0x0000000119e01b40 x26: 0x0000000000000280 x27: 0x0000000119d06c50
 x28: 0x0000000000000001 fp: 0x000000016bce95f0 lr: 0x000000018542ce58
 sp: 0x000000016bce95f0 pc: 0x00000001855b1b60 cpsr: 0x80000000

From the above register information, we can get the register values of x0, x1, X2 as 0XAA, 0xbb, 0xCC, thus restoring the function causing crash as memcpy (0XAA, 0xbb, 0xCC);.

(the three parameters of memcpy are specially constructed by me to describe the problem.)

There are two possibilities for crash:

1. Parameter 1 writes data illegally;

2. Illegal reading of parameter 2;

Let’s first look at a similar problem. What’s wrong with the following code?


int *p1=malloc(1024);
int *p2=malloc(1024);
memcpy(p1, p2, 1025);

The answer is: it works normally in most cases and crashes in a few cases.

The essence of crash is that heap memory access is out of bounds, but the distance between heap memory space and stack memory space is not fixed. If P1 + 1025 still has write permission and P2 + 1025 still has read permission, crash will not occur.

Attachment:
In actual development, the value of register x2 + register X5 is the third parameter of real memcpy.
x2: 0x00000000000003e0 + x5: 0x0000000000000020 = 0x0000000000000400 = 1024
It is suspected that Apple has modified the memcpy method:
When the second parameter is the heap memory address, it will be truncated;
When the second parameter is an illegal address (such as 0x00000000000000bb), no truncation will be performed;

summary

It is normal to encounter problems. If we can learn knowledge from solving problems and use problems to verify knowledge, then problems can also become a part of learning progress.

Well, the above is the whole content of this article. I hope that the content of this article has some reference learning value for your study or work. If you have any questions, you can leave a message and exchange. Thank you for your support for developepaer.