Das Symbol UIViewAlertForUnsatisfiableConstraints
ist eigentlich eine Funktion:
_UIViewAlertForUnsatisfiableConstraints(NSLayoutConstraint* unsatisfiableConstraint, NSArray<NSLayoutConstraint*>* allConstraints)
.
Es ist privat, so dass Sie es nicht ersetzen können.
Aber es wird aus der privaten Methode -[UIView engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:]
aufgerufen, die swizzled werden kann. Diese Methode hat etwa diesen Inhalt:
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);
}
}
}
Wenn ich von this article richtig verstehe, wird __UIConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints
immer NO auf iOS zurückkehren, so alles, was Sie tun müssen, ist private bool Eigenschaft namens _isUnsatisfiableConstraintsLoggingSuspended
und rief ursprüngliche Methode dann zu überprüfen.
Dies ist Ergebnis Codebeispiel:
#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
Es funktioniert auf iOS 8.2/10.09 (es funktioniert nicht in iOS 8.1, so vorsichtig sein), aber ich kann keine Garantie geben. Es fängt auch Constraint-Probleme in Systemkomponenten wie Tastatur/Video Player/etc. Dieser Code ist zerbrechlich (es kann zu einem Absturz bei jedem System-Update führen, Parameter ändern, usw.) und ich werde nicht empfehlen, es in der Produktion zu verwenden (rate, dass es nicht sogar automatisierten Überprüfungsprozess passieren wird). Du hast das letzte Wort, aber du bist gewarnt.
Ich denke jedoch, dass Sie es in Builds für interne/externe Tester verwenden können, um Bugs im automatischen Layout vor der Produktion zu beheben.
Beachten Sie, dass Sie swift verwenden: Sie können diesen Code mit Bridging-Header-Datei zu Ihrem Swift-Projekt hinzufügen.
Das ist eine gute Frage. Wie ich es verstehe, können Sie mit symbolischen Haltepunkten ein bestimmtes Symbol, eine Methode oder einen Selektor unterbrechen.Ich habe versucht, eine globale C-Funktion 'UIViewAlertForUnsatisfibleConstraints()' zu öffnen und zu sehen, ob das eine Instanz oder Klassenmethode auf 'UIView' ist, aber ich habe bisher nichts gefunden. – JAL