📜 ⬆️ ⬇️

How to remove UIPickerView freezes in iOS simulator

From time to time I notice that hangs happen when I try to select an element in the UIPickerView in the simulator. But to the extent that the brakes are now apparent, it has become unbearable to observe: a change in the selected element in the “drum” can take up to a minute during which the interface does not react to anything.

Perhaps this is a flaw in the beta versions.
On a pure project, especially for the study of this problem, everything is exactly the same.

This problem was tested on 4 launch options:
Xcode 6.4 + 8.1 shows up
Xcode 6.4 + 8.3 shows up
Xcode 7.0 + 8.3 shows up
Xcode 7.0 + 9.0 does not appear
')
It suggests that there is some slight discrepancy between the performance of the versions of the simulator, which in this case is very annoying manifestation option.

Let's try to fix the problem.

We are launching a fairly simple project to which a “drum” has been added:
image

And now we try to slightly pull the list up.
As a result, it freezes in this position, in this case for 28 seconds:
image

Well, let's see what makes him think.
We pause and watch the backtrace:
image

Among the heroes of the occasion can be traced AudioServicesPlaySystemSound .
Apparently, then you should not be surprised, because the Internet has long been replete with a special attitude to playing sounds in the simulator. Up to the point that the macros are advised to turn off the play call in relation to the simulator, because from it you can expect almost a drop.

Let's try to disable it here. It is called from within the system framework, so, of course, it will not be possible to turn it off directly. But you can try to break the chain before it a little higher.

More specifically, its _playClickIfNecessary method calls . Looking at the name, I venture to suggest that this method does not do anything more than play the sound. It remains to replace its own implementation, which simply does nothing.

For the sake of example, let's try to create the necessary while loading the application.
For example, inside AppDelegate.

#if TARGET_IPHONE_SIMULATOR - (void)UIPickerTableView__playClickIfNecessary { // nothing to do } #endif + (void)initialize { # if TARGET_IPHONE_SIMULATOR Class srcClass = self; Class dstClass = NSClassFromString(@"UIPickerTableView"); if (srcClass && dstClass) { SEL srcSelector = NSSelectorFromString(@"UIPickerTableView__playClickIfNecessary"); SEL dstSelector = NSSelectorFromString(@"_playClickIfNecessary"); Method srcMethod = class_getInstanceMethod(srcClass, srcSelector); Method dstMethod = class_getInstanceMethod(dstClass, dstSelector); method_exchangeImplementations(srcMethod, dstMethod); } # endif } 


Tried to make a replacement through the category, but failed:
- through the table - because its implementation overlaps the UIPickerTableView;
- via UIPickerTableView, because it could not properly import the hidden API.

In any case, it is not so important how to replace the implementation.
The main thing is that after replacing now everything works without brakes and freezes, which is infinitely nice.

However, surely someone knows a more concise way to get rid of the problem, then I will be very happy to add to the comments. Because in half an hour I couldn’t find anything sensible on Google.

UPD. The comments suggested a more concise way:

 Method m = class_getInstanceMethod(objc_lookUpClass("UIPickerTableView"), sel_getUid("_playClickIfNecessary")); method_setImplementation(m, imp_implementationWithBlock(^(id _self){})); 

Source: https://habr.com/ru/post/261995/


All Articles