Можно ли уловить ограничения неопределенности автоопределения в производстве - эквивалент точки останова UIViewAlertForUnsatisfiableConstraints
, но для производственных приложений?
Моей целью было бы добавить глобальный обработчик, который сообщал бы о таких ошибках в систему ведения журнала.
Символ UIViewAlertForUnsatisfiableConstraints
фактически является функцией:
_UIViewAlertForUnsatisfiableConstraints(NSLayoutConstraint* unsatisfiableConstraint, NSArray<NSLayoutConstraint*>* allConstraints)
.
Это личное, поэтому вы не можете его заменить.
Но он вызывается из частного метода -[UIView engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:]
, который можно swizzled. Этот метод имеет примерно такое содержание:
void -[UIView engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:] {
if ([self _isUnsatisfiableConstraintsLoggingSuspended]) {
[self _recordConstraintBrokenWhileUnsatisfiableConstraintsLoggingSuspended:$arg4]; // add constraint to some pool
}
else {
if (__UIConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints) {
// print something in os_log
}
else {
_UIViewAlertForUnsatisfiableConstraints($arg4, $arg5);
}
}
}
Если я правильно понял из в этой статье, __UIConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints
всегда будет возвращать NO на iOS, так что вам нужно всего лишь проверить private bool, называемое _isUnsatisfiableConstraintsLoggingSuspended
, и затем вызовите исходный метод.
Это пример кода результата:
#import <objc/runtime.h>
void SwizzleInstanceMethod(Class classToSwizzle, SEL origSEL, Class myClass, SEL newSEL) {
Method methodToSwizzle = class_getInstanceMethod(classToSwizzle, origSEL);
Method myMethod = class_getInstanceMethod(myClass, newSEL);
class_replaceMethod(classToSwizzle, newSEL, method_getImplementation(methodToSwizzle), method_getTypeEncoding(methodToSwizzle));
class_replaceMethod(classToSwizzle, origSEL, method_getImplementation(myMethod), method_getTypeEncoding(myMethod));
}
@interface InterceptUnsatisfiableConstraints : NSObject
@end
@implementation InterceptUnsatisfiableConstraints
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL willBreakConstantSel = NSSelectorFromString(@"engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:");
SwizzleInstanceMethod([UIView class], willBreakConstantSel, [self class], @selector(pr_engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:));
});
}
- (void)pr_engine:(id)engine willBreakConstraint:(NSLayoutConstraint*)constraint dueToMutuallyExclusiveConstraints:(NSArray<NSLayoutConstraint*>*)layoutConstraints {
BOOL constrainsLoggingSuspended = [[self valueForKey:@"_isUnsatisfiableConstraintsLoggingSuspended"] boolValue];
if (!constrainsLoggingSuspended) {
NSLog(@"_UIViewAlertForUnsatisfiableConstraints would be called on next line, log this event");
}
[self pr_engine:engine willBreakConstraint:constraint dueToMutuallyExclusiveConstraints:layoutConstraints];
}
@end
Он работает на iOS 8.2/9/10 (он не работает в iOS 8.1, поэтому будьте осторожны), но я не могу дать никаких гарантий. Кроме того, он улавливает проблемы ограничения в системных компонентах, таких как клавиатура/видеоплеер/и т.д. Этот код является хрупким (это может привести к сбою при обновлении любой версии системы, изменении параметров и т.д.), И я не буду рекомендовать использовать его в производстве (предположим, что он не пройдет даже автоматический процесс проверки). У вас последнее слово, но вас предупреждают.
Однако я думаю, что вы можете использовать его в сборках для внутренних/внешних тестеров для исправления ошибок в автозапуске перед выпуском.
Заметьте, что вы используете быстрый: вы можете добавить этот код в свой быстрый проект с мостом заголовочного файла.
_UIViewAlertForUnsatisfiableConstraints
?
Короткий ответ: это частный API, и вы не должны возиться с ним в производственном коде...
... по крайней мере, не зная связанных опасностей:
A) Apple отклонит ваше приложение, если вы попытаетесь переопределить SPI, как это, в продукте, представленном в хранилище приложений. И если он проскальзывает по какой-то причине, они поймают его позже, и это, как правило, хуже.
B) Метод swizzling, как говорит @Roman в своем ответе, часто приносит с собой некоторую вероятность того, что вы дестабилизируете все, над чем работаете дальше (или в будущем). Я все еще беспокоюсь, когда я пользуюсь сторонней библиотекой, что кто-то делает что-то хрупкое, как это под капотом.
С этими предупреждениями, продолжайте, переопределите частные методы и оцените их до вашего сердца. Просто не отправляйте этот код.
UIViewAlertForUnsatisfiableConstraints()
и попытался выяснить, является ли это экземпляром или методом класса вUIView
но пока ничего не нашел.